-
-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Convert/Port Flask code to FastAPI #789
Comments
Flask
|
Thanks @paulespinosa this is super helpful. |
In the FastAPI migration, code has been organized according to "workflow capability" rather than "technical function." It represents the current model used to represent a Host Home Program workflow. As we learn more, the organization of code and the choices described below will change. Code OrganizationThe directories of the front-end code and the back-end code have changed as follows:
The new FastAPI Back-endUnder API code is now located in the
The
PoetryThe back-end API now uses the Python package and dependency management tool The project dependencies are specified in The DataAccessLayer and SQLAlchemy ModelsIn the Flask-based API, The # FastAPI-based API SQLAlchemy Session dependency injection
@router.get("/{housing_org_id}")
def get_housing_org(housing_org_id: int, db_session: DbSessionDep) -> schemas.HousingOrg | None: In the FastAPI-based API - The SQLAlchemy models are moved to their related packages under SQLAlchemy models are defined by importing from app.core.db import Base
class User(Base):
__tablename__ = "user"
# ... Migrating Models to SQLAlchemy 2.0In the FastAPI-based API, SQLAlchemy models have been updated to using the 2.0 style declarative mappings following the steps documented in the Migrating an Existing Mapping section of the SQLAlchemy 2.0 Migration Guide. For example, the new intpk = Annotated[int, mapped_column(primary_key=True)]
class HousingOrg(Base):
__tablename__ = "housing_orgs"
housing_org_id: Mapped[intpk]
org_name: Mapped[str] = mapped_column(String, nullable=False, unique=True)
programs: Mapped[List["HousingProgram"]] = relationship(
back_populates="housing_org") Data SchemasData schemas represent the shape of the data that come into and go out of the API via the HTTP endpoints (a.k.a path operation functions). In the Flask-based API, In the FastAPI-based API, the data schemas have been moved to their related packages under In the FastAPI-based API, # FastAPI-based API data schema
class RoleBase(BaseModel):
id: int
type: UserRoleEnum
model_config = ConfigDict(from_attributes=True) CRUD and RepositoriesIn the Flask-based API, database access was performed directly via the SQLAlchemy In the FastAPI-based API, database access is performed either in a For simple CRUD-like operations on a SQLAlchemy model, use a CRUD file to define the operations. For more advanced use of domain models, use of the Repository pattern is a consideration. In either case, transactions and commits are maintained by the caller. For example, the Housing Orgs controller below maintains the database transaction. The transaction automatically commits the changes. @router.post("/",
status_code=status.HTTP_201_CREATED,
response_model=schemas.HousingOrg)
def create_housing_org(
housing_org: schemas.HousingOrg,
request: Request,
session: DbSessionDep) -> Any:
with session.begin():
db_org = crud.read_housing_org_by_name(session, housing_org.org_name)
if db_org:
redirect_url = request.url_for('get_housing_org',
**{'housing_org_id': db_org.housing_org_id})
return RedirectResponse(url=redirect_url,
status_code=status.HTTP_303_SEE_OTHER)
new_housing_org = models.HousingOrg(org_name=housing_org.org_name)
crud.create_housing_org(session, new_housing_org)
session.refresh(new_housing_org) ControllersIn the Flask-based API, all of the controllers were located in In the FastAPI-base API, the controllers have been moved to their related packages under 'modules/'. For example, the Flask-based API Endpoints (a.k.a. path operation functions) are defined in the "controller" files using the FastAPI decorators. For example: router = APIRouter()
@router.get("<endpoint path>")
@router.post("<endpoint path>")
@router.put("<endpoint path>")
@router.delete("<endpoint path>") Dependency InjectionThe FastAPI-based API uses FastAPI's dependency injection system. The dependencies are defined in # FastAPI-based API SQLAlchemy Session dependency injection
# DbSessionDep is defined in modules/deps.py
@router.get("/{housing_org_id}")
def get_housing_org(housing_org_id: int, db_session: DbSessionDep) -> schemas.HousingOrg | None: RoutingThe top-level router to the API SettingsIn the Flask-based API, the API configuration settings were defined in In the FastAPI-based API, the API configuration settings are located in The DatabaseIn the FastAPI-based API, the SQLAlchemy database engine and session code is defined in TestingIn the FastAPI-based API, tests have the sub-directories:
@pytest.fixture
def client(session_factory) -> TestClient:
def override_db_session():
try:
session = session_factory()
yield session
finally:
session.close()
main_api.dependency_overrides[db_session] = override_db_session
main_api.dependency_overrides[get_cognito_client] = lambda: None
return TestClient(main_api) An example use of the def test_signin_with_fake_credentials(client):
response = client.post(PATH + '/signin',
json={
'email': '[email protected]',
'password': '_pp#FXo;h$i~'
})
body = response.json()
assert response.status_code == 400, body
assert body["detail"]["code"] == "UserNotFoundException", body To mock AWS Cognito, Alembic
During the migration, the existing migration scripts have been deleted. This was done since all existing/older environments will be created from zero again. This includes the incubator environment. If you have an existing Postgres container volume or SQLite database, then they will need to be deleted. The PostgreSQL container volume can be deleted using the command: docker volume rm homeuniteus_db-data DockerIn the migrated codebase,
The docker compose up -d --build pgadmin motoserver The convenience container, The design of the Docker environment is pictured below. GitHub Actions |
Thanks Paul. This is very helpful! |
Thanks @paulespinosa this is awesome info! |
Overview
The goal of this task is to migrate the existing Flask codebase to FastAPI to improve performance, flexibility, and development speed. FastAPI offers features such as asynchronous request handling, Pydantic for data validation, and better dependency injection, which will enhance our current implementation. This migration will also ensure that our project uses more modern and efficient frameworks.
Action Items
message
,code
,status
. Discussed in issue API Error Design in Production vs Development Environments #828Resources/Instructions
The text was updated successfully, but these errors were encountered: