You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-[x] Very minimal project structure yet ready for quick start building new apps
43
44
-[x] Refresh token endpoint (not only access like in official template)
44
45
-[x] Two databases in docker-compose.yml (second one for tests) and ready to go Dockerfile with [Nginx Unit](https://unit.nginx.org/) webserver
45
-
-[x][Poetry](https://python-poetry.org/docs/) and Python 3.10 based
46
-
-[x]`pre-push.sh` script with poetry export, autoflake, black, isort and flake8
46
+
-[x][Poetry](https://python-poetry.org/docs/) and Python 3.11 based
47
+
-[x]`pre-commit` with poetry export, autoflake, black, isort and flake8
47
48
-[x] Rich setup for pytest async tests with few included and extensible `conftest.py`
48
49
49
50
<br>
50
51
51
-
_Check out also online example: https://minimal-fastapi-postgres-template.rafsaf.pl, it's 100% code used in template with added domain and https only._
52
+
_Check out also online example: https://minimal-fastapi-postgres-template.rafsaf.pl, it's 100% code used in template (docker image) with added domain and https only._
### Optionally there is also `requirements-dev.txt` file
76
+
python3.11 -m venv venv
76
77
source venv/bin/activate
77
78
pip install -r requirements-dev.txt
78
79
```
79
80
80
-
Note, be sure to use `python3.10` with this template with either poetry or standard venv & pip, if you need to stick to some earlier python version, you should adapt it yourself (remove python3.10+ specific syntax for example `str | int`)
81
+
Note, be sure to use `python3.11` with this template with either poetry or standard venv & pip, if you need to stick to some earlier python version, you should adapt it yourself (remove new versions specific syntax for example `str | int` for python < 3.10 or `tomllib` for python < 3.11)
81
82
82
83
### 3. Setup databases
83
84
@@ -99,7 +100,21 @@ uvicorn app.main:app --reload
99
100
100
101
You should then use `git init` to initialize git repository and access OpenAPI spec at http://localhost:8000/ by default. To customize docs url, cors and allowed hosts settings, read section about it.
101
102
102
-
### Running tests
103
+
### 5. Activate pre-commit
104
+
105
+
[pre-commit](https://pre-commit.com/) is de facto standard now for pre push activities like isort or black.
106
+
107
+
Refer to `.pre-commit-config.yaml` file to see my opinionated choices.
108
+
109
+
```bash
110
+
# Install pre-commit
111
+
pre-commit install
112
+
113
+
# First initialization and run on all files
114
+
pre-commit run --all-files
115
+
```
116
+
117
+
### 6. Running tests
103
118
104
119
```bash
105
120
# Note, it will use second database declared in docker-compose.yml, not default one
@@ -122,7 +137,7 @@ pytest
122
137
123
138
## About
124
139
125
-
This project is heavily based on the official template https://github.com/tiangolo/full-stack-fastapi-postgresql (and on my previous work: [link1](https://github.com/rafsaf/fastapi-plan), [link2](https://github.com/rafsaf/docker-fastapi-projects)), but as it now not too much up-to-date, it is much easier to create new one than change official. I didn't like some of conventions over there also (`crud` and `db` folders for example or `schemas` with bunch of files).
140
+
This project is heavily based on the official template https://github.com/tiangolo/full-stack-fastapi-postgresql (and on my previous work: [link1](https://github.com/rafsaf/fastapi-plan), [link2](https://github.com/rafsaf/docker-fastapi-projects)), but as it now not too much up-to-date, it is much easier to create new one than change official. I didn't like some of conventions over there also (`crud` and `db` folders for example or `schemas` with bunch of files). This template aims to be as much up-to-date as possible, using only newest python versions and libraries versions.
126
141
127
142
`2.0` style SQLAlchemy API is good enough so there is no need to write everything in `crud` and waste our time... The `core` folder was also rewritten. There is great base for writting tests in `tests`, but I didn't want to write hundreds of them, I noticed that usually after changes in the structure of the project, auto tests are useless and you have to write them from scratch anyway (delete old ones...), hence less than more. Similarly with the `User` model, it is very modest, with just `id` (uuid), `email` and `password_hash`, because it will be adapted to the project anyway.
128
143
@@ -145,51 +160,42 @@ We will add Pet model to `app/models.py`. To keep things clear, below is full re
145
160
# app/models.py
146
161
147
162
import uuid
148
-
from dataclasses import dataclass, field
149
163
150
-
from sqlalchemy importColumn, ForeignKey, Integer, String
164
+
from sqlalchemy import ForeignKey, Integer, String
151
165
from sqlalchemy.dialects.postgresql importUUID
152
-
from sqlalchemy.orm import registry, relationship
166
+
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
Note, we are using super powerful SQLAlchemy feature here - you can read more about this fairy new syntax based on dataclasses [in this topic in the docs](https://docs.sqlalchemy.org/en/14/orm/declarative_styles.html#example-two-dataclasses-with-declarative-table).
198
+
Note, we are using super powerful SQLAlchemy feature here - Mapped and mapped_column were first introduced in SQLAlchemy 2.0 on Feb 26, if this syntax is new for you, read carefully "what's new" part of documentation https://docs.sqlalchemy.org/en/20/changelog/whatsnew_20.html.
193
199
194
200
<br>
195
201
@@ -221,9 +227,9 @@ PS. Note, alembic is configured in a way that it work with async setup and also
221
227
222
228
### 3. Create request and response schemas
223
229
224
-
Note, I personally lately (after seeing clear benefits at work) prefer less files than a lot of them for things like schemas.
230
+
I personally lately (after seeing clear benefits at work in Samsung) prefer less files than a lot of them for things like schemas.
225
231
226
-
Thats why there are only 2 files: `requests.py` and `responses.py` in `schemas` folder and I would keep it that way even for few dozen of endpoints.
232
+
Thats why there are only 2 files: `requests.py` and `responses.py` in `schemas` folder and I would keep it that way even for few dozen of endpoints. Not to mention this is opinionated.
227
233
228
234
```python
229
235
# app/schemas/requests.py
@@ -245,7 +251,7 @@ class PetCreateRequest(BaseRequest):
This template has by default included `Dockerfile` with [Nginx Unit](https://unit.nginx.org/) webserver, that is my prefered choice, because of direct support for FastAPI and great ease of configuration. You should be able to run container(s) (over :80 port) and then need to setup the proxy, loadbalancer, with https enbaled, so the app stays behind it.
382
-
383
-
`nginx-unit-config.json` file included in main folder has some default configuration options, runs app in single process and thread. More info about config file here https://unit.nginx.org/configuration/#python and about also read howto for FastAPI: https://unit.nginx.org/howto/fastapi/.
381
+
This template has by default included `Dockerfile` with [Uvicorn](https://www.uvicorn.org/) webserver, because it's simple and just for showcase purposes, with direct relation to FastAPI and great ease of configuration. You should be able to run container(s) (over :8000 port) and then need to setup the proxy, loadbalancer, with https enbaled, so the app stays behind it.
384
382
385
-
If you prefer other webservers for FastAPI, check out [Daphne](https://github.com/django/daphne), [Hypercorn](https://pgjones.gitlab.io/hypercorn/index.html) or [Uvicorn](https://www.uvicorn.org/).
383
+
If you prefer other webservers for FastAPI, check out [Nginx Unit](https://unit.nginx.org/), [Daphne](https://github.com/django/daphne), [Hypercorn](https://pgjones.gitlab.io/hypercorn/index.html).
alembic==1.9.2 ; python_version>="3.11" and python_version < "4.0"
2
+
anyio==3.6.2 ; python_version>="3.11" and python_version < "4.0"
3
+
asyncpg==0.27.0 ; python_version>="3.11" and python_version < "4.0"
4
+
attrs==22.2.0 ; python_version>="3.11" and python_version < "4.0"
5
+
autoflake==2.0.1 ; python_version>="3.11" and python_version < "4.0"
6
+
bcrypt==4.0.1 ; python_version>="3.11" and python_version < "4.0"
7
+
black==23.1.0 ; python_version>="3.11" and python_version < "4.0"
8
+
certifi==2022.12.7 ; python_version>="3.11" and python_version < "4.0"
9
+
cffi==1.15.1 ; python_version>="3.11" and python_version < "4.0"
10
+
cfgv==3.3.1 ; python_version>="3.11" and python_version < "4.0"
11
+
click==8.1.3 ; python_version>="3.11" and python_version < "4.0"
12
+
colorama==0.4.6 ; python_version>="3.11" and python_version < "4.0" and sys_platform == "win32" or python_version >= "3.11" and python_version < "4.0" and platform_system == "Windows"
13
+
coverage==7.1.0 ; python_version>="3.11" and python_version < "4.0"
14
+
cryptography==39.0.0 ; python_version>="3.11" and python_version < "4.0"
15
+
distlib==0.3.6 ; python_version>="3.11" and python_version < "4.0"
16
+
dnspython==2.3.0 ; python_version>="3.11" and python_version < "4.0"
17
+
email-validator==1.3.1 ; python_version>="3.11" and python_version < "4.0"
18
+
fastapi==0.89.1 ; python_version>="3.11" and python_version < "4.0"
19
+
filelock==3.9.0 ; python_version>="3.11" and python_version < "4.0"
20
+
flake8==6.0.0 ; python_version>="3.11" and python_version < "4.0"
21
+
greenlet==2.0.2 ; python_version>="3.11" and python_version < "4.0" and platform_machine == "aarch64" or python_version >= "3.11" and python_version < "4.0" and platform_machine == "ppc64le" or python_version >= "3.11" and python_version < "4.0" and platform_machine == "x86_64" or python_version >= "3.11" and python_version < "4.0" and platform_machine == "amd64" or python_version >= "3.11" and python_version < "4.0" and platform_machine == "AMD64" or python_version >= "3.11" and python_version < "4.0" and platform_machine == "win32" or python_version >= "3.11" and python_version < "4.0" and platform_machine == "WIN32"
22
+
h11==0.14.0 ; python_version>="3.11" and python_version < "4.0"
23
+
httpcore==0.16.3 ; python_version>="3.11" and python_version < "4.0"
24
+
httptools==0.5.0 ; python_version>="3.11" and python_version < "4.0"
25
+
httpx==0.23.3 ; python_version>="3.11" and python_version < "4.0"
26
+
identify==2.5.17 ; python_version>="3.11" and python_version < "4.0"
27
+
idna==3.4 ; python_version>="3.11" and python_version < "4.0"
28
+
iniconfig==2.0.0 ; python_version>="3.11" and python_version < "4.0"
29
+
isort==5.12.0 ; python_version>="3.11" and python_version < "4.0"
30
+
mako==1.2.4 ; python_version>="3.11" and python_version < "4.0"
31
+
markupsafe==2.1.2 ; python_version>="3.11" and python_version < "4.0"
32
+
mccabe==0.7.0 ; python_version>="3.11" and python_version < "4.0"
33
+
mypy-extensions==1.0.0 ; python_version>="3.11" and python_version < "4.0"
34
+
nodeenv==1.7.0 ; python_version>="3.11" and python_version < "4.0"
35
+
packaging==23.0 ; python_version>="3.11" and python_version < "4.0"
36
+
passlib[bcrypt]==1.7.4 ; python_version>="3.11" and python_version < "4.0"
37
+
pathspec==0.11.0 ; python_version>="3.11" and python_version < "4.0"
38
+
platformdirs==2.6.2 ; python_version>="3.11" and python_version < "4.0"
39
+
pluggy==1.0.0 ; python_version>="3.11" and python_version < "4.0"
40
+
pre-commit==3.0.4 ; python_version>="3.11" and python_version < "4.0"
41
+
pycodestyle==2.10.0 ; python_version>="3.11" and python_version < "4.0"
42
+
pycparser==2.21 ; python_version>="3.11" and python_version < "4.0"
43
+
pydantic==1.10.4 ; python_version>="3.11" and python_version < "4.0"
44
+
pydantic[dotenv,email]==1.10.4 ; python_version>="3.11" and python_version < "4.0"
45
+
pyflakes==3.0.1 ; python_version>="3.11" and python_version < "4.0"
46
+
pyjwt[crypto]==2.6.0 ; python_version>="3.11" and python_version < "4.0"
47
+
pytest-asyncio==0.20.3 ; python_version>="3.11" and python_version < "4.0"
48
+
pytest==7.2.1 ; python_version>="3.11" and python_version < "4.0"
49
+
python-dotenv==0.21.1 ; python_version>="3.11" and python_version < "4.0"
50
+
python-multipart==0.0.5 ; python_version>="3.11" and python_version < "4.0"
51
+
pyyaml==6.0 ; python_version>="3.11" and python_version < "4.0"
52
+
rfc3986[idna2008]==1.5.0 ; python_version>="3.11" and python_version < "4.0"
53
+
setuptools==67.1.0 ; python_version>="3.11" and python_version < "4.0"
54
+
six==1.16.0 ; python_version>="3.11" and python_version < "4.0"
55
+
sniffio==1.3.0 ; python_version>="3.11" and python_version < "4.0"
56
+
sqlalchemy==2.0.1 ; python_version>="3.11" and python_version < "4.0"
57
+
starlette==0.22.0 ; python_version>="3.11" and python_version < "4.0"
58
+
typing-extensions==4.4.0 ; python_version>="3.11" and python_version < "4.0"
59
+
uvicorn[standard]==0.20.0 ; python_version>="3.11" and python_version < "4.0"
60
+
uvloop==0.17.0 ; sys_platform!="win32" and sys_platform != "cygwin" and platform_python_implementation != "PyPy" and python_version >= "3.11" and python_version < "4.0"
61
+
virtualenv==20.17.1 ; python_version>="3.11" and python_version < "4.0"
62
+
watchfiles==0.18.1 ; python_version>="3.11" and python_version < "4.0"
63
+
websockets==10.4 ; python_version>="3.11" and python_version < "4.0"
0 commit comments