App structure¶
tldr
When you run the cfa create command with auth none
or backend
options, a following file tree will be created:
๐ฆfastapi-app
โฃ ๐app
โ โฃ ๐api
โ โ โฃ ๐v1
โ โ โ โฃ ๐endpoints
โ โ โ โ โฃ ๐__init__.py
โ โ โ โ โ ๐item.py
โ โ โ โ ๐__init__.py
โ โ โฃ ๐__init__.py
โ โ โ ๐deps.py
โ โฃ ๐core
โ โ โฃ ๐__init__.py
โ โ โ ๐config.py
โ โฃ ๐crud
โ โ โฃ ๐__init__.py
โ โ โฃ ๐base.py
โ โ โฃ ๐crud_example.py
โ โ โ ๐crud_item.py
โ โฃ ๐database
โ โ โฃ ๐__init__.py
โ โ โฃ ๐base.py
โ โ โฃ ๐initialize.py
โ โ โ ๐session.py
โ โฃ ๐models
โ โ โฃ ๐__init__.py
โ โ โฃ ๐example.py
โ โ โ ๐item.py
โ โฃ ๐schemas
โ โ โฃ ๐__init__.py
โ โ โฃ ๐example.py
โ โ โ ๐item.py
โ โฃ ๐tests
โ โ โฃ ๐api
โ โ โ โฃ ๐v1
โ โ โ โ โฃ ๐__init__.py
โ โ โ โ โ ๐test_item.py
โ โ โ โ ๐__init__.py
โ โ โฃ ๐__init__.py
โ โ โ ๐conftest.py
โ โ ๐__init__.py
โฃ ๐git_hooks
โ โฃ ๐pre-commit.sh
โ โ ๐pre-push.sh
โฃ ๐.gitignore
โฃ ๐Dockerfile
โฃ ๐Pipfile
โฃ ๐Pipfile.lock
โฃ ๐README.md
โฃ ๐create_git_hooks.sh
โฃ ๐db.db
โฃ ๐docker-compose.yml
โฃ ๐env_example
โฃ ๐init_db.sh
โ ๐main.py
auth = self
adds and updates several files:
๐ฆfastapi-app
โฃ ๐app
โ โฃ ๐api
โ โ โฃ ๐v1
โ โ โ โฃ ๐endpoints
โ โ โ โ โฃ ๐__init__.py
โ โ โ โ โฃ ๐auth.py
โ โ โ โ โฃ ๐item.py
โ โ โ โ โ ๐user.py
โ โ โ โ ๐__init__.py
โ โ โฃ ๐__init__.py
โ โ โ ๐deps.py
โ โฃ ๐core
โ โ โฃ ๐__init__.py
โ โ โ ๐config.py
โ โฃ ๐crud
โ โ โฃ ๐__init__.py
โ โ โฃ ๐base.py
โ โ โฃ ๐crud_item.py
โ โ โ ๐crud_user.py
โ โฃ ๐database
โ โ โฃ ๐__init__.py
โ โ โฃ ๐base.py
โ โ โฃ ๐initialize.py
โ โ โ ๐session.py
โ โฃ ๐models
โ โ โฃ ๐__init__.py
โ โ โฃ ๐item.py
โ โ โ ๐user.py
โ โฃ ๐schemas
โ โ โฃ ๐__init__.py
โ โ โฃ ๐auth.py
โ โ โฃ ๐item.py
โ โ โ ๐user.py
โ โฃ ๐tests
โ โ โฃ ๐api
โ โ โ โฃ ๐v1
โ โ โ โ โฃ ๐__init__.py
โ โ โ โ โฃ ๐test_item.py
โ โ โ โ โ ๐test_user.py
โ โ โ โ ๐__init__.py
โ โ โฃ ๐__init__.py
โ โ โ ๐conftest.py
โ โฃ ๐__init__.py
โ โ ๐utils.py
โฃ ๐.gitignore
โฃ ๐Dockerfile
โฃ ๐Pipfile
โฃ ๐Pipfile.lock
โฃ ๐README.md
โฃ ๐create_git_hooks.sh
โฃ ๐docker-compose.yml
โฃ ๐env_example
โฃ ๐init_db.sh
โ ๐main.py
./¶
Place for some general files, environment files and other configurations
./app/api/¶
Folder where endpoints should be specified. E.g. to create a new endpoint for table. All endpoints related to a single table should be grouped in the same file, and the router should be then included in the ./app/api/v1/__init__.py
file.
./app/core/¶
A place for app configurations
./app/crud/¶
Crud classes utilizing models and schemas for a table in the database. Each crud class should inherit from the CRUDBase class which contains some basic methods for:
- creating (
create(db, obj_in)
) - reading (
read(db, item_id)
,read_multi(db, offset, limit)
) - updating (
update(db, item_id, obj_in)
) - deleting (
delete(db, item_id)
)
objects in the database
./app/database/¶
Database base class base.py
, which is inherited by the models, and session (session.py
). The initialize.py
contains db initialization scripts useful for development. However, in production the tables and migrations should be handled ideally by alembic
./app/models/¶
Database tables models. Simple classes that inherit from the base class specifying the columns, datatypes, indexes, foreign keys etc. For more info see SQLAlchemy docs
./app/schemas/¶
pydantic schemas declaring data validation. Schemas are used for database manipulations (create, read, update) as well as for validating requests and specifying response schemas. E.g. imagine we would like to add a post endpoint for creating new items in the database (in the ./app/api/v1/endpoints/item.py
file). It would look something like this:
@router.post('/', response_model=schemas.Item)
def get_items(
obj_in: schemas.ItemCreate,
db: Session = Depends(deps.get_db)
) -> Any:
return crud_item.create(db=db, obj_in=obj_in)
In the first line, we specify the schema of the json object that will be returned to the user. In the third line, we specify what we expect. If the incoming object does not correspond with the schema, the endpoint will throw an Error.
./app/tests/¶
Tests. See pytest for more info. In short, you simply write functions (with the word test in their names - this is very important) in a file with the word test in its name and then include some assertions inside of the functions. Running the command pytest will detect all these functions and run them.
For example to test if GET item
endpoint works, simply create a file ./app/tests/api/v1/test_item.py
with following content:
from fastapi.testclient import TestClient
from app.core.config import settings
def test_item_get_multi(client: TestClient) -> None:
"""Test the get items endpoint"""
r = client.get(f"{settings.API_VERSION}/item/")
assert r.status_code == 200
all_runs = r.json()
assert len(all_runs) > 0
There are some configurations already in place. See the app/tests/conftest.py
for more info. You should be fine with the default settings. For more info see the official documentation