11# FastAPI-boilerplate
22> A template to speed your FastAPI development up.
33
4- ## About
4+ ## 0. About
55** FastAPI boilerplate** creates an extendable async API using FastAPI, Pydantic V2, SQLAlchemy 2.0 and PostgreSQL:
66- [ ` FastAPI ` ] ( https://fastapi.tiangolo.com ) : modern Python web framework for building APIs
7- - [ ` Pydantic V2 ` ] ( https://docs.pydantic.dev/2.4/ ) : the most widely used data validation library for Python now rewritten in Rust [ ` (5x to 50x speed improvement) ` ] ( https://docs.pydantic.dev/latest/blog/pydantic-v2-alpha/ )
7+ - [ ` Pydantic V2 ` ] ( https://docs.pydantic.dev/2.4/ ) : the most widely used data validation library for Python, now rewritten in Rust [ ` (5x to 50x speed improvement) ` ] ( https://docs.pydantic.dev/latest/blog/pydantic-v2-alpha/ )
88- [ ` SQLAlchemy 2.0 ` ] ( https://docs.sqlalchemy.org/en/20/changelog/whatsnew_20.html ) : Python SQL toolkit and Object Relational Mapper
99- [ ` PostgreSQL ` ] ( https://www.postgresql.org ) : The World's Most Advanced Open Source Relational Database
1010
11- ## Features
11+ ## 1. Features
1212 - Fully async
1313 - Pydantic V2 and SQLAlchemy 2.0
1414 - User authentication with JWT
1515 - Easily extendable
1616 - Flexible
1717
18+ ### 1.1 To do
19+ - [ ] Redis cache
20+ - [ ] Arq job queues
21+
22+ ## 2. Contents
23+ 0 . [ About] ( #0-about )
24+ 1 . [ Features] ( #1-features )
25+ 1 . [ To do] ( #11-to-do )
26+ 2 . [ Contents] ( #2-contents )
27+ 3 . [ Usage] ( #3-usage )
28+ 4 . [ Requirements] ( #4-requirements )
29+ 1 . [ Packages] ( #41-packages )
30+ 2 . [ Environment Variables] ( #42-environment-variables )
31+ 5 . [ Running PostgreSQL with docker] ( #5-running-postgresql-with-docker )
32+ 6 . [ Running the api] ( #6-running-the-api )
33+ 7 . [ Creating the first superuser] ( #7-creating-the-first-superuser )
34+ 8 . [ Database Migrations] ( #8-database-migrations )
35+ 9 . [ Extending] ( #9-extending )
36+ 1 . [ Database Model] ( #91-database-model )
37+ 2 . [ SQLAlchemy Models] ( #92-sqlalchemy-model )
38+ 3 . [ Pydantic Schemas] ( #93-pydantic-schemas )
39+ 4 . [ Alembic Migrations] ( #94-alembic-migration )
40+ 5 . [ CRUD] ( #95-crud )
41+ 6 . [ Routes] ( #96-routes )
42+ 7 . [ Running] ( #97-running )
43+ 10 . [ Testing] ( #10-testing )
44+ 11 . [ Contributing] ( #11-contributing )
45+ 12 . [ References] ( #12-references )
46+ 13 . [ License] ( #13-license )
47+ 14 . [ Contact] ( #14-contact )
48+
1849___
19- # Usage
20- ## Start by cloning the repository
50+ ## 3. Usage
51+ Start by cloning the repository
2152``` sh
2253git clone https://github.com/igormagalhaesr/FastAPI-boilerplate
2354```
2455___
25- ## Requirements
26- ### Packages
56+ ## 4. Requirements
57+ ### 4.1 Packages
2758Then install poetry:
2859``` sh
2960pip install poetry
@@ -34,7 +65,7 @@ In the **src** directory, run to install required packages:
3465poetry install
3566```
3667
37- ### Environment Variables
68+ ### 4.2 Environment Variables
3869Then create a .env file:
3970``` sh
4071touch .env
@@ -85,7 +116,7 @@ ADMIN_PASSWORD="your_password"
85116```
86117
87118___
88- ## Running PostgreSQL with docker:
119+ ## 5. Running PostgreSQL with docker:
89120Install docker if you don't have it yet, then run:
90121``` sh
91122docker pull postgres
@@ -114,24 +145,24 @@ docker run -d \
114145[ ` If you didn't create the .env variables yet, click here. ` ] ( #environment-variables )
115146
116147___
117- ## Running the api
148+ ## 6. Running the api
118149While in the ** src** folder, run to start the application with uvicorn server:
119150``` sh
120151poetry run uvicorn app.main:app --reload
121152```
122153
123154___
124- ## Creating the first superuser:
155+ ## 7. Creating the first superuser:
125156While in the ** src** folder, run (after you started the application at least once to create the tables):
126157``` sh
127158poetry run python -m scripts.create_first_superuser
128159```
129160
130161___
131- ## Database Migrations
162+ ## 8. Database Migrations
132163Migrations done via [ Alembic] ( https://alembic.sqlalchemy.org/en/latest/ ) :
133164
134- Whenever you change somethin in the database, in the ** src** directory, run to create the script:
165+ Whenever you change something in the database, in the ** src** directory, run to create the script:
135166``` sh
136167poetry run alembic revision --autogenerate
137168```
@@ -142,7 +173,130 @@ poetry run alembic upgrade head
142173```
143174
144175___
145- ## Testing
176+ ## 9. Extending
177+ ### 9.1 Database Model
178+ Create the new entities and relationships and add them to the model
179+ ![ diagram] ( https://private-user-images.githubusercontent.com/43156212/273493228-e90bdf25-57e3-4811-b59e-ec3c2eb8eae2.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTEiLCJleHAiOjE2OTY4MjI2NDYsIm5iZiI6MTY5NjgyMjM0NiwicGF0aCI6Ii80MzE1NjIxMi8yNzM0OTMyMjgtZTkwYmRmMjUtNTdlMy00ODExLWI1OWUtZWMzYzJlYjhlYWUyLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFJV05KWUFYNENTVkVINTNBJTJGMjAyMzEwMDklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjMxMDA5VDAzMzIyNlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTcyOWJmMGY0MDY1OTc0YTlhODlkNjhiM2FmNTM0NGJlMTNiNTM5ZTlhYzgxMGRjNzZmNDc4OTVjMmU1NTZjMzQmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.7KR0K-ts3gRqP8n1eXklx-HxKqXsp3Iobpzvj1ZWxII )
180+
181+ ### 9.2 SQLAlchemy Model
182+ Inside ** app/models** , create a new ** entity.py** for each new entity (replacing entity with the name) and define the attributes according to [ SQLAlchemy 2.0 standards] ( https://docs.sqlalchemy.org/en/20/orm/mapping_styles.html#orm-mapping-styles ) :
183+ ``` python
184+ from sqlalchemy import String, DateTime
185+ from sqlalchemy.orm import Mapped, mapped_column, relationship
186+
187+ from app.core.database import Base
188+
189+ class Entity (Base ):
190+ __tablename__ = " entity"
191+
192+ id : Mapped[int ] = mapped_column(
193+ " id" , autoincrement = True , nullable = False , unique = True , primary_key = True , init = False
194+ )
195+ name: Mapped[str ] = mapped_column(String(30 ))
196+ ...
197+ ```
198+
199+ ### 9.3 Pydantic Schemas
200+ Inside app/schemas, create a new entity.py for for each new entity (replacing entity with the name) and create the schemas according to [ Pydantic V2] ( https://docs.pydantic.dev/latest/#pydantic-examples ) standards:
201+ ``` python
202+ from typing import Annotated
203+
204+ from pydantic import BaseModel, EmailStr, Field, HttpUrl, ConfigDict
205+
206+ class EntityBase (BaseModel ):
207+ name: Annotated[
208+ str ,
209+ Field(min_length = 2 , max_length = 30 , examples = [" Entity Name" ])
210+ ...
211+ ]
212+
213+ class Entity (EntityBase ):
214+ ...
215+
216+ class EntityRead (EntityBase ):
217+ ...
218+
219+ class EntityCreate (EntityBase ):
220+ ...
221+
222+ class EntityCreateInternal (EntityCreate ):
223+ ...
224+
225+ class EntityUpdate (BaseModel ):
226+ ...
227+
228+ class EntityUpdateInternal (BaseModel ):
229+ ...
230+
231+ class EntityDelete (BaseModel ):
232+ model_config = ConfigDict(extra = ' forbid' )
233+
234+ is_deleted: bool
235+ deleted_at: datetime
236+
237+ ```
238+
239+ ### 9.4 Alembic Migration
240+ Then, while in the ** src** folder, run Alembic migrations:
241+ ``` sh
242+ poetry run alembic revision --autogenerate
243+ ```
244+
245+ And to apply the migration
246+ ``` sh
247+ poetry run alembic upgrade head
248+ ```
249+
250+ ### 9.5 CRUD
251+ Inside ** app/crud** , create a new crud_entities.py inheriting from CRUDBase for each new entity:
252+ ``` python
253+ from app.crud.crud_base import CRUDBase
254+ from app.models.entity import Entity
255+ from app.schemas.entity import EntityCreateInternal, EntityUpdate, EntityUpdateInternal, EntityDelete
256+
257+ CRUDEntity = CRUDBase[Entity, EntityCreateInternal, EntityUpdate, EntityUpdateInternal, EntityDelete]
258+ crud_entity = CRUDEntity(Entity)
259+ ```
260+
261+ ### 9.6 Routes
262+ Inside ** app/api/v1** , create a new entities.py file and create the desired routes
263+ ``` python
264+ from typing import Annotated
265+
266+ from fastapi import Depends
267+
268+ from app.schemas.entity import EntityRead
269+ from app.core.database import async_get_db
270+ ...
271+
272+ router = fastapi.APIRouter(tags = [" entities" ])
273+
274+ @router.get (" /entities" , response_model = List[EntityRead])
275+ async def read_entities (db : Annotated[AsyncSession, Depends(async_get_db)]):
276+ entities = await crud_entities.get_multi(db = db)
277+ return entities
278+
279+ ...
280+ ```
281+ Then in ** app/api/v1/__ init__ .py** add the router such as:
282+ ``` python
283+ from fastapi import APIRouter
284+ from app.api.v1.entity import router as entity_router
285+ ...
286+
287+ router = APIRouter(prefix = " /v1" ) # this should be there already
288+ ...
289+ router.include_router(entity_router)
290+ ```
291+
292+ ### 9.7 Running
293+ While in the ** src** folder, run to start the application with uvicorn server:
294+ ``` sh
295+ poetry run uvicorn app.main:app --reload
296+ ```
297+
298+ ___
299+ ## 10. Testing
146300For tests, create in .env:
147301```
148302# ------------- test -------------
@@ -152,7 +306,7 @@ TEST_USERNAME="testeruser"
152306TEST_PASSWORD="Str1ng$t"
153307```
154308
155- While in the tests folder, create your test file with the name "test_ {object }.py", replacing object with what you're testing
309+ While in the tests folder, create your test file with the name "test_ {entity }.py", replacing entity with what you're testing
156310``` sh
157311touch test_items.py
158312```
@@ -162,24 +316,24 @@ Finally create your tests (you may want to copy the structure in test_user.py),
162316poetry run python -m pytest
163317```
164318___
165- # Other stuff
166- ## Contributing
319+ ## 11. Contributing
320+ Contributions are appreciated, even if just reporting bugs, documenting stuff or answering questions. To contribute with a feature:
1673211 . Fork it (https://github.com/igormagalhaesr/FastAPI-boilerplate )
1683222 . Create your feature branch (` git checkout -b feature/fooBar ` )
1693233 . Test your changes while in the src folder ` poetry run python -m pytest `
1703244 . Commit your changes (` git commit -am 'Add some fooBar' ` )
1713255 . Push to the branch (` git push origin feature/fooBar ` )
1723266 . Create a new Pull Request
173327
174- ## References
328+ ## 12. References
175329This project was inspired by a few projects, it's based on them with things changed to the way I like (and pydantic, sqlalchemy updated)
176330* [ ` Full Stack FastAPI and PostgreSQL ` ] ( https://github.com/tiangolo/full-stack-fastapi-postgresql ) by @tiangolo himself
177331* [ ` FastAPI Microservices ` ] ( https://github.com/Kludex/fastapi-microservices ) by @kludex which heavily inspired this boilerplate
178- * [ Async Web API with FastAPI + SQLAlchemy 2.0] ( https://github.com/rhoboro/async-fastapi-sqlalchemy )
332+ * [ ` Async Web API with FastAPI + SQLAlchemy 2.0 ` ] ( https://github.com/rhoboro/async-fastapi-sqlalchemy )
179333
180- ## License
334+ ## 13. License
181335[ ` MIT ` ] ( LICENSE.md )
182336
183- ## Contact
337+ ## 14. Contact
184338Igor Magalhaes –
[ @igormagalhaesr ] ( https://twitter.com/igormagalhaesr ) –
[email protected] 185- [ github.com/igormagalhaesr] ( https://github.com/igormagalhaesr/ )
339+ [ github.com/igormagalhaesr] ( https://github.com/igormagalhaesr/ )
0 commit comments