Skip to content

Commit db06010

Browse files
authored
Update README.md
1 parent b49e5ee commit db06010

File tree

1 file changed

+176
-22
lines changed

1 file changed

+176
-22
lines changed

README.md

Lines changed: 176 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,60 @@
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
2253
git clone https://github.com/igormagalhaesr/FastAPI-boilerplate
2354
```
2455
___
25-
## Requirements
26-
### Packages
56+
## 4. Requirements
57+
### 4.1 Packages
2758
Then install poetry:
2859
```sh
2960
pip install poetry
@@ -34,7 +65,7 @@ In the **src** directory, run to install required packages:
3465
poetry install
3566
```
3667

37-
### Environment Variables
68+
### 4.2 Environment Variables
3869
Then create a .env file:
3970
```sh
4071
touch .env
@@ -85,7 +116,7 @@ ADMIN_PASSWORD="your_password"
85116
```
86117

87118
___
88-
## Running PostgreSQL with docker:
119+
## 5. Running PostgreSQL with docker:
89120
Install docker if you don't have it yet, then run:
90121
```sh
91122
docker 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
118149
While in the **src** folder, run to start the application with uvicorn server:
119150
```sh
120151
poetry run uvicorn app.main:app --reload
121152
```
122153

123154
___
124-
## Creating the first superuser:
155+
## 7. Creating the first superuser:
125156
While in the **src** folder, run (after you started the application at least once to create the tables):
126157
```sh
127158
poetry run python -m scripts.create_first_superuser
128159
```
129160

130161
___
131-
## Database Migrations
162+
## 8. Database Migrations
132163
Migrations 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
136167
poetry 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
146300
For tests, create in .env:
147301
```
148302
# ------------- test -------------
@@ -152,7 +306,7 @@ TEST_USERNAME="testeruser"
152306
TEST_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
157311
touch test_items.py
158312
```
@@ -162,24 +316,24 @@ Finally create your tests (you may want to copy the structure in test_user.py),
162316
poetry 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:
167321
1. Fork it (https://github.com/igormagalhaesr/FastAPI-boilerplate)
168322
2. Create your feature branch (`git checkout -b feature/fooBar`)
169323
3. Test your changes while in the src folder `poetry run python -m pytest`
170324
4. Commit your changes (`git commit -am 'Add some fooBar'`)
171325
5. Push to the branch (`git push origin feature/fooBar`)
172326
6. Create a new Pull Request
173327

174-
## References
328+
## 12. References
175329
This 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
184338
Igor 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

Comments
 (0)