FastAPI Summary

  1. Short

    1. Open a bash terminal in the project folder

    2. Activate the Virtual Environment

      . venv/Scripts/activate  
      
    3. Run a server

      uvicorn main:app --reload
      
    4. Check using documentation by running in the browser

      http://127.0.0.1:8000/docs
    5. Run in the browser

      http://127.0.0.1:8000


  2. New Project Creation

    1. Open a VS Code bash terminal in the project folder


    2. Create requirements.txt file

        Examples
      •   fastapi
          uvicorn
        

      •   # FastAPI
          fastapi
        
          # Local server
          uvicorn
        
          # Validation of values
          pydantic
        
          # For uploading files
          python-multipart
        
          # For static files (used for uploaded files)
          aiofiles 
          
          # For database
          sqlalchemy
        
          # For hashing password
          passlib
          bcrypt
        
          #for loading environment variables
          python-dotenv
        
          # Used for authentication
          python-jose  
        

    3. Create .gitignore file

      venv/
      __pycache__/      
      

    4. Create main.py file

    5.   from fastapi import FastAPI
      
        app = FastAPI()
      
        @app.get("/")
        def index():
          return {'message': "Hello World!!!"}
      

    6. Install Virtual Environment

      python -m venv venv  
      

    7. Install all at once

        pip install -r requirements.txt
      

    8. Activate the Virtual Environment

      . venv/Scripts/activate  
      

      Expected result in the terminal:
        (venv)  
      

          Note: if there are some problems, make sure Git and GitBash are installed in the computer.


    9. Run a server

      uvicorn main:app --reload
      

    10. Check using documentation

      http://127.0.0.1:8000/docs

    11. Run in the browser

      http://127.0.0.1:8000


  3. Installation

    1. Install Python

      https://www.python.org/downloads/


    2. Install in the virtual environment

      1. Create a folder fastapi-practice


      2. Create .gitignore file with the following content
        venv/
        __pycache__/               
                      

      3. Open a terminal on fastapi-practice folder


      4. Create Virtual Environment

        Perform in the bash terminal:

        python -m venv venv

        OR

        python3 -m venv venv

      5. Activate Virtual Environment

        Perform in the bash terminal:

        . venv/Scripts/activate

        Expected result on the terminal: (venv) <-- a folder name


      6. Check Virtual Environment was Activated

          which python
        
        In case everything OK, it shows a folder of the virtual environment and not the general computer folder of Python installation
        If it shows general computer folder of Python installation, means there is a problem.

      7. Install fastAPI

        pip install fastapi



      8. Install and run a server
        1. Install a server

          to make endpoints available on a local machine

          pip install uvicorn

          uvicorn --version

        2. Create an main.py - on the same level as venv folder

                from fastapi import FastAPI
          
                app = FastAPI()
          
                @app.get("/")
                def index():
                  return {'message': "Hello World!!!"}
          


        3. Run a server
          uvicorn main:app --reload

        4. See in a browser

          http://127.0.0.1:8000


  4. Install using requirements.txt file


  5. FastAPI's Features


  6. FastAPI's Automatic Documentation

    Use JSON Formatter extension for Chrome to see error messages in a nice way


  7. REST APIs methods


  8. Status Code

    from fastapi import FastAPI, Response, status
    
    @app.get("/blog/{id}", status_code=status.HTTP_200_OK)
    def get_blog(id: int, response: Response):
      if id > 5:
        response.status_code = status.HTTP_404_NOT_FOUND
        return {'error': f'Blog {id} not found'}
      else:
        response.status_code = status.HTTP_200_OK
        return {'message': f"Blog with id {id}"}
    

  9. Tags

    Tags structure a documentation in a very nice way


  10. Summary and Description

    Used for documentation


  11. Response description

    Info about the output

        @app.get(
          "/blog/all",
          tags=['blog'],
          summary="Retrieve all blogs",
          description="This API call simulates fetching all blogs",
          response_description="The list of available blogs"        <---
          )
        def get_blogs(page=1, page_size: Optional[int] = None):
          return {'message': f"All {page_size} blogs on page {page}"}
    

  12. Routes



  13. Dependency injection


  14. FastAPI and SQL database - sqlite

    Based on Complete FastAPI masterclass from scratch 2023 on Udemy by Catalin Stefan



    1. Files


      • db\database.py
        from sqlalchemy import create_engine
        from sqlalchemy.ext.declarative import declarative_base
        from sqlalchemy.orm import sessionmaker
        
        SQLALCHEMY_DATABASE_URL = "sqlite:///./fastapi-practice.db"   <-- name of db file
        
        engine = create_engine(
            SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
        )
        SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
        
        Base = declarative_base()
        
        def get_db():
          db = SessionLocal()
          # try to provide the db, close it at the end 
          try:
            yield db
          finally:
            db.close()  
          


      • db\models\db_user_model.py
        from sqlalchemy.sql.sqltypes import Integer, String, Boolean
        from db.database import Base
        from sqlalchemy import Column
        
        
        class DbUser(Base):
          __tablename__ = 'users'
          id = Column(Integer, primary_key=True, index=True) # id = Column(Integer, primary_key=True, index=True) # will be automatically incremented when we add a new line in the table
          username = Column(String)
          email = Column(String)
          password = Column(String)
          


      • main.py
        from fastapi import FastAPI
        from routers.user import user
        from routers.blog import blog_get
        from routers.blog import blog_post
        from db.models.user import db_user_modal
        from db.database import engine
        
        app = FastAPI()
        app.include_router(user.router)
        app.include_router(blog_get.router)
        app.include_router(blog_post.router)
        
        @app.get("/")
        def index():
          return {'message': "Hello World!!!"}
        
        db_user_modal.Base.metadata.create_all(engine)  


      • schemas\user\user_schema.py
        from pydantic import BaseModel
        from typing import List, Dict, Optional
        
        class UserBase(BaseModel):
          username: str
          email: str
          password: str  
        
        class UserDisplay(BaseModel):  # what will be returned by API
          username: str
          email: str
          class Config():
            # allows the system automatically to return database data type (DbUser) into format we provided in UserDisplay class
            orm_mode = True   # object relational mapping - map what we have in the database to this class
        


      • db\db_user.py
        from sqlalchemy.orm.session import Session
        from schemas.user.user_schema import UserBase
        from db.models.user.db_user_modal import DbUser
        from db.hash import Hash
        
        • # Creation of a user in the database

          def create_user(db: Session, request: UserBase):
            new_user = DbUser(
              username = request.username,
              email = request.email,
              password = Hash.bcrypt(request.password)
            )
            db.add(new_user)
            db.commit()             # actually send the operation to the database
            db.refresh(new_user)    # will get user info with the id created in the database
            
            return new_user  
          

        • # Read all users from the database

          def get_all_users(db: Session):
            return db.query(DbUser).all()
          

        • # Read one user from the database

          from fastapi import HTTPException, status
          ...  
          def get_user(db: Session, id: int):
            # Example of several filters:
            # db.query(DbUser).filter(DbUser.id == id).filter(DbUser.email == email).first()
            user = db.query(DbUser).filter(DbUser.id == id).first()
            if not user:
              raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
                                  detail=f'User with id {id} not found')
            return user
          

        • # Update user

          def update_user(db: Session, id: int, request: UserBase):
            user = db.query(DbUser).filter(DbUser.id == id)
            user.update({
                DbUser.username: request.username,
                DbUser.email: request.email,
                DbUser.password: Hash.bcrypt(request.password)
            })
            db.commit()
            return 'OK'
          

        • # Delete user

          from fastapi import HTTPException, status  
          
          ...
          def delete_user(db: Session, id: int):
            user = db.query(DbUser).filter(DbUser.id == id).first()
            if not user:
              raise HTTPException(
                status_code = status.HTTP_404_NOT_FOUND,
                detail = f'User with id {id} not found'
                )  
            db.delete(user)
            db.commit()
            return {'message': 'OK'}
          


      • routers\user\user.py
        from fastapi import APIRouter, Response, status, Depends
        from sqlalchemy.orm import Session
        from typing import List
        from schemas.user.user_schema import UserBase
        from schemas.user.user_schema import UserDisplay
        from db.database import get_db
        from db import db_user
        
        router = APIRouter(
            prefix='/user',
            tags=['user']
        )
        
        • # Create a user

          @router.post('/', response_model=UserDisplay)
          def create_user(request: UserBase, db: Session = Depends(get_db)):
            return db_user.create_user(db, request)
          
          

        • # Read all users

          @router.get('/', response_model=List[UserDisplay])
          def get_all_users(db: Session = Depends(get_db)):
            return db_user.get_all_users(db)
          

        • # Read one user

          @router.get('/{id}', response_model=UserDisplay)
          def get_user(id: int, db: Session = Depends(get_db)):
            return db_user.get_user(db, id)  
          

        • # Update user

          @router.post('/{id}')
          def update_user(id: int, request: UserBase, db: Session = Depends(get_db)):
            return db_user.update_user(db, id, request)
          

        • # Delete user

          @router.delete('/{id}')
          def delete_user(id: int, db: Session = Depends(get_db)):
            return db_user.delete_user(db, id)
          

    2. Start server

        . venv/Scripts/activate  
        uvicorn main:app --reload
      

      As a result a new file named fastapi-practice.db will be created in the project's root folder. The name is specified in db\database.py file.



    3. Run TablePlus

      • Press on Create a new connection
      • Choose SQLite
      • Press on Select SQLite database file *.db. Specify the *.db created in the project
      • Give a name to SQLite Connection
      • Press on Connect button
      • Press on the table and see the structure of the table



    4. Test using docs

      http://127.0.0.1:8000/docs


  15. Error Handling


  16. Custom Response



  17. Custom Headers


  18. Cookies

    Optional - install Chrome Extension "EditThisCookie"

  19. Form Data


  20. CORS


  21. Authentication

  22. Working with Files


  23. Get versions of Packages

  24. Solving problems