Compare commits

...

38 Commits

Author SHA1 Message Date
Sebastián Ramírez
a085898309 🔖 Release version 0.47.1 2020-01-18 18:06:47 +01:00
Sebastián Ramírez
3b40c557ce 📝 Update release notes 2020-01-18 18:06:20 +01:00
Sebastián Ramírez
75a07f24bf 🔒 Fix clone field implementation to handle sub-models in response_model (#889) 2020-01-18 18:03:51 +01:00
Sebastián Ramírez
7cea84b74c 🐛 Fix FastAPI serialization of Pydantic ORM mode blocking the event loop (#888) 2020-01-18 17:32:57 +01:00
Sebastián Ramírez
3a5158a784 🔖 Release version 0.47.0 2020-01-18 17:14:59 +01:00
Sebastián Ramírez
bd581c5337 📝 Update release notes 2020-01-18 17:14:03 +01:00
Sebastián Ramírez
22982287ff 📝 Refactor docs, "Tutorial - User Guide" and "Advanced User Guide" (#887) 2020-01-18 16:21:54 +01:00
Sebastián Ramírez
a41a729682 🎨 Tweak external links, Markdown format, typos (#881) 2020-01-17 16:24:05 +01:00
Pavel Isaev
174e7b1730 🔒 Check both username and password in security tutorial (#865) 2020-01-17 12:49:54 +01:00
Nik
874d24181e 🐛 Fix validating form params declared with classes (list, tuple, set, etc) (#856) 2020-01-17 12:45:55 +01:00
Aviram Hassan
5db99a27cf add body to RequestValidationError for easier debugging (#853) 2020-01-17 12:37:44 +01:00
Sebastián Ramírez
180b842a1e 📝 Add external links, dynamic GitHub topic projects, and formatting (#850) 2020-01-17 10:46:44 +01:00
Sebastián Ramírez
3f53deebc9 🐛 Fix Peewee contextvars handling in docs (#879) 2020-01-17 09:59:38 +01:00
Sebastián Ramírez
e5d7878856 Use venv with Flit for local development, instead of requiring Flit and Pipenv (#877) 2020-01-17 09:51:03 +01:00
Sebastián Ramírez
3eca945bd1 📝 Udpate release notes 2020-01-12 20:43:46 +01:00
Zachary Wasserman
ba9c9a3f78 🔒 Update HTTP Basic Auth docs fixing timing attacks (#807) 2020-01-12 20:38:39 +01:00
Sebastián Ramírez
a9673f145a 🔖 Release version 0.46.0 2020-01-08 23:28:03 +01:00
Sebastián Ramírez
aa28784f6b 📝 Update release notes 2020-01-08 23:26:15 +01:00
Sebastián Ramírez
7b3319ddab ✏️ Tweak typos and configs (#837) 2020-01-08 23:25:29 +01:00
Sebastián Ramírez
6a20078259 📝 Update release notes 2020-01-08 23:03:08 +01:00
wxq0309
d0ab909544 📝 Add link to Chinese FastAPI posts (#810) 2020-01-08 23:01:58 +01:00
Sebastián Ramírez
13da029dca 📝 Update release notes 2020-01-08 22:51:55 +01:00
Jesse P. Johnson
91fe90e8e6 Implement OAuth2 authorization_code integration (#797) 2020-01-08 22:47:19 +01:00
Sebastián Ramírez
a0c8f93231 📝 Update release notes 2020-01-08 22:35:33 +01:00
Christoph Deil
cad6a6e0c1 📝 Highlight all new lines in docs example upgrade (#795) 2020-01-08 22:34:14 +01:00
Sebastián Ramírez
fd5ba77b83 📝 Update release notes 2020-01-08 22:23:54 +01:00
James Kaplan
cb1410426e 🐛 Fix callback handling in sub-routers (#792) 2020-01-08 22:22:14 +01:00
Sebastián Ramírez
7b31e52766 📝 Update release notes 2020-01-08 22:02:32 +01:00
Ken Kinder
4151616681 ✏️ Fix typos (#784) 2020-01-08 22:01:22 +01:00
Sebastián Ramírez
462e24e864 📝 Update release notes 2020-01-08 22:00:44 +01:00
Xucong ZHAN
9f9ed7a6bd 📝 Add four JP articles to external links (#783) 2020-01-08 21:58:33 +01:00
Sebastián Ramírez
b6ea9ea2ca 📝 Update release notes 2020-01-08 21:53:14 +01:00
Roald Storm
b85b2e3942 Add support for subtypes of main types in jsonable_encoder 2020-01-08 21:50:21 +01:00
Sebastián Ramírez
08fc2a41ca 📝 Update release notes 2020-01-08 19:16:57 +01:00
Dustyposa
8d3dcbcd1b fix type UrlStr -> HttpUrl (#832) 2020-01-08 00:08:43 -08:00
Justin DuJardin
861ed37c97 📝 update twitter compose tweet links (#813)
The links to post @tiangolo were not working
2019-12-30 15:22:11 -07:00
Sebastián Ramírez
7a445402d4 📝 Update release notes 2019-12-13 11:32:17 +01:00
Sebastián Ramírez
04c8502cc7 📝 Add docs for correctly using Peewee (#789) 2019-12-13 11:29:18 +01:00
127 changed files with 3087 additions and 932 deletions

1
.gitignore vendored
View File

@@ -13,3 +13,4 @@ coverage.xml
test.db
log.txt
Pipfile.lock
env3.*

View File

@@ -25,8 +25,8 @@ after_script:
- bash <(curl -s https://codecov.io/bash)
deploy:
provider: script
script: bash scripts/deploy.sh
on:
tags: true
python: "3.6"
provider: script
script: bash scripts/deploy.sh
on:
tags: true
python: "3.6"

38
Pipfile
View File

@@ -1,38 +0,0 @@
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
mypy = "*"
black = "*"
jupyter = "*"
better-exceptions = "*"
pytest = "*"
pytest-cov = "*"
isort = "*"
requests = "*"
flit = "*"
mkdocs = "*"
mkdocs-material = "*"
markdown-include = "*"
autoflake = "*"
email-validator = "*"
ujson = "*"
flake8 = "*"
python-multipart = "*"
sqlalchemy = "*"
uvicorn = "*"
[packages]
starlette = "==0.12.9"
pydantic = "==1.0.0"
databases = {extras = ["sqlite"],version = "*"}
hypercorn = "*"
orjson = "*"
[requires]
python_version = "3.6"
[pipenv]
allow_prereleases = true

View File

@@ -5,8 +5,8 @@
<em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
</p>
<p align="center">
<a href="https://travis-ci.org/tiangolo/fastapi" target="_blank">
<img src="https://travis-ci.org/tiangolo/fastapi.svg?branch=master" alt="Build Status">
<a href="https://travis-ci.com/tiangolo/fastapi" target="_blank">
<img src="https://travis-ci.com/tiangolo/fastapi.svg?branch=master" alt="Build Status">
</a>
<a href="https://codecov.io/gh/tiangolo/fastapi" target="_blank">
<img src="https://codecov.io/gh/tiangolo/fastapi/branch/master/graph/badge.svg" alt="Coverage">
@@ -39,7 +39,7 @@ The key features are:
* **Easy**: Designed to be easy to use and learn. Less time reading docs.
* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
* **Robust**: Get production-ready code. With automatic interactive documentation.
* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: <a href="https://github.com/OAI/OpenAPI-Specification" target="_blank">OpenAPI</a> (previously known as Swagger) and <a href="http://json-schema.org/" target="_blank">JSON Schema</a>.
* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (previously known as Swagger) and <a href="http://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
<small>* estimation based on tests on an internal development team, building production applications.</small>
@@ -83,9 +83,8 @@ Python 3.6+
FastAPI stands on the shoulders of giants:
* <a href="https://www.starlette.io/" target="_blank">Starlette</a> for the web parts.
* <a href="https://pydantic-docs.helpmanual.io/" target="_blank">Pydantic</a> for the data parts.
* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> for the web parts.
* <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> for the data parts.
## Installation
@@ -93,7 +92,7 @@ FastAPI stands on the shoulders of giants:
pip install fastapi
```
You will also need an ASGI server, for production such as <a href="http://www.uvicorn.org" target="_blank">Uvicorn</a> or <a href="https://gitlab.com/pgjones/hypercorn" target="_blank">Hypercorn</a>.
You will also need an ASGI server, for production such as <a href="http://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> or <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
```bash
pip install uvicorn
@@ -120,6 +119,7 @@ def read_root():
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
```
<details markdown="1">
<summary>Or use <code>async def</code>...</summary>
@@ -142,7 +142,7 @@ async def read_item(item_id: int, q: str = None):
```
**Note**:
If you don't know, check the _"In a hurry?"_ section about <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">`async` and `await` in the docs</a>.
</details>
@@ -168,7 +168,7 @@ The command `uvicorn main:app` refers to:
### Check it
Open your browser at <a href="http://127.0.0.1:8000/items/5?q=somequery" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
Open your browser at <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
You will see the JSON response as:
@@ -185,18 +185,17 @@ You already created an API that:
### Interactive API docs
Now go to <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" target="_blank">Swagger UI</a>):
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### Alternative API docs
And now, go to <a href="http://127.0.0.1:8000/redoc" target="_blank">http://127.0.0.1:8000/redoc</a>.
And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" target="_blank">ReDoc</a>):
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
@@ -206,8 +205,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
Declare the body using standard Python types, thanks to Pydantic.
```Python hl_lines="2 7 8 9 10 24"
```Python hl_lines="2 7 8 9 10 23 24 25"
from fastapi import FastAPI
from pydantic import BaseModel
@@ -239,7 +237,7 @@ The server should reload automatically (because you added `--reload` to the `uvi
### Interactive API docs upgrade
Now go to <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
* The interactive API documentation will be automatically updated, including the new body:
@@ -253,16 +251,14 @@ Now go to <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)
### Alternative API docs upgrade
And now, go to <a href="http://127.0.0.1:8000/redoc" target="_blank">http://127.0.0.1:8000/redoc</a>.
And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
* The alternative documentation will also reflect the new query parameter and body:
![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
### Recap
In summary, you declare **once** the types of parameters, body, etc. as function parameters.
@@ -332,7 +328,6 @@ Coming back to the previous code example, **FastAPI** will:
* Automatic client code generation systems, for many languages.
* Provide 2 interactive documentation web interfaces directly.
---
We just scratched the surface, but you already get the idea of how it all works.
@@ -359,8 +354,7 @@ Try changing the line with:
![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)
For a more complete example including more features, see the <a href="https://fastapi.tiangolo.com/tutorial/intro/">Tutorial - User Guide</a>.
For a more complete example including more features, see the <a href="https://fastapi.tiangolo.com/tutorial/">Tutorial - User Guide</a>.
**Spoiler alert**: the tutorial - user guide includes:
@@ -377,12 +371,11 @@ For a more complete example including more features, see the <a href="https://fa
* **Cookie Sessions**
* ...and more.
## Performance
Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" target="_blank">one of the fastest Python frameworks available</a>, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">one of the fastest Python frameworks available</a>, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
To understand more about it, see the section <a href="https://fastapi.tiangolo.com/benchmarks/" target="_blank">Benchmarks</a>.
To understand more about it, see the section <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">Benchmarks</a>.
## Optional Dependencies
@@ -391,7 +384,6 @@ Used by Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
Used by Starlette:
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
@@ -399,7 +391,7 @@ Used by Starlette:
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Required for `SchemaGenerator` support.
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI).
* <a href="https://graphene-python.org/" target="_blank"><code>graphene</code></a> - Required for `GraphQLApp` support.
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Required if you want to use `UJSONResponse`.
@@ -407,7 +399,7 @@ Used by FastAPI / Starlette:
* <a href="http://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - for the server that loads and serves your application.
You can install all of these with `pip3 install fastapi[all]`.
You can install all of these with `pip install fastapi[all]`.
## License

View File

@@ -1,6 +1,6 @@
!!! warning
This is a rather advanced topic.
If you are starting with **FastAPI**, you might not need this.
You can declare additional responses, with additional status codes, media types, descriptions, etc.
@@ -21,7 +21,6 @@ Each of those response `dict`s can have a key `model`, containing a Pydantic mod
For example, to declare another response with a status code `404` and a Pydantic model `Message`, you can write:
```Python hl_lines="18 23"
{!./src/additional_responses/tutorial001.py!}
```
@@ -199,7 +198,6 @@ It will all be combined and included in your OpenAPI, and shown in the API docs:
<img src="/img/tutorial/additional-responses/image01.png">
## Combine predefined responses and custom ones
You might want to have some predefined responses that apply to many *path operations*, but you want to combine them with custom responses needed by each *path operation*.
@@ -236,5 +234,5 @@ For example:
To see what exactly you can include in the responses, you can check these sections in the OpenAPI specification:
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responsesObject" target="_blank">OpenAPI Responses Object</a>, it includes the `Response Object`.
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responseObject" target="_blank">OpenAPI Response Object</a>, you can include anything from this directly in each response inside your `responses` parameter. Including `description`, `headers`, `content` (inside of this is that you declare different media types and JSON Schemas), and `links`.
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responsesObject" class="external-link" target="_blank">OpenAPI Responses Object</a>, it includes the `Response Object`.
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responseObject" class="external-link" target="_blank">OpenAPI Response Object</a>, you can include anything from this directly in each response inside your `responses` parameter. Including `description`, `headers`, `content` (inside of this is that you declare different media types and JSON Schemas), and `links`.

View File

@@ -27,4 +27,4 @@ To achieve that, import `JSONResponse`, and return your content there directly,
If you return additional status codes and responses directly, they won't be included in the OpenAPI schema (the API docs), because FastAPI doesn't have a way to know before hand what you are going to return.
But you can document that in your code, using: <a href="https://fastapi.tiangolo.com/tutorial/additional-responses/" target="_blank">Additional Responses</a>.
But you can document that in your code, using: [Additional Responses](additional-responses.md){.internal-link target=_blank}.

View File

@@ -57,7 +57,7 @@ And when solving the dependency, **FastAPI** will call this `checker` like:
checker(q="somequery")
```
...and pass whatever that returns as the value of the dependency in our path operation function as the parameter `fixed_content_included`:
...and pass whatever that returns as the value of the dependency in our *path operation function* as the parameter `fixed_content_included`:
```Python hl_lines="20"
{!./src/dependencies/tutorial011.py!}
@@ -68,6 +68,6 @@ checker(q="somequery")
These examples are intentionally simple, but show how it all works.
In the chapters about security, you will be using utility functions that are implemented in this same way.
In the chapters about security, there are utility functions that are implemented in this same way.
If you understood all this, you already know how those utility tools for security work underneath.

View File

@@ -1,4 +1,4 @@
You can also use <a href="https://github.com/encode/databases" target="_blank">`encode/databases`</a> with **FastAPI** to connect to databases using `async` and `await`.
You can also use <a href="https://github.com/encode/databases" class="external-link" target="_blank">`encode/databases`</a> with **FastAPI** to connect to databases using `async` and `await`.
It is compatible with:
@@ -11,9 +11,9 @@ In this example, we'll use **SQLite**, because it uses a single file and Python
Later, for your production application, you might want to use a database server like **PostgreSQL**.
!!! tip
You could adopt ideas from the previous section about <a href="/tutorial/sql-databases/" target="_blank">SQLAlchemy ORM</a>, like using utility functions to perform operations in the database, independent of your **FastAPI** code.
You could adopt ideas from the section about SQLAlchemy ORM ([SQL (Relational) Databases](../tutorial/sql-databases.md){.internal-link target=_blank}), like using utility functions to perform operations in the database, independent of your **FastAPI** code.
This section doesn't apply those ideas, to be equivalent to the counterpart in <a href="https://www.starlette.io/database/" target="_blank">Starlette</a>.
This section doesn't apply those ideas, to be equivalent to the counterpart in <a href="https://www.starlette.io/database/" class="external-link" target="_blank">Starlette</a>.
## Import and set up `SQLAlchemy`
@@ -149,7 +149,7 @@ So, the final result returned would be something like:
## Check it
You can copy this code as is, and see the docs at <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
You can copy this code as is, and see the docs at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
There you can see all your API documented and interact with it:
@@ -157,4 +157,4 @@ There you can see all your API documented and interact with it:
## More info
You can read more about <a href="https://github.com/encode/databases" target="_blank">`encode/databases` at its GitHub page</a>.
You can read more about <a href="https://github.com/encode/databases" class="external-link" target="_blank">`encode/databases` at its GitHub page</a>.

View File

@@ -13,10 +13,9 @@ For example, if you want to read or manipulate the request body before it is pro
Some use cases include:
* Converting non-JSON request bodies to JSON (e.g. [`msgpack`](https://msgpack.org/index.html)).
* Converting non-JSON request bodies to JSON (e.g. <a href="https://msgpack.org/index.html" class="external-link" target="_blank">`msgpack`</a>).
* Decompressing gzip-compressed request bodies.
* Automatically logging all request bodies.
* Accessing the request body in an exception handler.
## Handling custom request body encodings
@@ -59,7 +58,7 @@ Here we use it to create a `GzipRequest` from the original request.
And those two things, `scope` and `receive`, are what is needed to create a new `Request` instance.
To learn more about the `Request` check <a href="https://www.starlette.io/requests/" target="_blank">Starlette's docs about Requests</a>.
To learn more about the `Request` check <a href="https://www.starlette.io/requests/" class="external-link" target="_blank">Starlette's docs about Requests</a>.
The only thing the function returned by `GzipRequest.get_route_handler` does differently is convert the `Request` to a `GzipRequest`.
@@ -71,6 +70,11 @@ But because of our changes in `GzipRequest.body`, the request body will be autom
## Accessing the request body in an exception handler
!!! tip
To solve this same problem, it's probably a lot easier to use the `body` in a custom handler for `RequestValidationError` ([Handling Errors](../tutorial/handling-errors.md#use-the-requestvalidationerror-body){.internal-link target=_blank}).
But this example is still valid and it shows how to interact with the internal components.
We can also use this same approach to access the request body in an exception handler.
All we need to do is handle the request inside a `try`/`except` block:
@@ -89,12 +93,12 @@ If an exception occurs, the`Request` instance will still be in scope, so we can
You can also set the `route_class` parameter of an `APIRouter`:
```Python hl_lines="25"
```Python hl_lines="28"
{!./src/custom_request_and_route/tutorial003.py!}
```
In this example, the *path operations* under the `router` will use the custom `TimedRoute` class, and will have an extra `X-Response-Time` header in the response with the time it took to generate the response:
```Python hl_lines="15 16 17 18 19"
```Python hl_lines="15 16 17 18 19 20 21 22"
{!./src/custom_request_and_route/tutorial003.py!}
```

View File

@@ -5,7 +5,7 @@
By default, **FastAPI** will return the responses using Starlette's `JSONResponse`.
You can override it by returning a `Response` directly, <a href="https://fastapi.tiangolo.com/tutorial/response-directly/" target="_blank">as seen in a previous section</a>.
You can override it by returning a `Response` directly as seen in [Return a Response directly](response-directly.md){.internal-link target=_blank}.
But if you return a `Response` directly, the data won't be automatically converted, and the documentation won't be automatically generated (for example, including the specific "media type", in the HTTP header `Content-Type`).
@@ -43,7 +43,7 @@ Import the `Response` class (sub-class) you want to use and declare it in the *p
To return a response with HTML directly from **FastAPI**, use `HTMLResponse`.
* Import `HTMLResponse`.
* Pass `HTMLResponse` as the parameter `content_type` of your path operation.
* Pass `HTMLResponse` as the parameter `content_type` of your *path operation*.
```Python hl_lines="2 7"
{!./src/custom_response/tutorial002.py!}
@@ -61,7 +61,7 @@ To return a response with HTML directly from **FastAPI**, use `HTMLResponse`.
### Return a Starlette `Response`
As seen in <a href="https://fastapi.tiangolo.com/tutorial/response-directly/" target="_blank">another section</a>, you can also override the response directly in your path operation, by returning it.
As seen in [Return a Response directly](response-directly.md){.internal-link target=_blank}, you can also override the response directly in your *path operation*, by returning it.
The same example from above, returning an `HTMLResponse`, could look like:
@@ -70,7 +70,7 @@ The same example from above, returning an `HTMLResponse`, could look like:
```
!!! warning
A `Response` returned directly by your path operation function won't be documented in OpenAPI (for example, the `Content-Type` won't be documented) and won't be visible in the automatic interactive docs.
A `Response` returned directly by your *path operation function* won't be documented in OpenAPI (for example, the `Content-Type` won't be documented) and won't be visible in the automatic interactive docs.
!!! info
Of course, the actual `Content-Type` header, status code, etc, will come from the `Response` object your returned.
@@ -79,7 +79,7 @@ The same example from above, returning an `HTMLResponse`, could look like:
If you want to override the response from inside of the function but at the same time document the "media type" in OpenAPI, you can use the `response_class` parameter AND return a `Response` object.
The `response_class` will then be used only to document the OpenAPI path operation, but your `Response` will be used as is.
The `response_class` will then be used only to document the OpenAPI *path operation*, but your `Response` will be used as is.
#### Return an `HTMLResponse` directly
@@ -99,4 +99,4 @@ But as you passed the `HTMLResponse` in the `response_class`, **FastAPI** will k
## Additional documentation
You can also declare the media type and many other details in OpenAPI using `responses`: <a href="https://fastapi.tiangolo.com/tutorial/additional-responses/" target="_blank">Additional Responses in OpenAPI</a>.
You can also declare the media type and many other details in OpenAPI using `responses`: [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}.

View File

@@ -32,12 +32,12 @@ Here, the `shutdown` event handler function will write a text line `"Application
!!! tip
Notice that in this case we are using a standard Python `open()` function that interacts with a file.
So, it involves I/O (input/output), that requires "waiting" for things to be written to disk.
But `open()` doesn't use `async` and `await`.
So, we declare the event handler function with standard `def` instead of `async def`.
!!! info
You can read more about these event handlers in <a href="https://www.starlette.io/events/" target="_blank">Starlette's Events' docs</a>.
You can read more about these event handlers in <a href="https://www.starlette.io/events/" class="external-link" target="_blank">Starlette's Events' docs</a>.

View File

@@ -5,7 +5,6 @@
If you already know that you need to modify the generated OpenAPI schema, continue reading.
There are some cases where you might need to modify the generated OpenAPI schema.
In this section you will see how.
@@ -37,7 +36,7 @@ And that function `get_openapi()` receives as parameters:
Using the information above, you can use the same utility function to generate the OpenAPI schema and override each part that you need.
For example, let's add <a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" target="_blank">ReDoc's OpenAPI extension to include a custom logo</a>.
For example, let's add <a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" class="external-link" target="_blank">ReDoc's OpenAPI extension to include a custom logo</a>.
### Normal **FastAPI**
@@ -85,7 +84,7 @@ Now you can replace the `.openapi()` method with your new function.
### Check it
Once you go to <a href="http://127.0.0.1:8000/redoc" target="_blank">http://127.0.0.1:8000/redoc</a> you will see that you are using your custom logo (in this example, **FastAPI**'s logo):
Once you go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> you will see that you are using your custom logo (in this example, **FastAPI**'s logo):
<img src="/img/tutorial/extending-openapi/image01.png">
@@ -132,12 +131,12 @@ You can probably right-click each link and select an option similar to `Save lin
**Swagger UI** uses the files:
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui-bundle.js">`swagger-ui-bundle.js`</a>
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui.css" target="_blank">`swagger-ui.css`</a>
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui-bundle.js" class="external-link" target="_blank">`swagger-ui-bundle.js`</a>
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui.css" class="external-link" target="_blank">`swagger-ui.css`</a>
And **ReDoc** uses the file:
* <a href="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js" target="_blank">`redoc.standalone.js`</a>
* <a href="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js" class="external-link" target="_blank">`redoc.standalone.js`</a>
After that, your file structure could look like:
@@ -163,7 +162,7 @@ pip install aiofiles
### Serve the static files
* Import `StaticFiles` from Starlette.
* "Mount" it the same way you would <a href="https://fastapi.tiangolo.com/tutorial/sub-applications-proxy/" target="_blank">mount a Sub-Application</a>.
* "Mount" a `StaticFiles()` instance in a specific path.
```Python hl_lines="7 11"
{!./src/extending_openapi/tutorial002.py!}
@@ -171,7 +170,7 @@ pip install aiofiles
### Test the static files
Start your application and go to <a href="http://127.0.0.1:8000/static/redoc.standalone.js" target="_blank">http://127.0.0.1:8000/static/redoc.standalone.js</a>.
Start your application and go to <a href="http://127.0.0.1:8000/static/redoc.standalone.js" class="external-link" target="_blank">http://127.0.0.1:8000/static/redoc.standalone.js</a>.
You should see a very long JavaScript file for **ReDoc**.
@@ -230,7 +229,7 @@ And similarly for ReDoc...
### Create a *path operation* to test it
Now, to be able to test that everything works, create a path operation:
Now, to be able to test that everything works, create a *path operation*:
```Python hl_lines="39 40 41"
{!./src/extending_openapi/tutorial002.py!}
@@ -238,6 +237,6 @@ Now, to be able to test that everything works, create a path operation:
### Test it
Now, you should be able to disconnect your WiFi, go to your docs at <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>, and reload the page.
Now, you should be able to disconnect your WiFi, go to your docs at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, and reload the page.
And even without Internet, you would be able to see the docs for your API and interact with it.

View File

@@ -1,11 +1,11 @@
**FastAPI** has optional support for GraphQL (provided by Starlette directly), using the `graphene` library.
You can combine normal FastAPI path operations with GraphQL on the same application.
You can combine normal FastAPI *path operations* with GraphQL on the same application.
## Import and use `graphene`
GraphQL is implemented with Graphene, you can check <a href="https://docs.graphene-python.org/en/latest/quickstart/" target="_blank">Graphene's docs</a> for more details.
GraphQL is implemented with Graphene, you can check <a href="https://docs.graphene-python.org/en/latest/quickstart/" class="external-link" target="_blank">Graphene's docs</a> for more details.
Import `graphene` and define your GraphQL data:
@@ -26,13 +26,12 @@ Then import and add Starlette's `GraphQLApp`:
## Check it
Run it with Uvicorn and open your browser at <a href="http://127.0.0.1:8000" target="_blank">http://127.0.0.1:8000</a>.
Run it with Uvicorn and open your browser at <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
You will see GraphiQL web user interface:
<img src="/img/tutorial/graphql/image01.png">
## More details
For more details, including:
@@ -41,4 +40,4 @@ For more details, including:
* Adding background tasks
* Using normal or async functions
check the official <a href="https://www.starlette.io/graphql/" target="_blank">Starlette GraphQL docs</a>.
check the official <a href="https://www.starlette.io/graphql/" class="external-link" target="_blank">Starlette GraphQL docs</a>.

16
docs/advanced/index.md Normal file
View File

@@ -0,0 +1,16 @@
## Additional Features
The main [Tutorial - User Guide](../tutorial/){.internal-link target=_blank} should be enough to give you a tour through all the main features of **FastAPI**.
In the next sections you will see other options, configurations, and additional features.
!!! tip
The next sections are **not necessarily "advanced"**.
And it's possible that for your use case, the solution is in one of them.
## Read the Tutorial first
You could still use most of the features in **FastAPI** with the knowledge from the main [Tutorial - User Guide](../tutorial/){.internal-link target=_blank}.
And the next sections assume you already read it, and assume that you know those main ideas.

View File

@@ -1,6 +1,6 @@
**FastAPI** can also be integrated with any <abbr title="Distributed database (Big Data), also 'Not Only SQL'">NoSQL</abbr>.
Here we'll see an example using **<a href="https://www.couchbase.com/" target="_blank">Couchbase</a>**, a <abbr title="Document here refers to a JSON object (a dict), with keys and values, and those values can also be other JSON objects, arrays (lists), numbers, strings, booleans, etc.">document</abbr> based NoSQL database.
Here we'll see an example using **<a href="https://www.couchbase.com/" class="external-link" target="_blank">Couchbase</a>**, a <abbr title="Document here refers to a JSON object (a dict), with keys and values, and those values can also be other JSON objects, arrays (lists), numbers, strings, booleans, etc.">document</abbr> based NoSQL database.
You can adapt it to any other NoSQL database like:
@@ -11,7 +11,7 @@ You can adapt it to any other NoSQL database like:
* **ElasticSearch**, etc.
!!! tip
There is an official project generator with **FastAPI** and **Couchbase**, all based on **Docker**, including a frontend and more tools: <a href="https://github.com/tiangolo/full-stack-fastapi-couchbase" target="_blank">https://github.com/tiangolo/full-stack-fastapi-couchbase</a>
There is an official project generator with **FastAPI** and **Couchbase**, all based on **Docker**, including a frontend and more tools: <a href="https://github.com/tiangolo/full-stack-fastapi-couchbase" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-couchbase</a>
## Import Couchbase components
@@ -68,7 +68,7 @@ First, let's create a `User` model:
{!./src/nosql_databases/tutorial001.py!}
```
We will use this model in our path operation function, so, we don't include in it the `hashed_password`.
We will use this model in our *path operation function*, so, we don't include in it the `hashed_password`.
### `UserInDB` model
@@ -84,9 +84,8 @@ We don't create it as a subclass of Pydantic's `BaseModel` but as a subclass of
!!! note
Notice that we have a `hashed_password` and a `type` field that will be stored in the database.
But it is not part of the general `User` model (the one we will return in the path operation).
But it is not part of the general `User` model (the one we will return in the *path operation*).
## Get the user
@@ -97,21 +96,21 @@ Now create a function that will:
* Get the document with that ID.
* Put the contents of the document in a `UserInDB` model.
By creating a function that is only dedicated to getting your user from a `username` (or any other parameter) independent of your path operation function, you can more easily re-use it in multiple parts and also add <abbr title="Automated test, written in code, that checks if another piece of code is working correctly.">unit tests</abbr> for it:
By creating a function that is only dedicated to getting your user from a `username` (or any other parameter) independent of your *path operation function*, you can more easily re-use it in multiple parts and also add <abbr title="Automated test, written in code, that checks if another piece of code is working correctly.">unit tests</abbr> for it:
```Python hl_lines="37 38 39 40 41 42 43"
{!./src/nosql_databases/tutorial001.py!}
```
### f-strings
If you are not familiar with the `f"userprofile::{username}"`, it is a Python "<a href="https://docs.python.org/3/glossary.html#term-f-string" target="_blank">f-string</a>".
If you are not familiar with the `f"userprofile::{username}"`, it is a Python "<a href="https://docs.python.org/3/glossary.html#term-f-string" class="external-link" target="_blank">f-string</a>".
Any variable that is put inside of `{}` in an f-string will be expanded / injected in the string.
### `dict` unpacking
If you are not familiar with the `UserInDB(**result.value)`, <a href="https://docs.python.org/3/glossary.html#term-argument" target="_blank">it is using `dict` "unpacking"</a>.
If you are not familiar with the `UserInDB(**result.value)`, <a href="https://docs.python.org/3/glossary.html#term-argument" class="external-link" target="_blank">it is using `dict` "unpacking"</a>.
It will take the `dict` at `result.value`, and take each of its keys and values and pass them as key-values to `UserInDB` as keyword arguments.
@@ -138,9 +137,9 @@ UserInDB(username="johndoe", hashed_password="some_hash")
{!./src/nosql_databases/tutorial001.py!}
```
### Create the path operation function
### Create the *path operation function*
As our code is calling Couchbase and we are not using the <a href="https://docs.couchbase.com/python-sdk/2.5/async-programming.html#asyncio-python-3-5" target="_blank">experimental Python <code>await</code> support</a>, we should declare our function with normal `def` instead of `async def`.
As our code is calling Couchbase and we are not using the <a href="https://docs.couchbase.com/python-sdk/2.5/async-programming.html#asyncio-python-3-5" class="external-link" target="_blank">experimental Python <code>await</code> support</a>, we should declare our function with normal `def` instead of `async def`.
Also, Couchbase recommends not using a single `Bucket` object in multiple "<abbr title="A sequence of code being executed by the program, while at the same time, or at intervals, there can be others being executed too.">thread</abbr>s", so, we can get just get the bucket directly and pass it to our utility functions:

View File

@@ -29,12 +29,12 @@ It will have a *path operation* that will receive an `Invoice` body, and a query
This part is pretty normal, most of the code is probably already familiar to you:
```Python hl_lines="8 9 10 11 12 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54"
```Python hl_lines="8 9 10 11 12 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53"
{!./src/openapi_callbacks/tutorial001.py!}
```
!!! tip
The `callback_url` query parameter uses a Pydantic <a href="https://pydantic-docs.helpmanual.io/usage/types/#urls" target="_blank">URL</a> type.
The `callback_url` query parameter uses a Pydantic <a href="https://pydantic-docs.helpmanual.io/usage/types/#urls" class="external-link" target="_blank">URL</a> type.
The only new thing is the `callbacks=messages_callback_router.routes` as an argument to the *path operation decorator*. We'll see what that is next.
@@ -62,7 +62,7 @@ This example doesn't implement the callback itself (that could be just a line of
!!! tip
The actual callback is just an HTTP request.
When implementing the callback yourself, you could use something like <a href="https://www.encode.io/httpx/" target="_blank">HTTPX</a> or <a href="https://requests.readthedocs.io/" target="_blank">Requests</a>.
When implementing the callback yourself, you could use something like <a href="https://www.encode.io/httpx/" class="external-link" target="_blank">HTTPX</a> or <a href="https://requests.readthedocs.io/" class="external-link" target="_blank">Requests</a>.
## Write the callback documentation code
@@ -103,18 +103,18 @@ It should look just like a normal FastAPI *path operation*:
* It should probably have a declaration of the body it should receive, e.g. `body: InvoiceEvent`.
* And it could also have a declaration of the response it should return, e.g. `response_model=InvoiceEventReceived`.
```Python hl_lines="15 16 17 20 21 27 28 29 30 31 32"
```Python hl_lines="15 16 17 20 21 27 28 29 30 31"
{!./src/openapi_callbacks/tutorial001.py!}
```
There are 2 main differences from a normal *path operation*:
* It doesn't need to have any actual code, because your app will never call this code. It's only used to document the *external API*. So, the function could just have `pass`.
* The *path* can contain an <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#key-expression" target="_blank">OpenAPI 3 expression</a> (see more below) where it can use variables with parameters and parts of the original request sent to *your API*.
* The *path* can contain an <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a> (see more below) where it can use variables with parameters and parts of the original request sent to *your API*.
### The callback path expression
The callback *path* can have an <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#key-expression" target="_blank">OpenAPI 3 expression</a> that can contain parts of the original request sent to *your API*.
The callback *path* can have an <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a> that can contain parts of the original request sent to *your API*.
In this case, it's the `str`:
@@ -170,7 +170,7 @@ At this point you have the *callback path operation(s)* needed (the one(s) that
Now use the parameter `callbacks` in *your API's path operation decorator* to pass the attribute `.routes` (that's actually just a `list` of routes/*path operations*) from that callback router:
```Python hl_lines="35"
```Python hl_lines="34"
{!./src/openapi_callbacks/tutorial001.py!}
```
@@ -179,7 +179,7 @@ Now use the parameter `callbacks` in *your API's path operation decorator* to pa
### Check the docs
Now you can start your app with Uvicorn and go to <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
Now you can start your app with Uvicorn and go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
You will see your docs including a "Callback" section for your *path operation* that shows how the *external API* should look like:

View File

@@ -1,9 +1,9 @@
## OpenAPI operationId
!!! danger
!!! warning
If you are not an "expert" in OpenAPI, you probably don't need this.
You can set the OpenAPI `operationId` to be used in your path operation with the parameter `operation_id`.
You can set the OpenAPI `operationId` to be used in your *path operation* with the parameter `operation_id`.
You would have to make sure that it is unique for each operation.
@@ -31,7 +31,7 @@ You should do it after adding all your *path operations*.
## Exclude from OpenAPI
To exclude a path operation from the generated OpenAPI schema (and thus, from the automatic documentation systems), use the parameter `include_in_schema` and set it to `False`;
To exclude a *path operation* from the generated OpenAPI schema (and thus, from the automatic documentation systems), use the parameter `include_in_schema` and set it to `False`;
```Python hl_lines="6"
{!./src/path_operation_advanced_configuration/tutorial003.py!}

View File

@@ -1,4 +1,4 @@
You probably read before that you can set a <a href="https://fastapi.tiangolo.com/tutorial/response-status-code/" target="_blank">default Response Status Code</a>.
You probably read before that you can set a default [Response Status Code](../tutorial/response-status-code.md){.internal-link target=_blank}.
But in some cases you need to return a different status code than the default.

View File

@@ -1,6 +1,6 @@
## Use a `Response` parameter
You can declare a parameter of type `Response` in your *path operation function*, the same way you can declare a `Request` parameter.
You can declare a parameter of type `Response` in your *path operation function*.
And then you can set headers in that *temporal* response object.
@@ -20,7 +20,7 @@ You can also declare the `Response` parameter in dependencies, and set cookies (
You can also create cookies when returning a `Response` directly in your code.
To do that, you can create a response as described in <a href="https://fastapi.tiangolo.com/tutorial/response-directly/" target="_blank">Return a Response directly</a>.
To do that, you can create a response as described in [Return a Response Directly](response-directly.md){.internal-link target=_blank}.
Then set Cookies in it, and then return it:
@@ -29,7 +29,7 @@ Then set Cookies in it, and then return it:
```
!!! tip
Have in mind that if you return a response directly instead of using the `Response` parameter, FastAPI will return it directly.
Have in mind that if you return a response directly instead of using the `Response` parameter, FastAPI will return it directly.
So, you will have to make sure your data is of the correct type. E.g. it is compatible with JSON, if you are returning a `JSONResponse`.
@@ -37,4 +37,4 @@ Then set Cookies in it, and then return it:
### More info
To see all the available parameters and options, check the <a href="https://www.starlette.io/responses/#set-cookie" target="_blank">documentation in Starlette</a>.
To see all the available parameters and options, check the <a href="https://www.starlette.io/responses/#set-cookie" class="external-link" target="_blank">documentation in Starlette</a>.

View File

@@ -1,6 +1,6 @@
When you create a **FastAPI** *path operation* you can normally return any data from it: a `dict`, a `list`, a Pydantic model, a database model, etc.
By default, **FastAPI** would automatically convert that return value to JSON using the <a href="https://fastapi.tiangolo.com/tutorial/encoder/" target="_blank">`jsonable_encoder`</a>.
By default, **FastAPI** would automatically convert that return value to JSON using the `jsonable_encoder` explained in [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}.
Then, behind the scenes, it would put that JSON-compatible data (e.g. a `dict`) inside of a Starlette `JSONResponse` that would be used to send the response to the client.
@@ -10,7 +10,7 @@ It might be useful, for example, to return custom headers or cookies.
## Starlette `Response`
In fact, you can return any <a href="https://www.starlette.io/responses/" target="_blank">Starlette `Response`</a> or any sub-class of it.
In fact, you can return any <a href="https://www.starlette.io/responses/" class="external-link" target="_blank">Starlette `Response`</a> or any sub-class of it.
!!! tip
`JSONResponse` itself is a sub-class of `Response`.
@@ -42,9 +42,9 @@ The example above shows all the parts you need, but it's not very useful yet, as
Now, let's see how you could use that to return a custom response.
Let's say you want to return a response that is not available in the default <a href="https://www.starlette.io/responses/" target="_blank">Starlette `Response`s</a>.
Let's say you want to return a response that is not available in the default <a href="https://www.starlette.io/responses/" class="external-link" target="_blank">Starlette `Response`s</a>.
Let's say that you want to return <a href="https://en.wikipedia.org/wiki/XML" target="_blank">XML</a>.
Let's say that you want to return <a href="https://en.wikipedia.org/wiki/XML" class="external-link" target="_blank">XML</a>.
You could put your XML content in a string, put it in a Starlette Response, and return it:
@@ -56,8 +56,6 @@ You could put your XML content in a string, put it in a Starlette Response, and
When you return a `Response` directly its data is not validated, converted (serialized), nor documented automatically.
But you can still <a href="https://fastapi.tiangolo.com/tutorial/additional-responses/" target="_blank">document it</a>.
But you can still document it as described in [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}.
In the next sections you will see how to use/declare these custom `Response`s while still having automatic data conversion, documentation, etc.
You will also see how to use them to set response Headers and Cookies.
You can see in later sections how to use/declare these custom `Response`s while still having automatic data conversion, documentation, etc.

View File

@@ -1,6 +1,6 @@
## Use a `Response` parameter
You can declare a parameter of type `Response` in your *path operation function* (as you can do for cookies), the same way you can declare a `Request` parameter.
You can declare a parameter of type `Response` in your *path operation function* (as you can do for cookies).
And then you can set headers in that *temporal* response object.
@@ -20,7 +20,7 @@ You can also declare the `Response` parameter in dependencies, and set headers (
You can also add headers when you return a `Response` directly.
Create a response as described in <a href="https://fastapi.tiangolo.com/tutorial/response-directly/" target="_blank">Return a Response directly</a> and pass the headers as an additional parameter:
Create a response as described in [Return a Response Directly](response-directly.md){.internal-link target=_blank} and pass the headers as an additional parameter:
```Python hl_lines="10 11 12"
{!./src/response_headers/tutorial001.py!}
@@ -28,6 +28,6 @@ Create a response as described in <a href="https://fastapi.tiangolo.com/tutorial
## Custom Headers
Have in mind that custom proprietary headers can be added <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" target="_blank">using the 'X-' prefix</a>.
Have in mind that custom proprietary headers can be added <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">using the 'X-' prefix</a>.
But if you have custom headers that you want a client in a browser to be able to see, you need to add them to your <a href="https://fastapi.tiangolo.com/tutorial/cors/" target="_blank">CORS configurations</a>, using the parameter `expose_headers` documented in <a href="https://www.starlette.io/middleware/#corsmiddleware" target="_blank">Starlette's CORS docs</a>.
But if you have custom headers that you want a client in a browser to be able to see, you need to add them to your CORS configurations (read more in [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}), using the parameter `expose_headers` documented in <a href="https://www.starlette.io/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette's CORS docs</a>.

View File

@@ -0,0 +1,105 @@
For the simplest cases, you can use HTTP Basic Auth.
In HTTP Basic Auth, the application expects a header that contains a username and a password.
If it doesn't receive it, it returns an HTTP 401 "Unauthorized" error.
And returns a header `WWW-Authenticate` with a value of `Basic`, and an optional `realm` parameter.
That tells the browser to show the integrated prompt for a username and password.
Then, when you type that username and password, the browser sends them in the header automatically.
## Simple HTTP Basic Auth
* Import `HTTPBasic` and `HTTPBasicCredentials`.
* Create a "`security` scheme" using `HTTPBasic`.
* Use that `security` with a dependency in your *path operation*.
* It returns an object of type `HTTPBasicCredentials`:
* It contains the `username` and `password` sent.
```Python hl_lines="2 6 10"
{!./src/security/tutorial006.py!}
```
When you try to open the URL for the first time (or click the "Execute" button in the docs) the browser will ask you for your username and password:
<img src="/img/tutorial/security/image12.png">
## Check the username
Here's a more complete example.
Use a dependency to check if the username and password are correct.
For this, use the Python standard module <a href="https://docs.python.org/3/library/secrets.html" class="external-link" target="_blank">`secrets`</a> to check the username and password:
```Python hl_lines="1 13 14 15"
{!./src/security/tutorial007.py!}
```
This will ensure that `credentials.username` is `"stanleyjobson"`, and that `credentials.password` is `"swordfish"`. This would be similar to:
```Python
if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"):
# Return some error
...
```
But by using the `secrets.compare_digest()` it will be secure against a type of attacks called "timing attacks".
### Timing Attacks
But what's a "timing attack"?
Let's imagine an attacker is trying to guess the username and password.
And that attacker sends a request with a username `johndoe` and a password `love123`.
Then the Python code in your application would be equivalent to something like:
```Python
if "johndoe" == "stanleyjobson" and "love123" == "swordfish":
...
```
But right at the moment Python compares the first `j` in `johndoe` to the first `s` in `stanleyjobson`, it will return `False`, because it already knows that those two strings are not the same, thinking that "there's no need to waste more computation comparing the rest of the letters". And your application will say "incorrect user or password".
But then the attacker tries with username `stanleyjobsox` and password `love123`.
And your application code does something like:
```Python
if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish":
...
```
Python will have to compare the whole `stanleyjobso` in both `stanleyjobsox` and `stanleyjobson` before realizing that both strings are not the same. So it will take some extra microseconds to reply back "incorrect user or password".
#### The time to answer helps the attacker
At that point, by noticing that the server took some microseconds longer to send the "incorrect user or password" response, the attacker will know that she/he got _something_ right, some of the initial letters were right.
And then she/he can try again knowing that it's probably something more similar to `stanleyjobsox` than to `johndoe`.
#### A "professional" attack
Of course, the attacker would not try all this by hand, she/he would write a program to do it, possibly with thousands or millions of tests per second. And would get just one extra correct letter at a time.
But doing that, in some minutes or hours the attacker would have guessed the correct username and password, with the "help" of our application, just using the time taken to answer.
#### Fix it with `secrets.compare_digest()`
But in our code we are actually using `secrets.compare_digest()`.
In short, it will take the same time to compare `stanleyjobsox` to `stanleyjobson` than it takes to compare `johndoe` to `stanleyjobson`. And the same for the password.
That way, using `secrets.compare_digest()` in your application code, it will be safe against this whole range of security attacks.
### Return the error
After detecting that the credentials are incorrect, return an `HTTPException` with a status code 401 (the same returned when no credentials are provided) and add the header `WWW-Authenticate` to make the browser show the login prompt again:
```Python hl_lines="16 17 18 19 20"
{!./src/security/tutorial007.py!}
```

View File

@@ -0,0 +1,14 @@
## Additional Features
There are some extra features to handle security apart from the ones covered in the [Tutorial - User Guide: Security](../../tutorial/security/){.internal-link target=_blank}.
!!! tip
The next sections are **not necessarily "advanced"**.
And it's possible that for your use case, the solution is in one of them.
## Read the Tutorial first
The next sections assume you already read the main [Tutorial - User Guide: Security](../../tutorial/security/){.internal-link target=_blank}.
They are all based on the same concepts, but allow some extra functionalities.

View File

@@ -29,13 +29,30 @@ The content of each of these strings can have any format, but should not contain
These scopes represent "permissions".
In OpenAPI (e.g. the API docs), you can define "security schemes", the same as you saw in the previous sections.
In OpenAPI (e.g. the API docs), you can define "security schemes".
When one of these security schemes uses OAuth2, you can also declare and use scopes.
Each "scope" is just a string (without spaces).
They are normally used to declare specific security permissions, for example:
* `users:read` or `users:write` are common examples.
* `instagram_basic` is used by Facebook / Instagram.
* `https://www.googleapis.com/auth/drive` is used by Google.
!!! info
In OAuth2 a "scope" is just a string that declares a specific permission required.
It doesn't matter if it has other characters like `:` or if it is a URL.
Those details are implementation specific.
For OAuth2 they are just strings.
## Global view
First, let's quickly see the parts that change from the previous section about OAuth2 and JWT. Now using OAuth2 scopes:
First, let's quickly see the parts that change from the examples in the main **Tutorial - User Guide** for [OAuth2 with Password (and hashing), Bearer with JWT tokens](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. Now using OAuth2 scopes:
```Python hl_lines="2 5 9 13 48 66 107 109 110 111 112 113 114 115 116 117 123 124 125 126 130 131 132 133 134 135 136 141 155"
{!./src/security/tutorial005.py!}
@@ -108,7 +125,7 @@ In this case, it requires the scope `me` (it could require more than one scope).
But by using `Security` instead of `Depends`, **FastAPI** will know that it can declare security scopes, use them internally, and document the API with OpenAPI.
But when you import `Query`, `Path`, `Depends`, `Security` and others from `fastapi`, <a href="https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#recap" target="_blank">those are actually functions that return classes of the same name</a>.
But when you import `Query`, `Path`, `Depends`, `Security` and others from `fastapi`, those are actually functions that return special classes.
## Use `SecurityScopes`
@@ -200,7 +217,7 @@ Here's how the hierarchy of dependencies and scopes looks like:
!!! tip
The important and "magic" thing here is that `get_current_user` will have a different list of `scopes` to check for each *path operation*.
All depending on the `scopes` declared in each *path operation* and each dependency in the dependency tree for that specific path operation.
All depending on the `scopes` declared in each *path operation* and each dependency in the dependency tree for that specific *path operation*.
## More details about `SecurityScopes`
@@ -210,7 +227,7 @@ It will always have the security scopes declared in the current `Security` depen
Because the `SecurityScopes` will have all the scopes declared by dependants, you can use it to verify that a token has the required scopes in a central dependency function, and then declare different scope requirements in different *path operations*.
They will be checked independently for each path operation.
They will be checked independently for each *path operation*.
## Check it
@@ -247,4 +264,4 @@ The most secure is the code flow, but is more complex to implement as it require
## `Security` in decorator `dependencies`
The same way you can define a `list` of <a href="https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/" target="_blank">`Depends` in the decorator's `dependencies` parameter</a>, you could also use `Security` with `scopes` there.
The same way you can define a `list` of `Depends` in the decorator's `dependencies` parameter (as explained in [Dependencies in path operation decorators](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}), you could also use `Security` with `scopes` there.

View File

@@ -0,0 +1,534 @@
!!! warning
If you are just starting, the tutorial [SQL (Relational) Databases](../tutorial/sql-databases.md){.internal-link target=_blank} that uses SQLAlchemy should be enough.
Feel free to skip this.
If you are starting a project from scratch, you are probably better off with SQLAlchemy ORM ([SQL (Relational) Databases](../tutorial/sql-databases.md){.internal-link target=_blank}), or any other async ORM.
If you already have a code base that uses <a href="http://docs.peewee-orm.com/en/latest/" class="external-link" target="_blank">Peewee ORM</a>, you can check here how to use it with **FastAPI**.
!!! warning "Python 3.7+ required"
You will need Python 3.7 or above to safely use Peewee with FastAPI.
## Peewee for async
Peewee was not designed for async frameworks, or with them in mind.
Peewee has some heavy assumptions about its defaults and about how it should be used.
If you are developing an application with an older non-async framework, and can work with all its defaults, **it can be a great tool**.
But if you need to change some of the defaults, support more than one predefined database, work with an async framework (like FastAPI), etc, you will need to add quite some complex extra code to override those defaults.
Nevertheless, it's possible to do it, and here you'll see exactly what code you have to add to be able to use Peewee with FastAPI.
!!! note "Technical Details"
You can read more about Peewee's stand about async in Python <a href="http://docs.peewee-orm.com/en/latest/peewee/database.html#async-with-gevent" class="external-link" target="_blank">in the docs</a>, <a href="https://github.com/coleifer/peewee/issues/263#issuecomment-517347032" class="external-link" target="_blank">an issue</a>, <a href="https://github.com/coleifer/peewee/pull/2072#issuecomment-563215132" class="external-link" target="_blank">a PR</a>.
## The same app
We are going to create the same application as in the SQLAlchemy tutorial ([SQL (Relational) Databases](../tutorial/sql-databases.md){.internal-link target=_blank}).
Most of the code is actually the same.
So, we are going to focus only on the differences.
## File structure
Let's say you have a directory named `my_super_project` that contains a sub-directory called `sql_app` with a structure like this:
```
.
└── sql_app
├── __init__.py
├── crud.py
├── database.py
├── main.py
└── schemas.py
```
This is almost the same structure as we had for the SQLAlchemy tutorial.
Now let's see what each file/module does.
## Create the Peewee parts
Let's refer to the file `sql_app/database.py`.
### The standard Peewee code
Let's first check all the normal Peewee code, create a Peewee database:
```Python hl_lines="3 5 22"
{!./src/sql_databases_peewee/sql_app/database.py!}
```
!!! tip
Have in mind that if you wanted to use a different database, like PostgreSQL, you couldn't just change the string. You would need to use a different Peewee database class.
#### Note
The argument:
```Python
check_same_thread=False
```
is equivalent to the one in the SQLAlchemy tutorial:
```Python
connect_args={"check_same_thread": False}
```
...it is needed only for `SQLite`.
!!! info "Technical Details"
Exactly the same technical details as in [SQL (Relational) Databases](../tutorial/sql-databases.md#note){.internal-link target=_blank} apply.
### Make Peewee async-compatible `PeeweeConnectionState`
The main issue with Peewee and FastAPI is that Peewee relies heavily on <a href="https://docs.python.org/3/library/threading.html#thread-local-data" class="external-link" target="_blank">Python's `threading.local`</a>, and it doesn't have a direct way to override it or let you handle connections/sessions directly (as is done in the SQLAlchemy tutorial).
And `threading.local` is not compatible with the new async features of modern Python.
!!! note "Technical Details"
`threading.local` is used to have a "magic" variable that has a different value for each thread.
This was useful in older frameworks designed to have one single thread per request, no more, no less.
Using this, each request would have its own database connection/session, which is the actual final goal.
But FastAPI, using the new async features, could handle more than one request on the same thread. And at the same time, for a single request, it could run multiple things in different threads (in a threadpool), depending on if you use `async def` or normal `def`. This is what gives all the performance improvements to FastAPI.
But Python 3.7 and above provide a more advanced alternative to `threading.local`, that can also be used in the places where `threading.local` would be used, but is compatible with the new async features.
We are going to use that. It's called <a href="https://docs.python.org/3/library/contextvars.html" class="external-link" target="_blank">`contextvars`</a>.
We are going to override the internal parts of Peewee that use `threading.local` and replace them with `contextvars`, with the corresponding updates.
This might seem a bit complex (and it actually is), you don't really need to completely understand how it works to use it.
We will create a `PeeweeConnectionState`:
```Python hl_lines="10 11 12 13 14 15 16 17 18 19"
{!./src/sql_databases_peewee/sql_app/database.py!}
```
This class inherits from a special internal class used by Peewee.
It has all the logic to make Peewee use `contextvars` instead of `threading.local`.
`contextvars` works a bit differently than `threading.local`. But the rest of Peewee's internal code assumes that this class works with `threading.local`.
So, we need to do some extra tricks to make it work as if it was just using `threading.local`. The `__init__`, `__setattr__`, and `__getattr__` implement all the required tricks for this to be used by Peewee without knowing that it is now compatible with FastAPI.
!!! tip
This will just make Peewee behave correctly when used with FastAPI. Not randomly opening or closing connections that are being used, creating errors, etc.
But it doesn't give Peewee async super-powers. You should still use normal `def` functions and not `async def`.
### Use the custom `PeeweeConnectionState` class
Now, overwrite the `._state` internal attribute in the Peewee database `db` object using the new `PeeweeConnectionState`:
```Python hl_lines="24"
{!./src/sql_databases_peewee/sql_app/database.py!}
```
!!! tip
Make sure you overwrite `db._state` *after* creating `db`.
!!! tip
You would do the same for any other Peewee database, including `PostgresqlDatabase`, `MySQLDatabase`, etc.
## Create the database models
Let's now see the file `sql_app/models.py`.
### Create Peewee models for our data
Now create the Peewee models (classes) for `User` and `Item`.
This is the same you would do if you followed the Peewee tutorial and updated the models to have the same data as in the SQLAlchemy tutorial.
!!! tip
Peewee also uses the term "**model**" to refer to these classes and instances that interact with the database.
But Pydantic also uses the term "**model**" to refer to something different, the data validation, conversion, and documentation classes and instances.
Import `db` from `database` (the file `database.py` from above) and use it here.
```Python hl_lines="3 6 7 8 9 10 11 12 15 16 17 18 19 20 21"
{!./src/sql_databases_peewee/sql_app/models.py!}
```
!!! tip
Peewee creates several magic attributes.
It will automatically add an `id` attribute as an integer to be the primary key.
It will chose the name of the tables based on the class names.
For the `Item`, it will create an attribute `owner_id` with the integer ID of the `User`. But we don't declare it anywhere.
## Create the Pydantic models
Now let's check the file `sql_app/schemas.py`.
!!! tip
To avoid confusion between the Peewee *models* and the Pydantic *models*, we will have the file `models.py` with the Peewee models, and the file `schemas.py` with the Pydantic models.
These Pydantic models define more or less a "schema" (a valid data shape).
So this will help us avoiding confusion while using both.
### Create the Pydantic *models* / schemas
Create all the same Pydantic models as in the SQLAlchemy tutorial:
```Python hl_lines="16 17 18 21 22 25 26 27 28 29 30 34 35 38 39 42 43 44 45 46 47 48"
{!./src/sql_databases_peewee/sql_app/schemas.py!}
```
!!! tip
Here we are creating the models with an `id`.
We didn't explicitly specify an `id` attribute in the Peewee models, but Peewee adds one automatically.
We are also adding the magic `owner_id` attribute to `Item`.
### Create a `PeeweeGetterDict` for the Pydantic *models* / schemas
When you access a relationship in a Peewee object, like in `some_user.items`, Peewee doesn't provide a `list` of `Item`.
It provides a special custom object of class `ModelSelect`.
It's possible to create a `list` of its items with `list(some_user.items)`.
But the object itself is not a `list`. And it's also not an actual Python <a href="https://docs.python.org/3/glossary.html#term-generator" class="external-link" target="_blank">generator</a>. Because of this, Pydantic doesn't know by default how to convert it to a `list` of Pydantic *models* / schemas.
But recent versions of Pydantic allow providing a custom class that inherits from `pydantic.utils.GetterDict`, to provide the functionality used when using the `orm_mode = True` to retrieve the values for ORM model attributes.
We are going to create a custom `PeeweeGetterDict` class and use it in all the same Pydantic *models* / schemas that use `orm_mode`:
```Python hl_lines="3 8 9 10 11 12 13 31 49"
{!./src/sql_databases_peewee/sql_app/schemas.py!}
```
Here we are checking if the attribute that is being accessed (e.g. `.items` in `some_user.items`) is an instance of `peewee.ModelSelect`.
And if that's the case, just return a `list` with it.
And then we use it in the Pydantic *models* / schemas that use `orm_mode = True`, with the configuration variable `getter_dict = PeeweeGetterDict`.
!!! tip
We only need to create one `PeeweeGetterDict` class, and we can use it in all the Pydantic *models* / schemas.
## CRUD utils
Now let's see the file `sql_app/crud.py`.
### Create all the CRUD utils
Create all the same CRUD utils as in the SQLAlchemy tutorial, all the code is very similar:
```Python hl_lines="1 4 5 8 9 12 13 16 17 18 19 20 23 24 27 28 29 30"
{!./src/sql_databases_peewee/sql_app/crud.py!}
```
There are some differences with the code for the SQLAlchemy tutorial.
We don't pass a `db` attribute around. Instead we use the models directly. This is because the `db` object is a global object, that includes all the connection logic. That's why we had to do all the `contextvars` updates above.
Aso, when returning several objects, like in `get_users`, we directly call `list`, like in:
```Python
list(models.User.select())
```
This is for the same reason that we had to create a custom `PeeweeGetterDict`. But by returning something that is already a `list` instead of the `peewee.ModelSelect` the `response_model` in the *path operation* with `List[models.User]` (that we'll see later) will work correctly.
## Main **FastAPI** app
And now in the file `sql_app/main.py` let's integrate and use all the other parts we created before.
### Create the database tables
In a very simplistic way create the database tables:
```Python hl_lines="10 11 12"
{!./src/sql_databases_peewee/sql_app/main.py!}
```
### Create a dependency
Create a dependency that will connect the database right at the beginning of a request and disconnect it at the end:
```Python hl_lines="19 20 21 22 23 24 25"
{!./src/sql_databases_peewee/sql_app/main.py!}
```
Here we have an empty `yield` because we are actually not using the database object directly.
It is connecting to the database and storing the connection data in an internal variable that is independent for each request (using the `contextvars` tricks from above).
And then, in each *path operation function* that needs to access the database we add it as a dependency.
But we are not using the value given by this dependency (it actually doesn't give any value, as it has an empty `yield`). So, we don't add it to the *path operation function* but to the *path operation decorator* in the `dependencies` parameter:
```Python hl_lines="36 44 51 63 69 76"
{!./src/sql_databases_peewee/sql_app/main.py!}
```
### Context Variable Middleware
For all the `contextvars` parts to work, we need to make sure there's a new "context" each time there's a new request, so that we have a specific context variable Peewee can use to save its state (database connection, transactions, etc).
For that, we need to create a middleware.
Right before the request, we are going to reset the database state. We will "set" a value to the context variable and then we will ask the Peewee database state to "reset" (this will create the default values it uses).
And then the rest of the request is processed with that new context variable we just set, all automatically and more or less "magically".
For the **next request**, as we will reset that context variable again in the middleware, that new request will have its own database state (connection, transactions, etc).
```Python hl_lines="28 29 30 31 32 33"
{!./src/sql_databases_peewee/sql_app/main.py!}
```
!!! tip
As FastAPI is an async framework, one request could start being processed, and before finishing, another request could be received and start processing as well, and it all could be processed in the same thread.
But context variables are aware of these async features, so, a Peewee database state set in the middleware will keep its own data throughout the entire request.
And at the same time, the other concurrent request will have its own database state that will be independent for the whole request.
#### Peewee Proxy
If you are using a <a href="http://docs.peewee-orm.com/en/latest/peewee/database.html#dynamically-defining-a-database" class="external-link" target="_blank">Peewee Proxy</a>, the actual database is at `db.obj`.
So, you would reset it with:
```Python hl_lines="3 4"
@app.middleware("http")
async def reset_db_middleware(request: Request, call_next):
database.db.obj._state._state.set(db_state_default.copy())
database.db.obj._state.reset()
response = await call_next(request)
return response
```
### Create your **FastAPI** *path operations*
Now, finally, here's the standard **FastAPI** *path operations* code.
```Python hl_lines="36 37 38 39 40 41 44 45 46 47 50 51 52 53 54 55 56 57 60 61 62 63 64 65 66 69 70 71 72 75 76 77 78 79 80 81 82 83"
{!./src/sql_databases_peewee/sql_app/main.py!}
```
### About `def` vs `async def`
The same as with SQLAlchemy, we are not doing something like:
```Python
user = await models.User.select().first()
```
...but instead we are using:
```Python
user = models.User.select().first()
```
So, again, we should declare the *path operation functions* and the dependency without `async def`, just with a normal `def`, as:
```Python hl_lines="2"
# Something goes here
def read_users(skip: int = 0, limit: int = 100):
# Something goes here
```
## Testing Peewee with async
This example includes an extra *path operation* that simulates a long processing request with `time.sleep(sleep_time)`.
It will have the database connection open at the beginning and will just wait some seconds before replying back. And each new request will wait one second less.
This will easily let you test that your app with Peewee and FastAPI is behaving correctly with all the stuff about threads.
If you want to check how Peewee would break your app if used without modification, go the the `sql_app/database.py` file and comment the line:
```Python
# db._state = PeeweeConnectionState()
```
And in the file `sql_app/main.py` file, comment the middleware:
```Python
# @app.middleware("http")
# async def reset_db_middleware(request: Request, call_next):
# database.db._state._state.set(db_state_default.copy())
# database.db._state.reset()
# response = await call_next(request)
# return response
```
Then run your app with Uvicorn:
```bash
uvicorn sql_app.main:app --reload
```
Open your browser at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> and create a couple of users.
Then open 10 tabs at <a href="http://127.0.0.1:8000/docs#/default/read_slow_users_slowusers__get" class="external-link" target="_blank">http://127.0.0.1:8000/docs#/default/read_slow_users_slowusers__get</a> at the same time.
Go to the *path operation* "Get `/slowusers/`" in all of the tabs. Use the "Try it out" button and execute the request in each tab, one right after the other.
The tabs will wait for a bit and then some of them will show `Internal Server Error`.
### What happens
The first tab will make your app create a connection to the database and wait for some seconds before replying back and closing the connection.
Then, for the request in the next tab, your app will wait for one second less, and so on.
This means that it will end up finishing some of the last tabs' requests than some of the previous ones.
Then one the last requests that wait less seconds will try to open a database connection, but as one of those previous requests for the other tabs will probably be handled in the same thread as the first one, it will have the same database connection that is already open, and Peewee will throw an error and you will see it in the terminal, and the response will have an `Internal Server Error`.
This will probably happen for more than one of those tabs.
If you had multiple clients talking to your app exactly at the same time, this is what could happen.
And as your app starts to handle more and more clients at the same time, the waiting time in a single request needs to be shorter and shorter to trigger the error.
### Fix Peewee with FastAPI
Now go back to the file `sql_app/database.py`, and uncomment the line:
```Python
db._state = PeeweeConnectionState()
```
And in the file `sql_app/main.py` file, uncomment the middleware:
```Python
@app.middleware("http")
async def reset_db_middleware(request: Request, call_next):
database.db._state._state.set(db_state_default.copy())
database.db._state.reset()
response = await call_next(request)
return response
```
Terminate your running app and start it again.
Repeat the same process with the 10 tabs. This time all of them will wait and you will get all the results without errors.
...You fixed it!
## Review all the files
Remember you should have a directory named `my_super_project` (or however you want) that contains a sub-directory called `sql_app`.
`sql_app` should have the following files:
* `sql_app/__init__.py`: is an empty file.
* `sql_app/database.py`:
```Python hl_lines=""
{!./src/sql_databases_peewee/sql_app/database.py!}
```
* `sql_app/models.py`:
```Python hl_lines=""
{!./src/sql_databases_peewee/sql_app/models.py!}
```
* `sql_app/schemas.py`:
```Python hl_lines=""
{!./src/sql_databases_peewee/sql_app/schemas.py!}
```
* `sql_app/crud.py`:
```Python hl_lines=""
{!./src/sql_databases_peewee/sql_app/crud.py!}
```
* `sql_app/main.py`:
```Python hl_lines=""
{!./src/sql_databases_peewee/sql_app/main.py!}
```
## Technical Details
!!! warning
These are very technical details that you probably don't need.
### The problem
Peewee uses <a href="https://docs.python.org/3/library/threading.html#thread-local-data" class="external-link" target="_blank">`threading.local`</a> by default to store it's database "state" data (connection, transactions, etc).
`threading.local` creates a value exclusive to the current thread, but an async framework would run all the "tasks" (e.g. requests) in the same thread, and possibly not in order.
On top of that, an async framework could run some sync code in a threadpool (using `asyncio.run_in_executor`), but belonging to the same "task" (e.g. to the same request).
This means that, with Peewee's current implementation, multiple tasks could be using the same `threading.local` variable and end up sharing the same connection and data, and at the same time, if they execute sync IO-blocking code in a threadpool (as with normal `def` functions in FastAPI, in *path operations* and dependencies), that code won't have access to the database state variables, even while it's part of the same "task" (request) and it should be able to get access to that.
### Context variables
Python 3.7 has <a href="https://docs.python.org/3/library/contextvars.html" class="external-link" target="_blank">`contextvars`</a> that can create a local variable very similar to `threading.local`, but also supporting these async features.
There are several things to have in mind.
The `ContextVar` has to be created at the top of the module, like `some_var = ContextVar("some_var", default="default value")`.
To set a value used in the current "context" (e.g. for the current request) use `some_var.set("new value")`.
To get a value anywhere inside of the context (e.g. in any part handling the current request) use `some_var.get()`.
### Set context variables in middleware
If some part of the async code sets the value with `some_var.set("updated in function")` (e.g. the middleware), the rest of the code in it will see that new value.
And if it calls any other function with `await some_function()` (e.g. `response = await call_next(request)` in our middleware) that internal `some_function()` (or `response = await call_next(request)` in our example) and everything it calls inside, will see that same new value `"updated in function"`.
So, in our case, if we set the Peewee state variable in the middleware and then call `response = await call_next(request)` all the rest of the internal code in our app (that is called by `call_next()`) will see this value we set in the middleware and will be able to reuse it.
But if the value is set in an internal function (e.g. in `get_db()`) that value will be seen only by that internal function and any code it calls, not by the parent function nor by any sibling function. So, we can't set the Peewee database state in `get_db()`, or the *path operation functions* wouldn't see the new Peewee database state for that "context".
### But `get_db` is an async context manager
You might be thinking that `get_db()` is actually not used as a function, it's converted to a context manager.
So the *path operation function* is part of it.
But the code after the `yield`, in the `finally` is not executed in the same "context".
So, if you reset the state in `get_db()`, the *path operation function* would see the database connection set there. But the `finally` block would not see the same context variable value, and so, as the database object would not have the same context variable for its state, it would not have the same connection, so you couldn't close it in the `finally` in `get_db()` after the request is done.
In the middleware we are setting the Peewee state to a context variable that holds a `dict`. So, it's set for every new request.
And as the database state variables are stored inside of that `dict` instead of new context variables, when Peewee sets the new database state (connection, transactions, etc) in any part of the internal code, underneath, all that will be set as keys in that `dict`. But the `dict` would still be the same we set in the middleware. That's what allows the `get_db()` dependency to make Peewee create a new connection (that is stored in that `dict`) and allows the `finally` block to still have access to the same connection.
Because the context variable is set outside all that, in the middleware.
### Connect and disconnect in dependency
Then the next question would be, why not just connect and disconnect the database in the middleware itself, instead of `get_db()`?
First, the middleware has to be `async`, and creating and closing the database connection is potentially blocking, so it could degrade performance.
But more importantly, the middleware returns a `response`, and this `response` is actually an awaitable function that will do all the work in your code, including background tasks.
If you closed the connection in the middleware right before returning the `response`, some of your code would not have the chance to use the database connection set in the context variable.
Because some other code will call that `response` with `await response(...)`. And inside of that `await response(...)` is that, for example, background tasks are run. But if the connection was already closed before `response` is awaited, then it won't be able to access it.

View File

@@ -33,7 +33,6 @@ For these cases, you can declare an `openapi_prefix` parameter in your `FastAPI`
See the section below, about "mounting", for an example.
## Mounting a **FastAPI** application
"Mounting" means adding a complete "independent" application in a specific path, that then takes care of handling all the sub-paths.
@@ -42,7 +41,7 @@ You could want to do this if you have several "independent" applications that yo
### Top-level application
First, create the main, top-level, **FastAPI** application, and its path operations:
First, create the main, top-level, **FastAPI** application, and its *path operations*:
```Python hl_lines="3 6 7 8"
{!./src/sub_applications/tutorial001.py!}
@@ -50,7 +49,7 @@ First, create the main, top-level, **FastAPI** application, and its path operati
### Sub-application
Then, create your sub-application, and its path operations.
Then, create your sub-application, and its *path operations*.
This sub-application is just another standard FastAPI application, but this is the one that will be "mounted".
@@ -78,18 +77,16 @@ Now, run `uvicorn`, if your file is at `main.py`, it would be:
uvicorn main:app --reload
```
And open the docs at <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
And open the docs at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
You will see the automatic API docs for the main app, including only its own paths:
<img src="/img/tutorial/sub-applications/image01.png">
And then, open the docs for the sub-application, at <a href="http://127.0.0.1:8000/subapi/docs" target="_blank">http://127.0.0.1:8000/subapi/docs</a>.
And then, open the docs for the sub-application, at <a href="http://127.0.0.1:8000/subapi/docs" class="external-link" target="_blank">http://127.0.0.1:8000/subapi/docs</a>.
You will see the automatic API docs for the sub-application, including only its own sub-paths, with their correct prefix:
<img src="/img/tutorial/sub-applications/image02.png">
If you try interacting with any of the two user interfaces, they will work, because the browser will be able to talk to the correct path (or sub-path).
If you try interacting with any of the two user interfaces, they will work, because the browser will be able to talk to the correct path (or sub-path).

View File

@@ -64,4 +64,4 @@ And because you are using `StaticFiles`, that CSS file would be served automatic
## More details
For more details, including how to test templates, check <a href="https://www.starlette.io/templates/" target="_blank">Starlette's docs on templates</a>.
For more details, including how to test templates, check <a href="https://www.starlette.io/templates/" class="external-link" target="_blank">Starlette's docs on templates</a>.

View File

@@ -0,0 +1,7 @@
## Testing Events, `startup` and `shutdown`
When you need your event handlers (`startup` and `shutdown`) to run in your tests, you can use the `TestClient` with a `with` statement:
```Python hl_lines="9 10 11 12 20 21 22 23 24"
{!./src/app_testing/tutorial003.py!}
```

View File

@@ -0,0 +1,9 @@
## Testing WebSockets
You can use the same `TestClient` to test WebSockets.
For this, you use the `TestClient` in a `with` statement, connecting to the WebSocket:
```Python hl_lines="27 28 29 30 31"
{!./src/app_testing/tutorial002.py!}
```

View File

@@ -13,7 +13,7 @@ But there are situations where you might need to access the `Request` object dir
## Details about the `Request` object
As **FastAPI** is actually **Starlette** underneath, with a layer of several tools on top, you can use Starlette's <a href="https://www.starlette.io/requests/" target="_blank">`Request`</a> object directly when you need to.
As **FastAPI** is actually **Starlette** underneath, with a layer of several tools on top, you can use Starlette's <a href="https://www.starlette.io/requests/" class="external-link" target="_blank">`Request`</a> object directly when you need to.
It would also mean that if you get data from the `Request` object directly (for example, read the body) it won't be validated, converted or annotated (with OpenAPI, for the automatic documentation) by FastAPI.
@@ -52,4 +52,4 @@ Then declare a *path operation function* parameter with the type being the `Requ
## `Request` documentation
You can read more details about the <a href="https://www.starlette.io/requests/" target="_blank">`Request` object in the official Starlette documentation site</a>.
You can read more details about the <a href="https://www.starlette.io/requests/" class="external-link" target="_blank">`Request` object in the official Starlette documentation site</a>.

View File

@@ -1,5 +1,5 @@
You can use <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" target="_blank">WebSockets</a> with **FastAPI**.
You can use <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" class="external-link" target="_blank">WebSockets</a> with **FastAPI**.
## WebSockets client
@@ -68,18 +68,17 @@ They work the same way as for other FastAPI endpoints/*path operations*:
!!! info
In a WebSocket it doesn't really make sense to raise an `HTTPException`. So it's better to close the WebSocket connection directly.
You can use a closing code from the <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" target="_blank">valid codes defined in the specification</a>.
You can use a closing code from the <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" class="external-link" target="_blank">valid codes defined in the specification</a>.
In the future, there will be a `WebSocketException` that you will be able to `raise` from anywhere, and add exception handlers for it. It depends on the <a href="https://github.com/encode/starlette/pull/527" target="_blank">PR #527</a> in Starlette.
In the future, there will be a `WebSocketException` that you will be able to `raise` from anywhere, and add exception handlers for it. It depends on the <a href="https://github.com/encode/starlette/pull/527" class="external-link" target="_blank">PR #527</a> in Starlette.
## More info
To learn more about the options, check Starlette's documentation for:
* <a href="https://www.starlette.io/applications/" target="_blank">Applications (`websocket_route`)</a>.
* <a href="https://www.starlette.io/websockets/" target="_blank">The `WebSocket` class</a>.
* <a href="https://www.starlette.io/endpoints/#websocketendpoint" target="_blank">Class-based WebSocket handling</a>.
* <a href="https://www.starlette.io/applications/" class="external-link" target="_blank">Applications (`websocket_route`)</a>.
* <a href="https://www.starlette.io/websockets/" class="external-link" target="_blank">The `WebSocket` class</a>.
* <a href="https://www.starlette.io/endpoints/#websocketendpoint" class="external-link" target="_blank">Class-based WebSocket handling</a>.
## Test it
@@ -89,7 +88,7 @@ If your file is named `main.py`, run your application with:
uvicorn main:app --reload
```
Open your browser at <a href="http://127.0.0.1:8000" target="_blank">http://127.0.0.1:8000</a>.
Open your browser at <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
You will see a simple page like:

View File

@@ -12,7 +12,7 @@ But at some point, there was no other option than creating something that provid
## Previous tools
### <a href="https://www.djangoproject.com/" target="_blank">Django</a>
### <a href="https://www.djangoproject.com/" class="external-link" target="_blank">Django</a>
It's the most popular Python framework and is widely trusted. It is used to build systems like Instagram.
@@ -20,7 +20,7 @@ It's relatively tightly coupled with relational databases (like MySQL or Postgre
It was created to generate the HTML in the backend, not to create APIs used by a modern frontend (like React, Vue.js and Angular) or by other systems (like <abbr title="Internet of Things">IoT</abbr> devices) communicating with it.
### <a href="https://www.django-rest-framework.org/" target="_blank">Django REST Framework</a>
### <a href="https://www.django-rest-framework.org/" class="external-link" target="_blank">Django REST Framework</a>
Django REST framework was created to be a flexible toolkit for building Web APIs using Django underneath, to improve its API capabilities.
@@ -35,7 +35,7 @@ It was one of the first examples of **automatic API documentation**, and this wa
!!! check "Inspired **FastAPI** to"
Have an automatic API documentation web user interface.
### <a href="http://flask.pocoo.org/" target="_blank">Flask</a>
### <a href="http://flask.pocoo.org/" class="external-link" target="_blank">Flask</a>
Flask is a "microframework", it doesn't include database integrations nor many of the things that come by default in Django.
@@ -55,7 +55,7 @@ Given the simplicity of Flask, it seemed like a good match for building APIs. Th
Have a simple and easy to use routing system.
### <a href="http://docs.python-requests.org" target="_blank">Requests</a>
### <a href="http://docs.python-requests.org" class="external-link" target="_blank">Requests</a>
**FastAPI** is not actually an alternative to **Requests**. Their scope is very different.
@@ -79,7 +79,7 @@ The way you use it is very simple. For example, to do a `GET` request, you would
response = requests.get("http://example.com/some/url")
```
The FastAPI counterpart API path operation could look like:
The FastAPI counterpart API *path operation* could look like:
```Python hl_lines="1"
@app.get("/some/url")
@@ -95,7 +95,7 @@ See the similarities in `requests.get(...)` and `@app.get(...)`.
* Have sensible defaults, but powerful customizations.
### <a href="https://swagger.io/" target="_blank">Swagger</a> / <a href="https://github.com/OAI/OpenAPI-Specification/" target="_blank">OpenAPI</a>
### <a href="https://swagger.io/" class="external-link" target="_blank">Swagger</a> / <a href="https://github.com/OAI/OpenAPI-Specification/" class="external-link" target="_blank">OpenAPI</a>
The main feature I wanted from Django REST Framework was the automatic API documentation.
@@ -112,8 +112,8 @@ That's why when talking about version 2.0 it's common to say "Swagger", and for
And integrate standards-based user interface tools:
* <a href="https://github.com/swagger-api/swagger-ui" target="_blank">Swagger UI</a>
* <a href="https://github.com/Rebilly/ReDoc" target="_blank">ReDoc</a>
* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>
* <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>
These two were chosen for being fairly popular and stable, but doing a quick search, you could find dozens of additional alternative user interfaces for OpenAPI (that you can use with **FastAPI**).
@@ -121,7 +121,7 @@ That's why when talking about version 2.0 it's common to say "Swagger", and for
There are several Flask REST frameworks, but after investing the time and work into investigating them, I found that many are discontinued or abandoned, with several standing issues that made them unfit.
### <a href="https://marshmallow.readthedocs.io/en/3.0/" target="_blank">Marshmallow</a>
### <a href="https://marshmallow.readthedocs.io/en/3.0/" class="external-link" target="_blank">Marshmallow</a>
One of the main features needed by API systems is data "<abbr title="also called marshalling, conversion">serialization</abbr>" which is taking data from the code (Python) and converting it into something that can be sent through the network. For example, converting an object containing data from a database into a JSON object. Converting `datetime` objects into strings, etc.
@@ -136,7 +136,7 @@ But it was created before there existed Python type hints. So, to define every <
!!! check "Inspired **FastAPI** to"
Use code to define "schemas" that provide data types and validation, automatically.
### <a href="https://webargs.readthedocs.io/en/latest/" target="_blank">Webargs</a>
### <a href="https://webargs.readthedocs.io/en/latest/" class="external-link" target="_blank">Webargs</a>
Another big feature required by APIs is <abbr title="reading and converting to Python data">parsing</abbr> data from incoming requests.
@@ -152,7 +152,7 @@ It's a great tool and I have used it a lot too, before having **FastAPI**.
!!! check "Inspired **FastAPI** to"
Have automatic validation of incoming request data.
### <a href="https://apispec.readthedocs.io/en/stable/" target="_blank">APISpec</a>
### <a href="https://apispec.readthedocs.io/en/stable/" class="external-link" target="_blank">APISpec</a>
Marshmallow and Webargs provide validation, parsing and serialization as plug-ins.
@@ -177,7 +177,7 @@ The editor can't help much with that. And if we modify parameters or Marshmallow
!!! check "Inspired **FastAPI** to"
Support the open standard for APIs, OpenAPI.
### <a href="https://flask-apispec.readthedocs.io/en/latest/" target="_blank">Flask-apispec</a>
### <a href="https://flask-apispec.readthedocs.io/en/latest/" class="external-link" target="_blank">Flask-apispec</a>
It's a Flask plug-in, that ties together Webargs, Marshmallow and APISpec.
@@ -191,11 +191,11 @@ This combination of Flask, Flask-apispec with Marshmallow and Webargs was my fav
Using it led to the creation of several Flask full-stack generators. These are the main stack I (and several external teams) have been using up to now:
* <a href="https://github.com/tiangolo/full-stack" target="_blank">https://github.com/tiangolo/full-stack</a>
* <a href="https://github.com/tiangolo/full-stack-flask-couchbase" target="_blank">https://github.com/tiangolo/full-stack-flask-couchbase</a>
* <a href="https://github.com/tiangolo/full-stack-flask-couchdb" target="_blank">https://github.com/tiangolo/full-stack-flask-couchdb</a>
* <a href="https://github.com/tiangolo/full-stack" class="external-link" target="_blank">https://github.com/tiangolo/full-stack</a>
* <a href="https://github.com/tiangolo/full-stack-flask-couchbase" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-flask-couchbase</a>
* <a href="https://github.com/tiangolo/full-stack-flask-couchdb" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-flask-couchdb</a>
And these same full-stack generators were the base of the <a href="/project-generation/" target="_blank">**FastAPI** project generator</a>.
And these same full-stack generators were the base of the [**FastAPI** Project Generators](project-generation.md){.internal-link target=_blank}.
!!! info
Flask-apispec was created by the same Marshmallow developers.
@@ -203,7 +203,7 @@ And these same full-stack generators were the base of the <a href="/project-gene
!!! check "Inspired **FastAPI** to"
Generate the OpenAPI schema automatically, from the same code that defines serialization and validation.
### <a href="https://nestjs.com/" target="_blank">NestJS</a> (and <a href="https://angular.io/" target="_blank">Angular</a>)
### <a href="https://nestjs.com/" class="external-link" target="_blank">NestJS</a> (and <a href="https://angular.io/" class="external-link" target="_blank">Angular</a>)
This isn't even Python, NestJS is a JavaScript (TypeScript) NodeJS framework inspired by Angular.
@@ -222,21 +222,21 @@ It can't handle nested models very well. So, if the JSON body in the request is
Have a powerful dependency injection system. Find a way to minimize code repetition.
### <a href="https://sanic.readthedocs.io/en/latest/" target="_blank">Sanic</a>
### <a href="https://sanic.readthedocs.io/en/latest/" class="external-link" target="_blank">Sanic</a>
It was one of the first extremely fast Python frameworks based on `asyncio`. It was made to be very similar to Flask.
!!! note "Technical Details"
It used <a href="https://github.com/MagicStack/uvloop" target="_blank">`uvloop`</a> instead of the default Python `asyncio` loop. That's what made it so fast.
It used <a href="https://github.com/MagicStack/uvloop" class="external-link" target="_blank">`uvloop`</a> instead of the default Python `asyncio` loop. That's what made it so fast.
It <a href="https://github.com/huge-success/sanic/issues/761" target="_blank">still doesn't implement the ASGI spec for Python asynchronous web development</a>, but it clearly inspired Uvicorn and Starlette, that are currently faster than Sanic in open benchmarks.
It <a href="https://github.com/huge-success/sanic/issues/761" class="external-link" target="_blank">still doesn't implement the ASGI spec for Python asynchronous web development</a>, but it clearly inspired Uvicorn and Starlette, that are currently faster than Sanic in open benchmarks.
!!! check "Inspired **FastAPI** to"
Find a way to have a crazy performance.
That's why **FastAPI** is based on Starlette, as it is the fastest framework available (tested by third-party benchmarks).
### <a href="https://falconframework.org/" target="_blank">Falcon</a>
### <a href="https://falconframework.org/" class="external-link" target="_blank">Falcon</a>
Falcon is another high performance Python framework, it is designed to be minimal, and work as the foundation of other frameworks like Hug.
@@ -253,7 +253,7 @@ So, data validation, serialization, and documentation, have to be done in code,
Although in FastAPI it's optional, and is used mainly to set headers, cookies, and alternative status codes.
### <a href="https://moltenframework.com/" target="_blank">Molten</a>
### <a href="https://moltenframework.com/" class="external-link" target="_blank">Molten</a>
I discovered Molten in the first stages of building **FastAPI**. And it has quite similar ideas:
@@ -274,7 +274,7 @@ Routes are declared in a single place, using functions declared in other places
This actually inspired updating parts of Pydantic, to support the same validation declaration style (all this functionality is now already available in Pydantic).
### <a href="http://www.hug.rest/" target="_blank">Hug</a>
### <a href="http://www.hug.rest/" class="external-link" target="_blank">Hug</a>
Hug was one of the first frameworks to implement the declaration of API parameter types using Python type hints. This was a great idea that inspired other tools to do the same.
@@ -289,7 +289,7 @@ It has an interesting, uncommon feature: using the same framework, it's possible
As it is based on the previous standard for synchronous Python web frameworks (WSGI), it can't handle Websockets and other things, although it still has high performance too.
!!! info
Hug was created by Timothy Crosley, the same creator of <a href="https://github.com/timothycrosley/isort" target="_blank">`isort`</a>, a great tool to automatically sort imports in Python files.
Hug was created by Timothy Crosley, the same creator of <a href="https://github.com/timothycrosley/isort" class="external-link" target="_blank">`isort`</a>, a great tool to automatically sort imports in Python files.
!!! check "Ideas inspired in **FastAPI**"
Hug inspired parts of APIStar, and was one of the tools I found most promising, alongside APIStar.
@@ -298,7 +298,7 @@ As it is based on the previous standard for synchronous Python web frameworks (W
Hug inspired **FastAPI** to declare a `response` parameter in functions to set headers and cookies.
### <a href="https://github.com/encode/apistar" target="_blank">APIStar</a> (<= 0.5)
### <a href="https://github.com/encode/apistar" class="external-link" target="_blank">APIStar</a> (<= 0.5)
Right before deciding to build **FastAPI** I found **APIStar** server. It had almost everything I was looking for and had a great design.
@@ -342,7 +342,7 @@ Now APIStar is a set of tools to validate OpenAPI specifications, not a web fram
## Used by **FastAPI**
### <a href="https://pydantic-docs.helpmanual.io/" target="_blank">Pydantic</a>
### <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a>
Pydantic is a library to define data validation, serialization and documentation (using JSON Schema) based on Python type hints.
@@ -355,7 +355,7 @@ It is comparable to Marshmallow. Although it's faster than Marshmallow in benchm
**FastAPI** then takes that JSON Schema data and puts it in OpenAPI, apart from all the other things it does.
### <a href="https://www.starlette.io/" target="_blank">Starlette</a>
### <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a>
Starlette is a lightweight <abbr title="The new standard for building asynchronous Python web">ASGI</abbr> framework/toolkit, which is ideal for building high-performance asyncio services.
@@ -395,7 +395,7 @@ That's one of the main things that **FastAPI** adds on top, all based on Python
So, anything that you can do with Starlette, you can do it directly with **FastAPI**, as it is basically Starlette on steroids.
### <a href="https://www.uvicorn.org/" target="_blank">Uvicorn</a>
### <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>
Uvicorn is a lightning-fast ASGI server, built on uvloop and httptools.
@@ -408,8 +408,8 @@ It is the recommended server for Starlette and **FastAPI**.
You can combine it with Gunicorn, to have an asynchronous multi-process server.
Check more details in the <a href="/deployment/" target="_blank">Deployment</a> section.
Check more details in the [Deployment](deployment.md){.internal-link target=_blank} section.
## Benchmarks and speed
To understand, compare, and see the difference between Uvicorn, Starlette and FastAPI, check the section about [Benchmarks](/benchmarks/).
To understand, compare, and see the difference between Uvicorn, Starlette and FastAPI, check the section about [Benchmarks](benchmarks.md){.internal-link target=_blank}.

View File

@@ -1,5 +1,4 @@
Details about the `async def` syntax for path operation functions and some background about asynchronous code, concurrency, and parallelism.
Details about the `async def` syntax for *path operation functions* and some background about asynchronous code, concurrency, and parallelism.
## In a hurry?
@@ -7,12 +6,11 @@ Details about the `async def` syntax for path operation functions and some backg
If you are using third party libraries that tell you to call them with `await`, like:
```Python
results = await some_library()
```
Then, declare your path operation functions with `async def` like:
Then, declare your *path operation functions* with `async def` like:
```Python hl_lines="2"
@app.get('/')
@@ -26,7 +24,7 @@ async def read_results():
---
If you are using a third party library that communicates with something (a database, an API, the file system, etc) and doesn't have support for using `await`, (this is currently the case for most database libraries), then declare your path operation functions as normally, with just `def`, like:
If you are using a third party library that communicates with something (a database, an API, the file system, etc) and doesn't have support for using `await`, (this is currently the case for most database libraries), then declare your *path operation functions* as normally, with just `def`, like:
```Python hl_lines="2"
@app.get('/')
@@ -45,13 +43,12 @@ If you just don't know, use normal `def`.
---
**Note**: you can mix `def` and `async def` in your path operation functions as much as you need and define each one using the best option for you. FastAPI will do the right thing with them.
**Note**: you can mix `def` and `async def` in your *path operation functions* as much as you need and define each one using the best option for you. FastAPI will do the right thing with them.
Anyway, in any of the cases above, FastAPI will still work asynchronously and be extremely fast.
But by following the steps above, it will be able to do some performance optimizations.
## Technical Details
Modern versions of Python have support for **"asynchronous code"** using something called **"coroutines"**, with **`async` and `await`** syntax.
@@ -62,7 +59,6 @@ Let's see that phrase by parts in the sections below, below:
* **`async` and `await`**
* **Coroutines**
## Asynchronous Code
Asynchronous code just means that the language has a way to tell the computer / program that at some point in the code, he will have to wait for *something else* to finish somewhere else. Let's say that *something else* is called "slow-file".
@@ -92,7 +88,6 @@ Instead of that, by being an "asynchronous" system, once finished, the task can
For "synchronous" (contrary to "asynchronous") they commonly also use the term "sequential", because the computer / program follows all the steps in sequence before switching to a different task, even if those steps involve waiting.
### Concurrency and Burgers
This idea of **asynchronous** code described above is also sometimes called **"concurrency"**. It is different from **"parallelism"**.
@@ -103,7 +98,6 @@ But the details between *concurrency* and *parallelism* are quite different.
To see the difference, imagine the following story about burgers:
### Concurrent Burgers
You go with your crush to get fast food, you stand in line while the cashier takes the orders from the people in front of you.
@@ -144,7 +138,6 @@ So you wait for your crush to finish the story (finish the current work / task b
Then you go to the counter, to the initial task that is now finished, pick the burgers, say thanks and take them to the table. That finishes that step / task of interaction with the counter. That in turn, creates a new task, of "eating burgers", but the previous one of "getting burgers" is finished.
### Parallel Burgers
You go with your crush to get parallel fast food.
@@ -195,7 +188,6 @@ And you have to wait in the line for a long time or you lose your turn.
You probably wouldn't want to take your crush with you to do errands at the bank.
### Burger Conclusion
In this scenario of "fast food burgers with your crush", as there is a lot of waiting, it makes a lot more sense to have a concurrent system.
@@ -218,8 +210,7 @@ That kind of asynchronicity is what made NodeJS popular (even though NodeJS is n
And that's the same level of performance</a> you get with **FastAPI**.
And as you can have parallelism and asynchronicity at the same time, you get higher performance than most of the tested NodeJS frameworks and on par with Go, which is a compiled language closer to C <a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" target="_blank">(all thanks to Starlette)</a>.
And as you can have parallelism and asynchronicity at the same time, you get higher performance than most of the tested NodeJS frameworks and on par with Go, which is a compiled language closer to C <a href="https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1" class="external-link" target="_blank">(all thanks to Starlette)</a>.
### Is concurrency better than parallelism?
@@ -258,7 +249,6 @@ For example:
* **Machine Learning**: it normally requires lots of "matrix" and "vector" multiplications. Think of a huge spreadsheet with numbers and multiplying all of them together at the same time.
* **Deep Learning**: this is a sub-field of Machine Learning, so, the same applies. It's just that there is not a single spreadsheet of numbers to multiply, but a huge set of them, and in many cases, you use a special processor to build and / or use those models.
### Concurrency + Parallelism: Web + Machine Learning
With **FastAPI** you can take the advantage of concurrency that is very common for web development (the same main attractive of NodeJS).
@@ -267,8 +257,7 @@ But you can also exploit the benefits of parallelism and multiprocessing (having
That, plus the simple fact that Python is the main language for **Data Science**, Machine Learning and especially Deep Learning, make FastAPI a very good match for Data Science / Machine Learning web APIs and applications (among many others).
To see how to achieve this parallelism in production see the section about [Deployment](deployment.md).
To see how to achieve this parallelism in production see the section about [Deployment](deployment.md){.internal-link target=_blank}.
## `async` and `await`
@@ -310,7 +299,7 @@ burgers = get_burgers(2)
---
So, if you are using a library that tells you that you can call it with `await`, you need to create the path operation functions that uses it with `async def`, like in:
So, if you are using a library that tells you that you can call it with `await`, you need to create the *path operation functions* that uses it with `async def`, like in:
```Python hl_lines="2 3"
@app.get('/burgers')
@@ -327,10 +316,9 @@ But at the same time, functions defined with `async def` have to be "awaited". S
So, about the egg and the chicken, how do you call the first `async` function?
If you are working with **FastAPI** you don't have to worry about that, because that "first" function will be your path operation function, and FastAPI will know how to do the right thing.
But if you want to use `async` / `await` without FastAPI, <a href="https://docs.python.org/3/library/asyncio-task.html#coroutine" target="_blank">check the official Python docs</a>.
If you are working with **FastAPI** you don't have to worry about that, because that "first" function will be your *path operation function*, and FastAPI will know how to do the right thing.
But if you want to use `async` / `await` without FastAPI, <a href="https://docs.python.org/3/library/asyncio-task.html#coroutine" class="external-link" target="_blank">check the official Python docs</a>.
### Other forms of asynchronous code
@@ -342,10 +330,9 @@ This same syntax (or almost identical) was also included recently in modern vers
But before that, handling asynchronous code was quite more complex and difficult.
In previous versions of Python, you could have used threads or <a href="http://www.gevent.org/" target="_blank">Gevent</a>. But the code is way more complex to understand, debug, and think about.
In previous versions of NodeJS / Browser JavaScript, you would have used "callbacks". Which lead to <a href="http://callbackhell.com/" target="_blank">callback hell</a>.
In previous versions of Python, you could have used threads or <a href="http://www.gevent.org/" class="external-link" target="_blank">Gevent</a>. But the code is way more complex to understand, debug, and think about.
In previous versions of NodeJS / Browser JavaScript, you would have used "callbacks". Which lead to <a href="http://callbackhell.com/" class="external-link" target="_blank">callback hell</a>.
## Coroutines
@@ -363,7 +350,6 @@ That should make more sense now.
All that is what powers FastAPI (through Starlette) and what makes it have such an impressive performance.
## Very Technical Details
!!! warning
@@ -379,7 +365,7 @@ When you declare a *path operation function* with normal `def` instead of `async
If you are coming from another async framework that does not work in the way described above and you are used to define trivial compute-only *path operation functions* with plain `def` for a tiny performance gain (about 100 nanoseconds), please note that in **FastAPI** the effect would be quite opposite. In these cases, it's better to use `async def` unless your *path operation functions* use code that performs blocking <abbr title="Input/Output: disk reading or writing, network communications.">IO</abbr>.
Still, in both situations, chances are that **FastAPI** will <a href="https://fastapi.tiangolo.com/#performance" target="_blank">still be faster</a> than (or at least comparable to) your previous framework.
Still, in both situations, chances are that **FastAPI** will [still be faster](/#performance){.internal-link target=_blank} than (or at least comparable to) your previous framework.
### Dependencies

View File

@@ -1,4 +1,4 @@
Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" target="_blank">one of the fastest Python frameworks available</a>, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">one of the fastest Python frameworks available</a>, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
But when checking benchmarks and comparisons you should have the following in mind.

View File

@@ -1,44 +1,80 @@
First, you might want to see the basic ways to <a href="https://fastapi.tiangolo.com/help-fastapi/" target="_blank">help FastAPI and get help</a>.
First, you might want to see the basic ways to [help FastAPI and get help](help-fastapi.md){.internal-link target=_blank}.
## Developing
If you already cloned the repository and you know that you need to deep dive in the code, here are some guidelines to set up your environment.
### Virtual environment with `venv`
### Pipenv
You can create a virtual environment in a directory using Python's `venv` module:
If you are using <a href="https://pipenv.readthedocs.io/en/latest/" target="_blank">Pipenv</a>, you can create a virtual environment and install the packages with:
```bash
pipenv install --dev
```console
$ python -m venv env
```
Then you can activate that virtual environment with:
That will create a directory `./env/` with the Python binaries and then you will be able to install packages for that isolated environment.
```bash
pipenv shell
### Activate the environment
Activate the new environment with:
```console
$ source ./env/bin/activate
```
Or in Windows' PowerShell:
### No Pipenv
```console
$ .\env\Scripts\Activate.ps1
```
If you are not using Pipenv, you can create a virtual environment with your preferred tool, and install the packages listed in the file `Pipfile`.
Or if you use Bash for Windows (e.g. <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
```console
$ source ./env/Scripts/activate
```
To check it worked, use:
```console
$ which pip
some/directory/fastapi/env/bin/pip
```
If it shows the `pip` binary at `env/bin/pip` then it worked. 🎉
Or in Windows PowerShell:
```console
$ Get-Command pip
some/directory/fastapi/env/bin/pip
```
!!! tip
Every time you install a new package with `pip` under that environment, activate the environment again.
This makes sure that if you use a terminal program installed by that package (like `flit`), you use the one from your local environment and not any other that could be installed globally.
### Flit
**FastAPI** uses <a href="https://flit.readthedocs.io/en/latest/index.html" target="_blank">Flit</a> to build, package and publish the project.
**FastAPI** uses <a href="https://flit.readthedocs.io/en/latest/index.html" class="external-link" target="_blank">Flit</a> to build, package and publish the project.
If you installed the development dependencies with one of the methods above, you already have the `flit` command.
After activating the environment as described above, install `flit`:
To install your local version of FastAPI as a package in your local environment, run:
```bash
flit install --symlink
```console
$ pip install flit
```
It will install your local FastAPI in your local environment.
Now re-activate the environment to make sure you are using the `flit` you just installed (and not a global one).
And now use `flit` to install the development dependencies:
```console
$ flit install --deps develop --symlink
```
It will install all the dependencies and your local FastAPI in your local environment.
#### Using your local FastAPI
@@ -48,27 +84,35 @@ And if you update that local FastAPI source code, as it is installed with `--sym
That way, you don't have to "install" your local version to be able to test every change.
### Format
There is a script that you can run that will format and clean all your code:
```bash
bash scripts/lint.sh
```console
$ bash scripts/format.sh
```
It will also auto-sort all your imports.
For it to sort them correctly, you need to have FastAPI installed locally in your environment, with the command in the section above:
```bash
flit install --symlink
```console
$ flit install --symlink
```
### Format imports
### Docs
There is another script that formats all the imports and makes sure you don't have unused imports:
The documentation uses <a href="https://www.mkdocs.org/" target="_blank">MkDocs</a>.
```console
$ bash scripts/format-imports.sh
```
As it runs one command after the other and modifies and reverts many files, it takes a bit longer to run, so it might be easier to use `scripts/format.sh` frequently and `scripts/format-imports.sh` only before committing.
## Docs
The documentation uses <a href="https://www.mkdocs.org/" class="external-link" target="_blank">MkDocs</a>.
All the documentation is in Markdown format in the directory `./docs`.
@@ -80,8 +124,7 @@ In fact, those blocks of code are not written inside the Markdown, they are Pyth
And those Python files are included/injected in the documentation when generating the site.
#### Docs for tests
### Docs for tests
Most of the tests actually run against the example source files in the documentation.
@@ -89,35 +132,44 @@ This helps making sure that:
* The documentation is up to date.
* The documentation examples can be run as is.
* Most of the features are covered by the documentation, ensured by the coverage tests.
* Most of the features are covered by the documentation, ensured by test coverage.
During local development, there is a script that builds the site and checks for any changes, live-reloading:
```bash
bash scripts/docs-live.sh
```console
$ bash scripts/docs-live.sh
```
It will serve the documentation on `http://0.0.0.0:8008`.
That way, you can edit the documentation/source files and see the changes live.
#### Apps and docs at the same time
### Apps and docs at the same time
And if you run the examples with, e.g.:
If you run the examples with, e.g.:
```bash
uvicorn tutorial001:app --reload
```console
$ uvicorn tutorial001:app --reload
```
as Uvicorn by default will use the port `8000`, the documentation on port `8008` won't clash.
### Tests
## Tests
There is a script that you can run locally to test all the code and generate coverage reports in HTML:
```bash
bash scripts/test-cov-html.sh
```console
$ bash scripts/test-cov-html.sh
```
This command generates a directory `./htmlcov/`, if you open the file `./htmlcov/index.html` in your browser, you can explore interactively the regions of code that are covered by the tests, and notice if there is any region missing.
### Tests in your editor
If you want to use the integrated tests in your editor add `./docs/src` to your `PYTHONPATH` variable.
For example, in VS Code you can create a file `.env` with:
```env
PYTHONPATH=./docs/src
```

13
docs/css/custom.css Normal file
View File

@@ -0,0 +1,13 @@
a.external-link::after {
/* \00A0 is a non-breaking space
to make the mark be on the same line as the link
*/
content: "\00A0[↪]";
}
a.internal-link::after {
/* \00A0 is a non-breaking space
to make the mark be on the same line as the link
*/
content: "\00A0↪";
}

View File

@@ -1,4 +1,4 @@
You can use <a href="https://www.docker.com/" target="_blank">**Docker**</a> for deployment. It has several advantages like security, replicability, development simplicity, etc.
You can use <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a> for deployment. It has several advantages like security, replicability, development simplicity, etc.
In this section you'll see instructions and links to guides to know how to:
@@ -11,20 +11,18 @@ In this section you'll see instructions and links to guides to know how to:
You can also easily use **FastAPI** in a standard server directly too (without Docker).
## Docker
If you are using Docker, you can use the official Docker image:
### <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>
### <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>
This image has an "auto-tuning" mechanism included, so that you can just add your code and get very high performance automatically. And without making sacrifices.
But you can still change and update all the configurations with environment variables or configuration files.
!!! tip
To see all the configurations and options, go to the Docker image page: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
To see all the configurations and options, go to the Docker image page: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
### Create a `Dockerfile`
@@ -39,8 +37,7 @@ COPY ./app /app
#### Bigger Applications
If you followed the section about creating <a href="https://fastapi.tiangolo.com/tutorial/bigger-applications/" target="_blank">Bigger Applications with Multiple Files
</a>, your `Dockerfile` might instead look like:
If you followed the section about creating [Bigger Applications with Multiple Files](tutorial/bigger-applications.md){.internal-link target=_blank}, your `Dockerfile` might instead look like:
```Dockerfile
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
@@ -115,10 +112,9 @@ docker run -d --name mycontainer -p 80:80 myimage
Now you have an optimized FastAPI server in a Docker container. Auto-tuned for your current server (and number of CPU cores).
### Check it
You should be able to check it in your Docker container's URL, for example: <a href="http://192.168.99.100/items/5?q=somequery" target="_blank">http://192.168.99.100/items/5?q=somequery</a> or <a href="http://127.0.0.1/items/5?q=somequery" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (or equivalent, using your Docker host).
You should be able to check it in your Docker container's URL, for example: <a href="http://192.168.99.100/items/5?q=somequery" class="external-link" target="_blank">http://192.168.99.100/items/5?q=somequery</a> or <a href="http://127.0.0.1/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (or equivalent, using your Docker host).
You will see something like:
@@ -126,25 +122,22 @@ You will see something like:
{"item_id": 5, "q": "somequery"}
```
### Interactive API docs
Now you can go to <a href="http://192.168.99.100/docs" target="_blank">http://192.168.99.100/docs</a> or <a href="http://127.0.0.1/docs" target="_blank">http://127.0.0.1/docs</a> (or equivalent, using your Docker host).
Now you can go to <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> or <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (or equivalent, using your Docker host).
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" target="_blank">Swagger UI</a>):
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### Alternative API docs
And you can also go to <a href="http://192.168.99.100/redoc" target="_blank">http://192.168.99.100/redoc</a> or <a href="http://127.0.0.1/redoc" target="_blank">http://127.0.0.1/redoc</a> (or equivalent, using your Docker host).
And you can also go to <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> or <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (or equivalent, using your Docker host).
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" target="_blank">ReDoc</a>):
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
## HTTPS
### About HTTPS
@@ -156,7 +149,7 @@ But it is way more complex than that.
!!! tip
If you are in a hurry or don't care, continue with the next section for step by step instructions to set everything up.
To learn the basics of HTTPS, from a consumer perspective, check <a href="https://howhttps.works/" target="_blank">https://howhttps.works/</a>.
To learn the basics of HTTPS, from a consumer perspective, check <a href="https://howhttps.works/" class="external-link" target="_blank">https://howhttps.works/</a>.
Now, from a developer's perspective, here are several things to have in mind while thinking about HTTPS:
@@ -174,15 +167,13 @@ Now, from a developer's perspective, here are several things to have in mind whi
* By default, that would mean that you can only have one HTTPS certificate per IP address.
* No matter how big your server is or how small each application you have on it might be.
* There is a solution to this, however.
* There's an extension to the TLS protocol (the one handling the encryption at the TCP level, before HTTP) called <a href="https://en.wikipedia.org/wiki/Server_Name_Indication" target="_blank"><abbr title="Server Name Indication">SNI</abbr></a>.
* There's an extension to the TLS protocol (the one handling the encryption at the TCP level, before HTTP) called <a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="Server Name Indication">SNI</abbr></a>.
* This SNI extension allows one single server (with a single IP address) to have several HTTPS certificates and serve multiple HTTPS domains/applications.
* For this to work, a single component (program) running on the server, listening on the public IP address, must have all the HTTPS certificates in the server.
* After obtaining a secure connection, the communication protocol is still HTTP.
* The contents are encrypted, even though they are being sent with the HTTP protocol.
It is a common practice to have one program/HTTP server running on the server (the machine, host, etc.) and managing all the HTTPS parts : sending the decrypted HTTP requests to the actual HTTP application running in the same server (the **FastAPI** application, in this case), take the HTTP response from the application, encrypt it using the appropriate certificate and sending it back to the client using HTTPS. This server is often called a <a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" target="_blank">TLS Termination Proxy</a>.
It is a common practice to have one program/HTTP server running on the server (the machine, host, etc.) and managing all the HTTPS parts : sending the decrypted HTTP requests to the actual HTTP application running in the same server (the **FastAPI** application, in this case), take the HTTP response from the application, encrypt it using the appropriate certificate and sending it back to the client using HTTPS. This server is often called a <a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">TLS Termination Proxy</a>.
### Let's Encrypt
@@ -190,7 +181,7 @@ Before Let's Encrypt, these HTTPS certificates were sold by trusted third-partie
The process to acquire one of these certificates used to be cumbersome, require quite some paperwork and the certificates were quite expensive.
But then <a href="https://letsencrypt.org/" target="_blank">Let's Encrypt</a> was created.
But then <a href="https://letsencrypt.org/" class="external-link" target="_blank">Let's Encrypt</a> was created.
It is a project from the Linux Foundation. It provides HTTPS certificates for free. In an automated way. These certificates use all the standard cryptographic security, and are short lived (about 3 months), so the security is actually better because of their reduced lifespan.
@@ -198,10 +189,9 @@ The domains are securely verified and the certificates are generated automatical
The idea is to automate the acquisition and renewal of these certificates, so that you can have secure HTTPS, for free, forever.
### Traefik
<a href="https://traefik.io/" target="_blank">Traefik</a> is a high performance reverse proxy / load balancer. It can do the "TLS Termination Proxy" job (apart from other features).
<a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a> is a high performance reverse proxy / load balancer. It can do the "TLS Termination Proxy" job (apart from other features).
It has integration with Let's Encrypt. So, it can handle all the HTTPS parts, including certificate acquisition and renewal.
@@ -211,7 +201,6 @@ It also has integrations with Docker. So, you can declare your domains in each a
With this information and tools, continue with the next section to combine everything.
## Docker Swarm mode cluster with Traefik and HTTPS
You can have a Docker Swarm mode cluster set up in minutes (about 20 min) with a main Traefik handling HTTPS (including certificate acquisition and renewal).
@@ -220,12 +209,11 @@ By using Docker Swarm mode, you can start with a "cluster" of a single machine (
To set up a Docker Swarm Mode cluster with Traefik and HTTPS handling, follow this guide:
### <a href="https://medium.com/@tiangolo/docker-swarm-mode-and-traefik-for-a-https-cluster-20328dba6232" target="_blank">Docker Swarm Mode and Traefik for an HTTPS cluster</a>.
### <a href="https://medium.com/@tiangolo/docker-swarm-mode-and-traefik-for-a-https-cluster-20328dba6232" class="external-link" target="_blank">Docker Swarm Mode and Traefik for an HTTPS cluster</a>
### Deploy a FastAPI application
The easiest way to set everything up, would be using the <a href="/project-generation/" target="_blank">FastAPI project generator</a>.
The easiest way to set everything up, would be using the [**FastAPI** Project Generators](project-generation.md){.internal-link target=_blank}.
It is designed to be integrated with this Docker Swarm cluster with Traefik and HTTPS described above.
@@ -233,20 +221,19 @@ You can generate a project in about 2 min.
The generated project has instructions to deploy it, doing it takes another 2 min.
## Alternatively, deploy **FastAPI** without Docker
You can deploy **FastAPI** directly without Docker too.
You just need to install an ASGI compatible server like:
* <a href="https://www.uvicorn.org/" target="_blank">Uvicorn</a>, a lightning-fast ASGI server, built on uvloop and httptools.
* <a href="https://www.uvicorn.org/" class="external-link" target="_blank">Uvicorn</a>, a lightning-fast ASGI server, built on uvloop and httptools.
```bash
pip install uvicorn
```
* <a href="https://gitlab.com/pgjones/hypercorn" target="_blank">Hypercorn</a>, an ASGI server also compatible with HTTP/2.
* <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>, an ASGI server also compatible with HTTP/2.
```bash
pip install hypercorn
@@ -268,7 +255,7 @@ hypercorn main:app --bind 0.0.0.0:80
You might want to set up some tooling to make sure it is restarted automatically if it stops.
You might also want to install <a href="https://gunicorn.org/" target="_blank">Gunicorn</a> and <a href="https://www.uvicorn.org/#running-with-gunicorn" target="_blank">use it as a manager for Uvicorn</a>, or use Hypercorn with multiple workers.
You might also want to install <a href="https://gunicorn.org/" class="external-link" target="_blank">Gunicorn</a> and <a href="https://www.uvicorn.org/#running-with-gunicorn" class="external-link" target="_blank">use it as a manager for Uvicorn</a>, or use Hypercorn with multiple workers.
Making sure to fine-tune the number of workers, etc.

View File

@@ -5,66 +5,107 @@ There are many posts, articles, tools, and projects, related to **FastAPI**.
Here's an incomplete list of some of them.
!!! tip
If you have an article, project, tool, or anything related to **FastAPI** that is not yet listed here, create a <a href="https://github.com/tiangolo/fastapi/edit/master/docs/external-links.md" target="_blank">Pull Request adding it</a>.
If you have an article, project, tool, or anything related to **FastAPI** that is not yet listed here, create a <a href="https://github.com/tiangolo/fastapi/edit/master/docs/external-links.md" class="external-link" target="_blank">Pull Request adding it</a>.
## Articles
### English
* <a href="https://medium.com/@williamhayes/fastapi-starlette-debug-vs-prod-5f7561db3a59" target="_blank">FastAPI/Starlette debug vs prod</a> by <a href="https://medium.com/@williamhayes" target="_blank">William Hayes</a>.
* <a href="https://medium.com/@williamhayes/fastapi-starlette-debug-vs-prod-5f7561db3a59" class="external-link" target="_blank">FastAPI/Starlette debug vs prod</a> by <a href="https://medium.com/@williamhayes" class="external-link" target="_blank">William Hayes</a>.
* <a href="https://medium.com/data-rebels/fastapi-google-as-an-external-authentication-provider-3a527672cf33" target="_blank">FastAPIGoogle as an external authentication provider</a> by <a href="https://medium.com/@nils_29588" target="_blank">Nils de Bruin</a>.
* <a href="https://medium.com/data-rebels/fastapi-google-as-an-external-authentication-provider-3a527672cf33" class="external-link" target="_blank">FastAPIGoogle as an external authentication provider</a> by <a href="https://medium.com/@nils_29588" class="external-link" target="_blank">Nils de Bruin</a>.
* <a href="https://medium.com/data-rebels/fastapi-how-to-add-basic-and-cookie-authentication-a45c85ef47d3" target="_blank">FastAPIHow to add basic and cookie authentication</a> by <a href="https://medium.com/@nils_29588" target="_blank">Nils de Bruin</a>.
* <a href="https://medium.com/data-rebels/fastapi-how-to-add-basic-and-cookie-authentication-a45c85ef47d3" class="external-link" target="_blank">FastAPIHow to add basic and cookie authentication</a> by <a href="https://medium.com/@nils_29588" class="external-link" target="_blank">Nils de Bruin</a>.
* <a href="https://dev.to/errietta/introduction-to-the-fastapi-python-framework-2n10" target="_blank">Introduction to the fastapi python framework</a> by <a href="https://dev.to/errietta" target="_blank">Errieta Kostala</a>.
* <a href="https://dev.to/errietta/introduction-to-the-fastapi-python-framework-2n10" class="external-link" target="_blank">Introduction to the fastapi python framework</a> by <a href="https://dev.to/errietta" class="external-link" target="_blank">Errieta Kostala</a>.
* <a href="http://nickc1.github.io/api,/scikit-learn/2019/01/10/scikit-fastapi.html" target="_blank">FastAPI and Scikit-Learn: Easily Deploy Models</a> by <a href="http://nickc1.github.io/" target="_blank">Nick Cortale</a>.
* <a href="http://nickc1.github.io/api,/scikit-learn/2019/01/10/scikit-fastapi.html" class="external-link" target="_blank">FastAPI and Scikit-Learn: Easily Deploy Models</a> by <a href="http://nickc1.github.io/" class="external-link" target="_blank">Nick Cortale</a>.
* <a href="https://medium.com/data-rebels/fastapi-authentication-revisited-enabling-api-key-authentication-122dc5975680" target="_blank">FastAPI authentication revisited: Enabling API key authentication</a> by <a href="https://medium.com/@nils_29588" target="_blank">Nils de Bruin</a>.
* <a href="https://medium.com/data-rebels/fastapi-authentication-revisited-enabling-api-key-authentication-122dc5975680" class="external-link" target="_blank">FastAPI authentication revisited: Enabling API key authentication</a> by <a href="https://medium.com/@nils_29588" class="external-link" target="_blank">Nils de Bruin</a>.
* <a href="https://blog.bartab.fr/fastapi-logging-on-the-fly/" target="_blank">FastAPI, a simple use case on logging</a> by <a href="https://blog.bartab.fr/" target="_blank">@euri10</a>.
* <a href="https://blog.bartab.fr/fastapi-logging-on-the-fly/" class="external-link" target="_blank">FastAPI, a simple use case on logging</a> by <a href="https://blog.bartab.fr/" class="external-link" target="_blank">@euri10</a>.
* <a href="https://medium.com/@nico.axtmann95/deploying-a-scikit-learn-model-with-onnx-und-fastapi-1af398268915" target="_blank">Deploying a scikit-learn model with ONNX and FastAPI</a> by <a href="https://www.linkedin.com/in/nico-axtmann" target="_blank">Nico Axtmann</a>.
* <a href="https://medium.com/@nico.axtmann95/deploying-a-scikit-learn-model-with-onnx-und-fastapi-1af398268915" class="external-link" target="_blank">Deploying a scikit-learn model with ONNX and FastAPI</a> by <a href="https://www.linkedin.com/in/nico-axtmann" class="external-link" target="_blank">Nico Axtmann</a>.
* <a href="https://geekflare.com/python-asynchronous-web-frameworks/" target="_blank">Top 5 Asynchronous Web Frameworks for Python</a> by <a href="https://geekflare.com/author/ankush/" target="_blank">Ankush Thakur</a> on <a href="https://geekflare.com" target="_blank">GeekFlare</a>.
* <a href="https://geekflare.com/python-asynchronous-web-frameworks/" class="external-link" target="_blank">Top 5 Asynchronous Web Frameworks for Python</a> by <a href="https://geekflare.com/author/ankush/" class="external-link" target="_blank">Ankush Thakur</a> on <a href="https://geekflare.com" class="external-link" target="_blank">GeekFlare</a>.
* <a href="https://medium.com/@gntrm/jwt-authentication-with-fastapi-and-aws-cognito-1333f7f2729e" target="_blank">JWT Authentication with FastAPI and AWS Cognito</a> by <a href="https://twitter.com/gntrm" target="_blank">Johannes Gontrum</a>.
* <a href="https://medium.com/@gntrm/jwt-authentication-with-fastapi-and-aws-cognito-1333f7f2729e" class="external-link" target="_blank">JWT Authentication with FastAPI and AWS Cognito</a> by <a href="https://twitter.com/gntrm" class="external-link" target="_blank">Johannes Gontrum</a>.
* <a href="https://towardsdatascience.com/how-to-deploy-a-machine-learning-model-dc51200fe8cf" target="_blank">How to Deploy a Machine Learning Model</a> by <a href="https://www.linkedin.com/in/mgrootendorst/" target="_blank">Maarten Grootendorst</a> on <a href="https://towardsdatascience.com/" target="_blank">Towards Data Science</a>.
* <a href="https://towardsdatascience.com/how-to-deploy-a-machine-learning-model-dc51200fe8cf" class="external-link" target="_blank">How to Deploy a Machine Learning Model</a> by <a href="https://www.linkedin.com/in/mgrootendorst/" class="external-link" target="_blank">Maarten Grootendorst</a> on <a href="https://towardsdatascience.com/" class="external-link" target="_blank">Towards Data Science</a>.
* <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank">Uber: Ludwig v0.2 Adds New Features and Other Improvements to its Deep Learning Toolbox [including a FastAPI server]</a> on <a href="https://eng.uber.com" target="_blank">Uber Engineering</a>.
* [Uber: Ludwig v0.2 Adds New Features and Other Improvements to its Deep Learning Toolbox [including a FastAPI server]](https://eng.uber.com/ludwig-v0-2/){.external-link target=_blank} on <a href="https://eng.uber.com" class="external-link" target="_blank">Uber Engineering</a>.
* <a href="https://gitlab.com/euri10/fastapi_cheatsheet" target="_blank">A FastAPI and Swagger UI visual cheatsheet</a> by <a href="https://gitlab.com/euri10" target="_blank">@euri10</a>
* <a href="https://gitlab.com/euri10/fastapi_cheatsheet" class="external-link" target="_blank">A FastAPI and Swagger UI visual cheatsheet</a> by <a href="https://gitlab.com/euri10" class="external-link" target="_blank">@euri10</a>
* <a href="https://medium.com/@mike.p.moritz/using-docker-compose-to-deploy-a-lightweight-python-rest-api-with-a-job-queue-37e6072a209b" class="external-link" target="_blank">Using Docker Compose to deploy a lightweight Python REST API with a job queue</a> by <a href="https://medium.com/@mike.p.moritz" class="external-link" target="_blank">Mike Moritz</a>.
* <a href="https://robwagner.dev/tortoise-fastapi-setup/" class="external-link" target="_blank">Setting up Tortoise ORM with FastAPI</a> by <a href="https://robwagner.dev/" class="external-link" target="_blank">Rob Wagner</a>.
* <a href="https://dev.to/dbanty/why-i-m-leaving-flask-3ki6" class="external-link" target="_blank">Why I'm Leaving Flask</a> by <a href="https://dev.to/dbanty" class="external-link" target="_blank">Dylan Anthony</a>.
* <a href="https://medium.com/python-data/how-to-deploy-tensorflow-2-0-models-as-an-api-service-with-fastapi-docker-128b177e81f3" class="external-link" target="_blank">How To Deploy Tensorflow 2.0 Models As An API Service With FastAPI & Docker</a> by <a href="https://medium.com/@bbrenyah" class="external-link" target="_blank">Bernard Brenyah</a>.
* <a href="https://testdriven.io/blog/fastapi-crud/" class="external-link" target="_blank">TestDriven.io: Developing and Testing an Asynchronous API with FastAPI and Pytest</a> by <a href="https://testdriven.io/authors/herman/" class="external-link" target="_blank">Michael Herman</a>.
* <a href="https://towardsdatascience.com/deploying-iris-classifications-with-fastapi-and-docker-7c9b83fdec3a" class="external-link" target="_blank">Towards Data Science: Deploying Iris Classifications with FastAPI and Docker</a> by <a href="https://towardsdatascience.com/@mandygu" class="external-link" target="_blank">Mandy Gu</a>.
* <a href="https://medium.com/analytics-vidhya/deploy-machine-learning-models-with-keras-fastapi-redis-and-docker-4940df614ece" class="external-link" target="_blank">Deploy Machine Learning Models with Keras, FastAPI, Redis and Docker</a> by <a href="https://medium.com/@shane.soh" class="external-link" target="_blank">Shane Soh</a>.
* <a href="https://medium.com/@arthur393/another-boilerplate-to-fastapi-azure-pipeline-ci-pytest-3c8d9a4be0bb" class="external-link" target="_blank">Another Boilerplate to FastAPI: Azure Pipeline CI + Pytest</a> by <a href="https://twitter.com/arthurheinrique" class="external-link" target="_blank">Arthur Henrique</a>.
### Japanese
* <a href="https://qiita.com/mtitg/items/47770e9a562dd150631d" target="_blank">FastAPIDB接続してCRUDするPython製APIサーバーを構築</a> by <a href="https://qiita.com/mtitg" target="_blank">@mtitg</a>.
* <a href="https://qiita.com/mtitg/items/47770e9a562dd150631d" class="external-link" target="_blank">FastAPIDB接続してCRUDするPython製APIサーバーを構築</a> by <a href="https://qiita.com/mtitg" class="external-link" target="_blank">@mtitg</a>.
* <a href="https://qiita.com/ryoryomaru/items/59958ed385b3571d50de" target="_blank">python製の最新APIフレームワーク FastAPI を触ってみた</a> by <a href="https://qiita.com/ryoryomaru" target="_blank">@ryoryomaru</a>.
* <a href="https://qiita.com/ryoryomaru/items/59958ed385b3571d50de" class="external-link" target="_blank">python製の最新APIフレームワーク FastAPI を触ってみた</a> by <a href="https://qiita.com/ryoryomaru" class="external-link" target="_blank">@ryoryomaru</a>.
* <a href="https://qiita.com/angel_katayoku/items/0e1f5dbbe62efc612a78" target="_blank">FastAPIでCORSを回避</a> by <a href="https://qiita.com/angel_katayoku" target="_blank">@angel_katayoku</a>.
* <a href="https://qiita.com/angel_katayoku/items/0e1f5dbbe62efc612a78" class="external-link" target="_blank">FastAPIでCORSを回避</a> by <a href="https://qiita.com/angel_katayoku" class="external-link" target="_blank">@angel_katayoku</a>.
* <a href="https://qiita.com/angel_katayoku/items/4fbc1a4e2b33fa2237d2" target="_blank">FastAPIをMySQLと接続してDockerで管理してみる</a> by <a href="https://qiita.com/angel_katayoku" target="_blank">@angel_katayoku</a>.
* <a href="https://qiita.com/angel_katayoku/items/4fbc1a4e2b33fa2237d2" class="external-link" target="_blank">FastAPIをMySQLと接続してDockerで管理してみる</a> by <a href="https://qiita.com/angel_katayoku" class="external-link" target="_blank">@angel_katayoku</a>.
* <a href="https://qiita.com/angel_katayoku/items/8a458a8952f50b73f420" target="_blank">FastAPIでPOSTされたJSONのレスポンスbodyを受け取る</a> by <a href="https://qiita.com/angel_katayoku" target="_blank">@angel_katayoku</a>.
* <a href="https://qiita.com/angel_katayoku/items/8a458a8952f50b73f420" class="external-link" target="_blank">FastAPIでPOSTされたJSONのレスポンスbodyを受け取る</a> by <a href="https://qiita.com/angel_katayoku" class="external-link" target="_blank">@angel_katayoku</a>.
* <a href="https://qiita.com/hikarut/items/b178af2e2440c67c6ac4" target="_blank">フロントエンド開発者向けのDockerによるPython開発環境構築</a> by <a href="https://qiita.com/hikarut" target="_blank">Hikaru Takahashi</a>.
* <a href="https://qiita.com/hikarut/items/b178af2e2440c67c6ac4" class="external-link" target="_blank">フロントエンド開発者向けのDockerによるPython開発環境構築</a> by <a href="https://qiita.com/hikarut" class="external-link" target="_blank">Hikaru Takahashi</a>.
* <a href="https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-environment" class="external-link" target="_blank">【第1回】FastAPIチュートリアル: ToDoアプリを作ってみよう【環境構築編】</a> by <a href="https://rightcode.co.jp/author/jun" class="external-link" target="_blank">ライトコードメディア編集部</a>
* <a href="https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-model-building" class="external-link" target="_blank">【第2回】FastAPIチュートリアル: ToDoアプリを作ってみよう【モデル構築編】</a> by <a href="https://rightcode.co.jp/author/jun" class="external-link" target="_blank">ライトコードメディア編集部</a>
* <a href="https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-authentication-user-registration" class="external-link" target="_blank">【第3回】FastAPIチュートリアル: toDoアプリを作ってみよう【認証・ユーザ登録編】</a> by <a href="https://rightcode.co.jp/author/jun" class="external-link" target="_blank">ライトコードメディア編集部</a>
* <a href="https://rightcode.co.jp/blog/information-technology/fastapi-tutorial-todo-apps-admin-page-improvement" class="external-link" target="_blank">【第4回】FastAPIチュートリアル: toDoアプリを作ってみよう【管理者ページ改良編】</a> by <a href="https://rightcode.co.jp/author/jun" class="external-link" target="_blank">ライトコードメディア編集部</a>
### Chinese
* <a href="https://cloud.tencent.com/developer/article/1431448" target="_blank">使用FastAPI框架快速构建高性能的api服务</a> by <a href="https://cloud.tencent.com/developer/user/5471722" target="_blank">逍遥散人</a>.
* <a href="https://cloud.tencent.com/developer/article/1431448" class="external-link" target="_blank">使用FastAPI框架快速构建高性能的api服务</a> by <a href="https://cloud.tencent.com/developer/user/5471722" class="external-link" target="_blank">逍遥散人</a>.
* <a href="https://wxq0309.github.io/" class="external-link" target="_blank">FastAPI框架中文文档</a> by <a href="https://wxq0309.github.io/" class="external-link" target="_blank">何大仙</a>.
### Vietnamese
* <a href="https://fullstackstation.com/fastapi-trien-khai-bang-docker/" target="_blank">FASTAPI: TRIỂN KHAI BẰNG DOCKER</a> by <a href="https://fullstackstation.com/author/figonking/" target="_blank">Nguyễn Nhân</a>.
* <a href="https://fullstackstation.com/fastapi-trien-khai-bang-docker/" class="external-link" target="_blank">FASTAPI: TRIỂN KHAI BẰNG DOCKER</a> by <a href="https://fullstackstation.com/author/figonking/" class="external-link" target="_blank">Nguyễn Nhân</a>.
### Russian
* <a href="https://habr.com/ru/post/454440/" target="_blank">Мелкая питонячая радость #2: Starlette - Солидная примочка FastAPI</a> by <a href="https://habr.com/ru/users/57uff3r/" target="_blank">Andrey Korchak</a>.
* <a href="https://habr.com/ru/post/454440/" class="external-link" target="_blank">Мелкая питонячая радость #2: Starlette - Солидная примочка FastAPI</a> by <a href="https://habr.com/ru/users/57uff3r/" class="external-link" target="_blank">Andrey Korchak</a>.
* <a href="https://habr.com/ru/post/478620/" target="_blank">Почему Вы должны попробовать FastAPI?</a> by <a href="https://github.com/prostomarkeloff" target="_blank">prostomarkeloff</a>.
* <a href="https://habr.com/ru/post/478620/" class="external-link" target="_blank">Почему Вы должны попробовать FastAPI?</a> by <a href="https://github.com/prostomarkeloff" class="external-link" target="_blank">prostomarkeloff</a>.
### German
* <a href="https://blog.codecentric.de/2019/08/inbetriebnahme-eines-scikit-learn-modells-mit-onnx-und-fastapi/" class="external-link" target="_blank">Inbetriebnahme eines scikit-learn-Modells mit ONNX und FastAPI</a> by <a href="https://twitter.com/_nicoax" class="external-link" target="_blank">Nico Axtmann</a>.
## Podcasts
* <a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">FastAPI on PythonBytes</a> by <a href="https://pythonbytes.fm/" target="_blank">Python Bytes FM</a>.
* <a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" class="external-link" target="_blank">FastAPI on PythonBytes</a> by <a href="https://pythonbytes.fm/" class="external-link" target="_blank">Python Bytes FM</a>.
## Talks
* <a href="https://www.youtube.com/watch?v=3DLwPcrE5mA" class="external-link" target="_blank">PyCon UK 2019: FastAPI from the ground up</a> by <a href="https://twitter.com/chriswithers13" class="external-link" target="_blank">Chris Withers</a>.
## Projects
Latest GitHub projects with the topic `fastapi`:
<div class="github-topic-projects">
</div>

View File

@@ -5,8 +5,8 @@
### Based on open standards
* <a href="https://github.com/OAI/OpenAPI-Specification" target="_blank"><strong>OpenAPI</strong></a> for API creation, including declarations of <abbr title="also known as: endpoints, routes">path</abbr> <abbr title="also known as HTTP methods, as POST, GET, PUT, DELETE">operations</abbr>, parameters, body requests, security, etc.
* Automatic data model documentation with <a href="http://json-schema.org/" target="_blank"><strong>JSON Schema</strong></a> (as OpenAPI itself is based on JSON Schema).
* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> for API creation, including declarations of <abbr title="also known as: endpoints, routes">path</abbr> <abbr title="also known as HTTP methods, as POST, GET, PUT, DELETE">operations</abbr>, parameters, body requests, security, etc.
* Automatic data model documentation with <a href="http://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> (as OpenAPI itself is based on JSON Schema).
* Designed around these standards, after a meticulous study. Instead of an afterthought layer on top.
* This also allows using automatic **client code generation** in many languages.
@@ -14,20 +14,19 @@
Interactive API documentation and exploration web user interfaces. As the framework is based on OpenAPI, there are multiple options, 2 included by default.
* <a href="https://github.com/swagger-api/swagger-ui" target="_blank"><strong>Swagger UI</strong></a>, with interactive exploration, call and test your API directly from the browser.
* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a>, with interactive exploration, call and test your API directly from the browser.
![Swagger UI interaction](img/index/index-03-swagger-02.png)
* Alternative API documentation with <a href="https://github.com/Rebilly/ReDoc" target="_blank"><strong>ReDoc</strong></a>.
* Alternative API documentation with <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank"><strong>ReDoc</strong></a>.
![ReDoc](img/index/index-06-redoc-02.png)
### Just Modern Python
It's all based on standard **Python 3.6 type** declarations (thanks to Pydantic). No new syntax to learn. Just standard modern Python.
If you need a 2 minute refresher of how to use Python types (even if you don't use FastAPI), check the tutorial section: [Python types](python-types.md).
If you need a 2 minute refresher of how to use Python types (even if you don't use FastAPI), check the short tutorial: [Python Types](python-types.md){.internal-link target=_blank}.
You write standard Python with types:
@@ -66,14 +65,14 @@ my_second_user: User = User(**second_user_data)
!!! info
`**second_user_data` means:
Pass the keys and values of the `second_user_data` dict directly as key-value arguments, equivalent to: `User(id=4, name="Mary", joined="2018-11-30")`
### Editor support
All the framework was designed to be easy and intuitive to use, all the decisions where tested on multiple editors even before starting development, to ensure the best development experience.
In the last Python developer survey it was clear <a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" target="_blank">that the most used feature is "autocompletion"</a>.
In the last Python developer survey it was clear <a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank">that the most used feature is "autocompletion"</a>.
The whole **FastAPI** framework is based to satisfy that. Autocompletion works everywhere.
@@ -81,11 +80,11 @@ You will rarely need to come back to the docs.
Here's how your editor might help you:
* in <a href="https://code.visualstudio.com/" target="_blank">Visual Studio Code</a>:
* in <a href="https://code.visualstudio.com/" class="external-link" target="_blank">Visual Studio Code</a>:
![editor support](img/vscode-completion.png)
* in <a href="https://www.jetbrains.com/pycharm/" target="_blank">PyCharm</a>:
* in <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a>:
![editor support](img/pycharm-completion.png)
@@ -122,13 +121,13 @@ Security and authentication integrated. Without any compromise with databases or
All the security schemes defined in OpenAPI, including:
* HTTP Basic.
* **OAuth2** (also with **JWT tokens**). Check the [tutorial on OAuth2 with JWT](tutorial/security/oauth2-jwt.md).
* **OAuth2** (also with **JWT tokens**). Check the tutorial on [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}.
* API keys in:
* Headers.
* Query parameters.
* Cookies, etc.
Plus all the security features from Starlette (including **session cookies**).
Plus all the security features from Starlette (including **session cookies**).
All built as reusable tools and components that are easy to integrate with your systems, data stores, relational and NoSQL databases, etc.
@@ -137,19 +136,17 @@ All built as reusable tools and components that are easy to integrate with your
FastAPI includes an extremely easy to use, but extremely powerful <abbr title='also known as "components", "resources", "services", "providers"'><strong>Dependency Injection</strong></abbr> system.
* Even dependencies can have dependencies, creating a hierarchy or **"graph" of dependencies**.
* All **automatically handled** by the framework.
* All **automatically handled** by the framework.
* All the dependencies can require data from requests and **augment the path operation** constraints and automatic documentation.
* **Automatic validation** even for path operation parameters defined in dependencies.
* **Automatic validation** even for *path operation* parameters defined in dependencies.
* Support for complex user authentication systems, **database connections**, etc.
* **No compromise** with databases, frontends, etc. But easy integration with all of them.
### Unlimited "plug-ins"
Or in other way, no need for them, import and use the code you need.
Any integration is designed to be so simple to use (with dependencies) that you can create a "plug-in" for your application in 2 lines of code using the same structure and syntax used for your path operations.
Or in other way, no need for them, import and use the code you need.
Any integration is designed to be so simple to use (with dependencies) that you can create a "plug-in" for your application in 2 lines of code using the same structure and syntax used for your *path operations*.
### Tested
@@ -159,13 +156,13 @@ Any integration is designed to be so simple to use (with dependencies) that you
## Starlette features
**FastAPI** is fully compatible with (and based on) <a href="https://www.starlette.io/" target="_blank"><strong>Starlette</strong></a>. So, any additional Starlette code you have, will also work.
**FastAPI** is fully compatible with (and based on) <a href="https://www.starlette.io/" class="external-link" target="_blank"><strong>Starlette</strong></a>. So, any additional Starlette code you have, will also work.
`FastAPI` is actually a sub-class of `Starlette`. So, if you already know or use Starlette, most of the functionality will work the same way.
With **FastAPI** you get all of **Starlette**'s features (as FastAPI is just Starlette on steroids):
* Seriously impressive performance. It is <a href="https://github.com/encode/starlette#performance" target="_blank">one of the fastest Python frameworks available, on par with **NodeJS** and **Go**</a>.
* Seriously impressive performance. It is <a href="https://github.com/encode/starlette#performance" class="external-link" target="_blank">one of the fastest Python frameworks available, on par with **NodeJS** and **Go**</a>.
* **WebSocket** support.
* **GraphQL** support.
* In-process background tasks.
@@ -178,7 +175,7 @@ With **FastAPI** you get all of **Starlette**'s features (as FastAPI is just Sta
## Pydantic features
**FastAPI** is fully compatible with (and based on) <a href="https://pydantic-docs.helpmanual.io" target="_blank"><strong>Pydantic</strong></a>. So, any additional Pydantic code you have, will also work.
**FastAPI** is fully compatible with (and based on) <a href="https://pydantic-docs.helpmanual.io" class="external-link" target="_blank"><strong>Pydantic</strong></a>. So, any additional Pydantic code you have, will also work.
Including external libraries also based on Pydantic, as <abbr title="Object-Relational Mapper">ORM</abbr>s, <abbr title="Object-Document Mapper">ODM</abbr>s for databases.
@@ -188,13 +185,13 @@ The same applies the other way around, in many cases you can just pass the objec
With **FastAPI** you get all of **Pydantic**'s features (as FastAPI is based on Pydantic for all the data handling):
* **No brainfuck**:
* **No brainfuck**:
* No new schema definition micro-language to learn.
* If you know Python types you know how to use Pydantic.
* Plays nicely with your **<abbr title="Integrated Development Environment, similar to a code editor">IDE</abbr>/<abbr title="A program that checks for code errors">linter</abbr>/brain**:
* Because pydantic data structures are just instances of classes you define; auto-completion, linting, mypy and your intuition should all work properly with your validated data.
* **Fast**:
* in <a href="https://pydantic-docs.helpmanual.io/#benchmarks-tag" target="_blank">benchmarks</a> Pydantic is faster than all other tested libraries.
* in <a href="https://pydantic-docs.helpmanual.io/#benchmarks-tag" class="external-link" target="_blank">benchmarks</a> Pydantic is faster than all other tested libraries.
* Validate **complex structures**:
* Use of hierarchical Pydantic models, Python `typing`s `List` and `Dict`, etc.
* And validators allow complex data schemas to be clearly and easily defined, checked and documented as JSON Schema.

View File

@@ -8,17 +8,15 @@ There are very simple ways to help (several involve just one or two clicks).
And there are several ways to get help too.
## Star **FastAPI** in GitHub
You can "star" FastAPI in GitHub (clicking the star button at the top right): <a href="https://github.com/tiangolo/fastapi" target="_blank">https://github.com/tiangolo/fastapi</a>.
You can "star" FastAPI in GitHub (clicking the star button at the top right): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>.
By adding a star, other users will be able to find it more easily and see that it has been already useful for others.
## Watch the GitHub repository for releases
You can "watch" FastAPI in GitHub (clicking the "watch" button at the top right): <a href="https://github.com/tiangolo/fastapi" target="_blank">https://github.com/tiangolo/fastapi</a>.
You can "watch" FastAPI in GitHub (clicking the "watch" button at the top right): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>.
There you can select "Releases only".
@@ -30,33 +28,32 @@ Doing it, you will receive notifications (in your email) whenever there's a new
<img src="https://badges.gitter.im/tiangolo/fastapi.svg" alt="Join the chat at https://gitter.im/tiangolo/fastapi">
</a>
Join the chat on Gitter: <a href="https://gitter.im/tiangolo/fastapi" target="_blank">https://gitter.im/tiangolo/fastapi</a>.
Join the chat on Gitter: <a href="https://gitter.im/tiangolo/fastapi" class="external-link" target="_blank">https://gitter.im/tiangolo/fastapi</a>.
There you can ask quick questions, help others, share ideas, etc.
## Connect with the author
You can connect with <a href="https://tiangolo.com" target="_blank">me (Sebastián Ramírez / `tiangolo`)</a>, the author.
You can connect with <a href="https://tiangolo.com" class="external-link" target="_blank">me (Sebastián Ramírez / `tiangolo`)</a>, the author.
You can:
* <a href="https://github.com/tiangolo" target="_blank">Follow me on **GitHub**</a>.
* <a href="https://github.com/tiangolo" class="external-link" target="_blank">Follow me on **GitHub**</a>.
* See other Open Source projects I have created that could help you.
* Follow me to see when I create a new Open Source project.
* <a href="https://twitter.com/tiangolo" target="_blank">Follow me on **Twitter**</a>.
* <a href="https://twitter.com/tiangolo" class="external-link" target="_blank">Follow me on **Twitter**</a>.
* Tell me how you use FastAPI (I love to hear that).
* Ask questions.
* <a href="https://www.linkedin.com/in/tiangolo/" target="_blank">Connect with me on **Linkedin**</a>.
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">Connect with me on **Linkedin**</a>.
* Talk to me.
* Endorse me or recommend me :)
* <a href="https://medium.com/@tiangolo" target="_blank">Read what I write (or follow me) on **Medium**</a>.
* <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">Read what I write (or follow me) on **Medium**</a>.
* Read other ideas, articles and tools I have created.
* Follow me to see when I publish something new.
## Tweet about **FastAPI**
<a href="http://twitter.com/home/?status=I'm loving FastAPI because... https://github.com/tiangolo/fastapi cc @tiangolo" target="_blank">Tweet about **FastAPI**</a> and let me and others why you like it.
<a href="https://twitter.com/compose/tweet?text=I'm loving FastAPI because... https://github.com/tiangolo/fastapi cc @tiangolo" class="external-link" target="_blank">Tweet about **FastAPI**</a> and let me and others know why you like it.
## Let me know how are you using **FastAPI**
@@ -64,22 +61,22 @@ I love to hear about how **FastAPI** is being used, what have you liked in it, i
You can let me know:
* <a href="http://twitter.com/home/?status=Hey @tiangolo, I'm using FastAPI at..." target="_blank">On **Twitter**</a>.
* <a href="https://www.linkedin.com/in/tiangolo/" target="_blank">On **Linkedin**</a>.
* <a href="https://medium.com/@tiangolo" target="_blank">On **Medium**</a>.
* <a href="https://twitter.com/compose/tweet?text=Hey @tiangolo, I'm using FastAPI at..." class="external-link" target="_blank">On **Twitter**</a>.
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">On **Linkedin**</a>.
* <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">On **Medium**</a>.
## Vote for FastAPI
* <a href="https://github.com/vinta/awesome-python/pull/1209" target="_blank">Vote to include **FastAPI** in `awesome-python`</a>.
* <a href="https://www.slant.co/options/34241/~fastapi-review" target="_blank">Vote for **FastAPI** in Slant</a>.
* <a href="https://github.com/vinta/awesome-python/pull/1209" class="external-link" target="_blank">Vote to include **FastAPI** in `awesome-python`</a>.
* <a href="https://www.slant.co/options/34241/~fastapi-review" class="external-link" target="_blank">Vote for **FastAPI** in Slant</a>.
## Help others with issues in GitHub
You can see <a href="https://github.com/tiangolo/fastapi/issues" target="_blank">existing issues</a> and try and help others.
You can see <a href="https://github.com/tiangolo/fastapi/issues" class="external-link" target="_blank">existing issues</a> and try and help others.
## Watch the GitHub repository
You can "watch" FastAPI in GitHub (clicking the "watch" button at the top right): <a href="https://github.com/tiangolo/fastapi" target="_blank">https://github.com/tiangolo/fastapi</a>.
You can "watch" FastAPI in GitHub (clicking the "watch" button at the top right): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>.
If you select "Watching" instead of "Releases only", you will receive notifications when someone creates a new issue.
@@ -87,7 +84,7 @@ Then you can try and help them solving those issues.
## Create issues
You can <a href="https://github.com/tiangolo/fastapi/issues/new/choose" target="_blank">create a new issue</a> in the GitHub repository, for example to:
You can <a href="https://github.com/tiangolo/fastapi/issues/new/choose" class="external-link" target="_blank">create a new issue</a> in the GitHub repository, for example to:
* Report a bug/issue.
* Suggest a new feature.
@@ -95,7 +92,7 @@ You can <a href="https://github.com/tiangolo/fastapi/issues/new/choose" target="
## Create a Pull Request
You can <a href="https://github.com/tiangolo/fastapi" target="_blank">create a Pull Request</a>, for example:
You can <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">create a Pull Request</a>, for example:
* To fix a typo you found on the documentation.
* To propose new documentation sections.

View File

@@ -1,10 +1,9 @@
Some time ago, <a href="https://github.com/tiangolo/fastapi/issues/3#issuecomment-454956920" target="_blank">a **FastAPI** user asked</a>:
Some time ago, <a href="https://github.com/tiangolo/fastapi/issues/3#issuecomment-454956920" class="external-link" target="_blank">a **FastAPI** user asked</a>:
> Whats the history of this project? It seems to have come from nowhere to awesome in a few weeks [...]
Here's a little bit of that history.
## Alternatives
I have been creating APIs with complex requirements for several years (Machine Learning, distributed systems, asynchronous jobs, NoSQL databases, etc), leading several teams of developers.
@@ -13,7 +12,7 @@ As part of that, I needed to investigate, test and use many alternatives.
The history of **FastAPI** is in great part the history of its predecessors.
As said in the section <a href="https://fastapi.tiangolo.com/alternatives/" target="_blank">Alternatives</a>:
As said in the section [Alternatives](alternatives.md){.internal-link target=_blank}:
<blockquote markdown="1">
@@ -27,7 +26,6 @@ But at some point, there was no other option than creating something that provid
</blockquote>
## Investigation
By using all the previous alternatives I had the chance to learn from all of them, take ideas, and combine them in the best way I could find for myself and the teams of developers I have worked with.
@@ -38,14 +36,13 @@ Also, the best approach was to use already existing standards.
So, before even starting to code **FastAPI**, I spent several months studying the specs for OpenAPI, JSON Schema, OAuth2, etc. Understanding their relationship, overlap, and differences.
## Design
Then I spent some time designing the developer "API" I wanted to have as a user (as a developer using FastAPI).
I tested several ideas in the most popular Python editors: PyCharm, VS Code, Jedi based editors.
By the last <a href="https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools" target="_blank">Python Developer Survey</a>, that covers about 80% of the users.
By the last <a href="https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools" class="external-link" target="_blank">Python Developer Survey</a>, that covers about 80% of the users.
It means that **FastAPI** was specifically tested with the editors used by 80% of the Python developers. And as most of the other editors tend to work similarly, all its benefits should work for virtually all editors.
@@ -53,21 +50,18 @@ That way I could find the best ways to reduce code duplication as much as possib
All in a way that provided the best development experience for all the developers.
## Requirements
After testing several alternatives, I decided that I was going to use <a href="https://pydantic-docs.helpmanual.io/" target="_blank">**Pydantic**</a> for its advantages.
After testing several alternatives, I decided that I was going to use <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">**Pydantic**</a> for its advantages.
Then I contributed to it, to make it fully compliant with JSON Schema, to support different ways to define constraint declarations, and to improve editor support (type checks, autocompletion) based on the tests in several editors.
During the development, I also contributed to <a href="https://www.starlette.io/" target="_blank">**Starlette**</a>, the other key requirement.
During the development, I also contributed to <a href="https://www.starlette.io/" class="external-link" target="_blank">**Starlette**</a>, the other key requirement.
## Development
By the time I started creating **FastAPI** itself, most of the pieces were already in place, the design was defined, the requirements and tools were ready, and the knowledge about the standards and specifications was clear and fresh.
## Future
By this point, it's already clear that **FastAPI** with its ideas is being useful for many people.
@@ -80,4 +74,4 @@ But still, there are many improvements and features to come.
**FastAPI** has a great future ahead.
And <a href="https://fastapi.tiangolo.com/help-fastapi/" target="_blank">your help</a> is greatly appreciated.
And [your help](help-fastapi.md){.internal-link target=_blank} is greatly appreciated.

View File

@@ -5,8 +5,8 @@
<em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
</p>
<p align="center">
<a href="https://travis-ci.org/tiangolo/fastapi" target="_blank">
<img src="https://travis-ci.org/tiangolo/fastapi.svg?branch=master" alt="Build Status">
<a href="https://travis-ci.com/tiangolo/fastapi" target="_blank">
<img src="https://travis-ci.com/tiangolo/fastapi.svg?branch=master" alt="Build Status">
</a>
<a href="https://codecov.io/gh/tiangolo/fastapi" target="_blank">
<img src="https://codecov.io/gh/tiangolo/fastapi/branch/master/graph/badge.svg" alt="Coverage">
@@ -39,7 +39,7 @@ The key features are:
* **Easy**: Designed to be easy to use and learn. Less time reading docs.
* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
* **Robust**: Get production-ready code. With automatic interactive documentation.
* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: <a href="https://github.com/OAI/OpenAPI-Specification" target="_blank">OpenAPI</a> (previously known as Swagger) and <a href="http://json-schema.org/" target="_blank">JSON Schema</a>.
* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (previously known as Swagger) and <a href="http://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
<small>* estimation based on tests on an internal development team, building production applications.</small>
@@ -83,9 +83,8 @@ Python 3.6+
FastAPI stands on the shoulders of giants:
* <a href="https://www.starlette.io/" target="_blank">Starlette</a> for the web parts.
* <a href="https://pydantic-docs.helpmanual.io/" target="_blank">Pydantic</a> for the data parts.
* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> for the web parts.
* <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> for the data parts.
## Installation
@@ -93,7 +92,7 @@ FastAPI stands on the shoulders of giants:
pip install fastapi
```
You will also need an ASGI server, for production such as <a href="http://www.uvicorn.org" target="_blank">Uvicorn</a> or <a href="https://gitlab.com/pgjones/hypercorn" target="_blank">Hypercorn</a>.
You will also need an ASGI server, for production such as <a href="http://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> or <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
```bash
pip install uvicorn
@@ -120,6 +119,7 @@ def read_root():
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}
```
<details markdown="1">
<summary>Or use <code>async def</code>...</summary>
@@ -142,7 +142,7 @@ async def read_item(item_id: int, q: str = None):
```
**Note**:
If you don't know, check the _"In a hurry?"_ section about <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">`async` and `await` in the docs</a>.
</details>
@@ -168,7 +168,7 @@ The command `uvicorn main:app` refers to:
### Check it
Open your browser at <a href="http://127.0.0.1:8000/items/5?q=somequery" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
Open your browser at <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
You will see the JSON response as:
@@ -185,18 +185,17 @@ You already created an API that:
### Interactive API docs
Now go to <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" target="_blank">Swagger UI</a>):
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### Alternative API docs
And now, go to <a href="http://127.0.0.1:8000/redoc" target="_blank">http://127.0.0.1:8000/redoc</a>.
And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" target="_blank">ReDoc</a>):
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
@@ -206,8 +205,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
Declare the body using standard Python types, thanks to Pydantic.
```Python hl_lines="2 7 8 9 10 24"
```Python hl_lines="2 7 8 9 10 23 24 25"
from fastapi import FastAPI
from pydantic import BaseModel
@@ -239,7 +237,7 @@ The server should reload automatically (because you added `--reload` to the `uvi
### Interactive API docs upgrade
Now go to <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
* The interactive API documentation will be automatically updated, including the new body:
@@ -253,16 +251,14 @@ Now go to <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)
### Alternative API docs upgrade
And now, go to <a href="http://127.0.0.1:8000/redoc" target="_blank">http://127.0.0.1:8000/redoc</a>.
And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
* The alternative documentation will also reflect the new query parameter and body:
![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
### Recap
In summary, you declare **once** the types of parameters, body, etc. as function parameters.
@@ -332,7 +328,6 @@ Coming back to the previous code example, **FastAPI** will:
* Automatic client code generation systems, for many languages.
* Provide 2 interactive documentation web interfaces directly.
---
We just scratched the surface, but you already get the idea of how it all works.
@@ -359,8 +354,7 @@ Try changing the line with:
![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)
For a more complete example including more features, see the <a href="https://fastapi.tiangolo.com/tutorial/intro/">Tutorial - User Guide</a>.
For a more complete example including more features, see the <a href="https://fastapi.tiangolo.com/tutorial/">Tutorial - User Guide</a>.
**Spoiler alert**: the tutorial - user guide includes:
@@ -377,12 +371,11 @@ For a more complete example including more features, see the <a href="https://fa
* **Cookie Sessions**
* ...and more.
## Performance
Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" target="_blank">one of the fastest Python frameworks available</a>, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">one of the fastest Python frameworks available</a>, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
To understand more about it, see the section <a href="https://fastapi.tiangolo.com/benchmarks/" target="_blank">Benchmarks</a>.
To understand more about it, see the section <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">Benchmarks</a>.
## Optional Dependencies
@@ -391,7 +384,6 @@ Used by Pydantic:
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
Used by Starlette:
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
@@ -399,7 +391,7 @@ Used by Starlette:
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Required for `SchemaGenerator` support.
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI).
* <a href="https://graphene-python.org/" target="_blank"><code>graphene</code></a> - Required for `GraphQLApp` support.
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Required if you want to use `UJSONResponse`.
@@ -407,7 +399,7 @@ Used by FastAPI / Starlette:
* <a href="http://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - for the server that loads and serves your application.
You can install all of these with `pip3 install fastapi[all]`.
You can install all of these with `pip install fastapi[all]`.
## License

39
docs/js/custom.js Normal file
View File

@@ -0,0 +1,39 @@
const div = document.querySelector('.github-topic-projects')
async function getDataBatch(page) {
const response = await fetch(`https://api.github.com/search/repositories?q=topic:fastapi&per_page=100&page=${page}`, { headers: { Accept: 'application/vnd.github.mercy-preview+json' } })
const data = await response.json()
return data
}
async function getData() {
let page = 1
let data = []
let dataBatch = await getDataBatch(page)
data = data.concat(dataBatch.items)
const totalCount = dataBatch.total_count
while (data.length < totalCount) {
page += 1
dataBatch = await getDataBatch(page)
data = data.concat(dataBatch.items)
}
return data
}
async function main() {
if (div) {
data = await getData()
div.innerHTML = '<ul></ul>'
const ul = document.querySelector('.github-topic-projects ul')
data.forEach(v => {
if (v.full_name === 'tiangolo/fastapi') {
return
}
const li = document.createElement('li')
li.innerHTML = `<a href="${v.html_url}" target="_blank">★ ${v.stargazers_count} - ${v.full_name}</a> by <a href="${v.owner.html_url}" target="_blank">@${v.owner.login}</a>`
ul.append(li)
})
}
}
main()

View File

@@ -1,24 +1,23 @@
There is a project generator that you can use to get started, with a lot of the initial set up, security, database and first API endpoints already done for you.
## Full-Stack-FastAPI-PostgreSQL
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" target="_blank">https://github.com/tiangolo/full-stack-fastapi-postgresql</a>
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-postgresql</a>
### Features
### Full-Stack-FastAPI-PostgreSQL Features
* Full **Docker** integration (Docker based).
* Docker Swarm Mode deployment.
* **Docker Compose** integration and optimization for local development
* **Production ready** Python web server using Uvicorn and Gunicorn.
* Python **[FastAPI](https://github.com/tiangolo/fastapi)** backend:
* Python <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">**FastAPI**</a> backend:
* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic).
* **Intuitive**: Great editor support. <abbr title="also known as auto-complete, autocompletion, IntelliSense">Completion</abbr> everywhere. Less time debugging.
* **Easy**: Designed to be easy to use and learn. Less time reading docs.
* **Short**: Minimize code duplication. Multiple features from each parameter declaration.
* **Robust**: Get production-ready code. With automatic interactive documentation.
* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: <a href="https://github.com/OAI/OpenAPI-Specification" target="_blank">OpenAPI</a> and <a href="http://json-schema.org/" target="_blank">JSON Schema</a>.
* [**Many other features**](https://github.com/tiangolo/fastapi) including automatic validation, serialization, interactive documentation, authentication with OAuth2 JWT tokens, etc.
* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> and <a href="http://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
* Many other features including automatic validation, serialization, interactive documentation, authentication with OAuth2 JWT tokens, etc.
* **Secure password** hashing by default.
* **JWT token** authentication.
* **SQLAlchemy** models (independent of Flask extensions, so they can be used with Celery workers directly).
@@ -49,26 +48,24 @@ GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" targ
* Traefik integration, including Let's Encrypt **HTTPS** certificates automatic generation.
* GitLab **CI** (continuous integration), including frontend and backend testing.
## Full-Stack-FastAPI-Couchbase
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-couchbase" target="_blank">https://github.com/tiangolo/full-stack-fastapi-couchbase</a>
GitHub: <a href="https://github.com/tiangolo/full-stack-fastapi-couchbase" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-couchbase</a>
### Features
### Full-Stack-FastAPI-Couchbase Features
* Full **Docker** integration (Docker based).
* Docker Swarm Mode deployment.
* **Docker Compose** integration and optimization for local development.
* **Production ready** Python web server using Uvicorn and Gunicorn.
* Python **[FastAPI](https://github.com/tiangolo/fastapi)** backend:
* Python <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">**FastAPI**</a> backend:
* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic).
* **Intuitive**: Great editor support. <abbr title="also known as auto-complete, autocompletion, IntelliSense">Completion</abbr> everywhere. Less time debugging.
* **Easy**: Designed to be easy to use and learn. Less time reading docs.
* **Short**: Minimize code duplication. Multiple features from each parameter declaration.
* **Robust**: Get production-ready code. With automatic interactive documentation.
* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: <a href="https://github.com/OAI/OpenAPI-Specification" target="_blank">OpenAPI</a> and <a href="http://json-schema.org/" target="_blank">JSON Schema</a>.
* [**Many other features**](https://github.com/tiangolo/fastapi) including automatic validation, serialization, interactive documentation, authentication with OAuth2 JWT tokens, etc.
* **Standards-based**: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> and <a href="http://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
* Many other features including automatic validation, serialization, interactive documentation, authentication with OAuth2 JWT tokens, etc.
* **Secure password** hashing by default.
* **JWT token** authentication.
* **CORS** (Cross Origin Resource Sharing).

View File

@@ -121,7 +121,6 @@ Now you know that you have to fix it, convert `age` to a string with `str(age)`:
{!./src/python_types/tutorial004.py!}
```
## Declaring types
You just saw the main place to declare type hints. As function parameters.
@@ -214,7 +213,6 @@ This means:
* The keys of this `dict` are of type `str` (let's say, the name of each item).
* The values of this `dict` are of type `float` (let's say, the price of each item).
### Classes as types
You can also declare a class as the type of a variable.
@@ -235,10 +233,9 @@ And then, again, you get all the editor support:
<img src="/img/python-types/image06.png">
## Pydantic models
<a href="https://pydantic-docs.helpmanual.io/" target="_blank">Pydantic</a> is a Python library to perform data validation.
<a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> is a Python library to perform data validation.
You declare the "shape" of the data as classes with attributes.
@@ -255,12 +252,11 @@ Taken from the official Pydantic docs:
```
!!! info
To learn more about <a href="https://pydantic-docs.helpmanual.io/" target="_blank">Pydantic, check its docs</a>.
To learn more about <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic, check its docs</a>.
**FastAPI** is all based on Pydantic.
You will see a lot more of all this in practice in the <a href="/tutorial/intro/" target="_blank">Tutorial - User Guide</a> (the next section).
You will see a lot more of all this in practice in the [Tutorial - User Guide](tutorial/){.internal-link target=_blank}.
## Type hints in **FastAPI**
@@ -280,9 +276,9 @@ With **FastAPI** you declare parameters with type hints and you get:
* **Document** the API using OpenAPI:
* which is then used by the automatic interactive documentation user interfaces.
This might all sound abstract. Don't worry. You'll see all this in action in the <a href="/tutorial/intro/" target="_blank">Tutorial - User Guide</a> (the next section).
This might all sound abstract. Don't worry. You'll see all this in action in the [Tutorial - User Guide](tutorial/){.internal-link target=_blank}.
The important thing is that by using standard Python types, in a single place (instead of adding more classes, decorators, etc), **FastAPI** will do a lot of the work for you.
!!! info
If you already went through all the tutorial and came back to see more about types, a good resource is <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" target="_blank">the "cheat sheet" from `mypy`</a>.
If you already went through all the tutorial and came back to see more about types, a good resource is <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">the "cheat sheet" from `mypy`</a>.

View File

@@ -1,5 +1,36 @@
## Latest changes
## 0.47.1
* Fix model filtering in `response_model`, cloning sub-models. PR [#889](https://github.com/tiangolo/fastapi/pull/889).
* Fix FastAPI serialization of Pydantic models using ORM mode blocking the event loop. PR [#888](https://github.com/tiangolo/fastapi/pull/888).
## 0.47.0
* Refactor documentation to make a simpler and shorter [Tutorial - User Guide](https://fastapi.tiangolo.com/tutorial/) and an additional [Advanced User Guide](https://fastapi.tiangolo.com/advanced/) with all the additional docs. PR [#887](https://github.com/tiangolo/fastapi/pull/887).
* Tweak external links, Markdown format, typos. PR [#881](https://github.com/tiangolo/fastapi/pull/881).
* Fix bug in tutorial handling HTTP Basic Auth `username` and `password`. PR [#865](https://github.com/tiangolo/fastapi/pull/865) by [@isaevpd](https://github.com/isaevpd).
* Fix handling form *path operation* parameters declared with pure classes like `list`, `tuple`, etc. PR [#856](https://github.com/tiangolo/fastapi/pull/856) by [@nsidnev](https://github.com/nsidnev).
* Add request `body` to `RequestValidationError`, new docs: [Use the `RequestValidationError` body](https://fastapi.tiangolo.com/tutorial/handling-errors/#use-the-requestvalidationerror-body). Initial PR [#853](https://github.com/tiangolo/fastapi/pull/853) by [@aviramha](https://github.com/aviramha).
* Update [External Links](https://fastapi.tiangolo.com/external-links/) with new links and dynamic GitHub projects with `fastapi` topic. PR [#850](https://github.com/tiangolo/fastapi/pull/850).
* Fix Peewee `contextvars` handling in docs: [SQL (Relational) Databases with Peewee](https://fastapi.tiangolo.com/tutorial/sql-databases-peewee/). PR [#879](https://github.com/tiangolo/fastapi/pull/879).
* Setup development environment with Python's Venv and Flit, instead of requiring the extra Pipenv duplicating dependencies. Updated docs: [Development - Contributing](https://fastapi.tiangolo.com/contributing/). PR [#877](https://github.com/tiangolo/fastapi/pull/877).
* Update docs for [HTTP Basic Auth](https://fastapi.tiangolo.com/tutorial/security/http-basic-auth/) to improve security against timing attacks. Initial PR [#807](https://github.com/tiangolo/fastapi/pull/807) by [@zwass](https://github.com/zwass).
## 0.46.0
* Fix typos and tweak configs. PR [#837](https://github.com/tiangolo/fastapi/pull/837).
* Add link to Chinese article in [External Links](https://fastapi.tiangolo.com/external-links/). PR [810](https://github.com/tiangolo/fastapi/pull/810) by [@wxq0309](https://github.com/wxq0309).
* Implement `OAuth2AuthorizationCodeBearer` class. PR [#797](https://github.com/tiangolo/fastapi/pull/797) by [@kuwv](https://github.com/kuwv).
* Update example upgrade in docs main page. PR [#795](https://github.com/tiangolo/fastapi/pull/795) by [@cdeil](https://github.com/cdeil).
* Fix callback handling for sub-routers. PR [#792](https://github.com/tiangolo/fastapi/pull/792) by [@jekirl](https://github.com/jekirl).
* Fix typos. PR [#784](https://github.com/tiangolo/fastapi/pull/784) by [@kkinder](https://github.com/kkinder).
* Add 4 Japanese articles to [External Links](https://fastapi.tiangolo.com/external-links/). PR [#783](https://github.com/tiangolo/fastapi/pull/783) by [@HymanZHAN](https://github.com/HymanZHAN).
* Add support for subtypes of main types in `jsonable_encoder`, e.g. asyncpg's UUIDs. PR [#756](https://github.com/tiangolo/fastapi/pull/756) by [@RmStorm](https://github.com/RmStorm).
* Fix usage of Pydantic's `HttpUrl` in docs. PR [#832](https://github.com/tiangolo/fastapi/pull/832) by [@Dustyposa](https://github.com/Dustyposa).
* Fix Twitter links in docs. PR [#813](https://github.com/tiangolo/fastapi/pull/813) by [@justindujardin](https://github.com/justindujardin).
* Add docs for correctly [using FastAPI with Peewee ORM](https://fastapi.tiangolo.com/tutorial/sql-databases-peewee/). Including how to overwrite parts of Peewee to correctly handle async threads. PR [#789](https://github.com/tiangolo/fastapi/pull/789).
## 0.45.0
* Add support for OpenAPI Callbacks:
@@ -89,7 +120,7 @@
## 0.39.0
* Allow path parameters to have default values (e.g. `None`) and discard them instead of raising an error.
* This allows declaring a parameter like `user_id: str = None` that can be taken from a query parameter, but the same path operation can be included in a router with a path `/users/{user_id}`, in which case will be taken from the path and will be required.
* This allows declaring a parameter like `user_id: str = None` that can be taken from a query parameter, but the same *path operation* can be included in a router with a path `/users/{user_id}`, in which case will be taken from the path and will be required.
* PR [#464](https://github.com/tiangolo/fastapi/pull/464) by [@jonathanunderwood](https://github.com/jonathanunderwood).
* Add support for setting a `default_response_class` in the `FastAPI` instance or in `include_router`. Initial PR [#467](https://github.com/tiangolo/fastapi/pull/467) by [@toppk](https://github.com/toppk).
* Add support for type annotations using strings and `from __future__ import annotations`. PR [#451](https://github.com/tiangolo/fastapi/pull/451) by [@dmontagu](https://github.com/dmontagu).
@@ -400,7 +431,7 @@
## 0.19.0
* Rename _path operation decorator_ parameter `content_type` to `response_class`. PR [#183](https://github.com/tiangolo/fastapi/pull/183).
* Rename *path operation decorator* parameter `content_type` to `response_class`. PR [#183](https://github.com/tiangolo/fastapi/pull/183).
* Add docs:
* How to use the `jsonable_encoder` in [JSON compatible encoder](https://fastapi.tiangolo.com/tutorial/encoder/).
@@ -428,7 +459,7 @@
## 0.16.0
* Upgrade _path operation_ `doctsring` parsing to support proper Markdown descriptions. New documentation at [Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#description-from-docstring). PR [#163](https://github.com/tiangolo/fastapi/pull/163).
* Upgrade *path operation* `doctsring` parsing to support proper Markdown descriptions. New documentation at [Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#description-from-docstring). PR [#163](https://github.com/tiangolo/fastapi/pull/163).
* Refactor internal usage of Pydantic to use correct data types. PR [#164](https://github.com/tiangolo/fastapi/pull/164).
@@ -446,11 +477,11 @@
## 0.14.0
* Improve automatically generated names of path operations in OpenAPI (in API docs). A function `read_items` instead of having a generated name "Read Items Get" will have "Read Items". PR [#155](https://github.com/tiangolo/fastapi/pull/155).
* Improve automatically generated names of *path operations* in OpenAPI (in API docs). A function `read_items` instead of having a generated name "Read Items Get" will have "Read Items". PR [#155](https://github.com/tiangolo/fastapi/pull/155).
* Add docs for: [Testing **FastAPI**](https://fastapi.tiangolo.com/tutorial/testing/). PR [#151](https://github.com/tiangolo/fastapi/pull/151).
* Update `/docs` Swagger UI to enable deep linking. This allows sharing the URL pointing directly to the path operation documentation in the docs. PR [#148](https://github.com/tiangolo/fastapi/pull/148) by [@wshayes](https://github.com/wshayes).
* Update `/docs` Swagger UI to enable deep linking. This allows sharing the URL pointing directly to the *path operation* documentation in the docs. PR [#148](https://github.com/tiangolo/fastapi/pull/148) by [@wshayes](https://github.com/wshayes).
* Update development dependencies, `Pipfile.lock`. PR [#150](https://github.com/tiangolo/fastapi/pull/150).
@@ -476,7 +507,7 @@
## 0.12.0
* Add additional `responses` parameter to _path operation decorators_ to extend responses in OpenAPI (and API docs).
* Add additional `responses` parameter to *path operation decorators* to extend responses in OpenAPI (and API docs).
* It also allows extending existing responses generated from `response_model`, declare other media types (like images), etc.
* The new documentation is here: [Additional Responses](https://fastapi.tiangolo.com/tutorial/additional-responses/).
* `responses` can also be added to `.include_router()`, the updated docs are here: [Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#add-some-custom-tags-and-responses).
@@ -519,7 +550,7 @@
## 0.10.0
* Add support for Background Tasks in _path operation functions_ and dependencies. New documentation about [Background Tasks is here](https://fastapi.tiangolo.com/tutorial/background-tasks/). PR [#103](https://github.com/tiangolo/fastapi/pull/103).
* Add support for Background Tasks in *path operation functions* and dependencies. New documentation about [Background Tasks is here](https://fastapi.tiangolo.com/tutorial/background-tasks/). PR [#103](https://github.com/tiangolo/fastapi/pull/103).
* Add support for `.websocket_route()` in `APIRouter`. PR [#100](https://github.com/tiangolo/fastapi/pull/100) by [@euri10](https://github.com/euri10).

View File

@@ -1,13 +1,13 @@
from typing import Set
from fastapi import FastAPI
from pydantic import BaseModel, UrlStr
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: UrlStr
url: HttpUrl
name: str

View File

@@ -1,13 +1,13 @@
from typing import List, Set
from fastapi import FastAPI
from pydantic import BaseModel, UrlStr
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: UrlStr
url: HttpUrl
name: str

View File

@@ -1,13 +1,13 @@
from typing import List, Set
from fastapi import FastAPI
from pydantic import BaseModel, UrlStr
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: UrlStr
url: HttpUrl
name: str

View File

@@ -1,13 +1,13 @@
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel, UrlStr
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: UrlStr
url: HttpUrl
name: str

View File

@@ -1,28 +1,27 @@
from fastapi import FastAPI, HTTPException
from fastapi.exception_handlers import (
http_exception_handler,
request_validation_exception_handler,
)
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException
from pydantic import BaseModel
from starlette import status
from starlette.requests import Request
from starlette.responses import JSONResponse
app = FastAPI()
@app.exception_handler(StarletteHTTPException)
async def custom_http_exception_handler(request, exc):
print(f"OMG! An HTTP error!: {exc}")
return await http_exception_handler(request, exc)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
print(f"OMG! The client sent invalid data!: {exc}")
return await request_validation_exception_handler(request, exc)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content=jsonable_encoder({"detail": exc.errors(), "body": exc.body}),
)
@app.get("/items/{item_id}")
async def read_item(item_id: int):
if item_id == 3:
raise HTTPException(status_code=418, detail="Nope! I don't like 3.")
return {"item_id": item_id}
class Item(BaseModel):
title: str
size: int
@app.post("/items/")
async def create_item(item: Item):
return item

View File

@@ -0,0 +1,28 @@
from fastapi import FastAPI, HTTPException
from fastapi.exception_handlers import (
http_exception_handler,
request_validation_exception_handler,
)
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException
app = FastAPI()
@app.exception_handler(StarletteHTTPException)
async def custom_http_exception_handler(request, exc):
print(f"OMG! An HTTP error!: {exc}")
return await http_exception_handler(request, exc)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
print(f"OMG! The client sent invalid data!: {exc}")
return await request_validation_exception_handler(request, exc)
@app.get("/items/{item_id}")
async def read_item(item_id: int):
if item_id == 3:
raise HTTPException(status_code=418, detail="Nope! I don't like 3.")
return {"item_id": item_id}

View File

@@ -25,8 +25,7 @@ invoices_callback_router = APIRouter(default_response_class=JSONResponse)
@invoices_callback_router.post(
"{$callback_url}/invoices/{$request.body.id}",
response_model=InvoiceEventReceived,
"{$callback_url}/invoices/{$request.body.id}", response_model=InvoiceEventReceived,
)
def invoice_notification(body: InvoiceEvent):
pass

View File

@@ -1,3 +1,5 @@
import secrets
from fastapi import Depends, FastAPI, HTTPException
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from starlette.status import HTTP_401_UNAUTHORIZED
@@ -8,7 +10,9 @@ security = HTTPBasic()
def get_current_username(credentials: HTTPBasicCredentials = Depends(security)):
if credentials.username != "foo" or credentials.password != "password":
correct_username = secrets.compare_digest(credentials.username, "stanleyjobson")
correct_password = secrets.compare_digest(credentials.password, "swordfish")
if not (correct_username and correct_password):
raise HTTPException(
status_code=HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password",

View File

View File

View File

@@ -0,0 +1,30 @@
from . import models, schemas
def get_user(user_id: int):
return models.User.filter(models.User.id == user_id).first()
def get_user_by_email(email: str):
return models.User.filter(models.User.email == email).first()
def get_users(skip: int = 0, limit: int = 100):
return list(models.User.select().offset(skip).limit(limit))
def create_user(user: schemas.UserCreate):
fake_hashed_password = user.password + "notreallyhashed"
db_user = models.User(email=user.email, hashed_password=fake_hashed_password)
db_user.save()
return db_user
def get_items(skip: int = 0, limit: int = 100):
return list(models.Item.select().offset(skip).limit(limit))
def create_user_item(item: schemas.ItemCreate, user_id: int):
db_item = models.Item(**item.dict(), owner_id=user_id)
db_item.save()
return db_item

View File

@@ -0,0 +1,24 @@
from contextvars import ContextVar
import peewee
DATABASE_NAME = "test.db"
db_state_default = {"closed": None, "conn": None, "ctx": None, "transactions": None}
db_state = ContextVar("db_state", default=db_state_default.copy())
class PeeweeConnectionState(peewee._ConnectionState):
def __init__(self, **kwargs):
super().__setattr__("_state", db_state)
super().__init__(**kwargs)
def __setattr__(self, name, value):
self._state.get()[name] = value
def __getattr__(self, name):
return self._state.get()[name]
db = peewee.SqliteDatabase(DATABASE_NAME, check_same_thread=False)
db._state = PeeweeConnectionState()

View File

@@ -0,0 +1,83 @@
import time
from typing import List
from fastapi import Depends, FastAPI, HTTPException
from starlette.requests import Request
from . import crud, database, models, schemas
from .database import db_state_default
database.db.connect()
database.db.create_tables([models.User, models.Item])
database.db.close()
app = FastAPI()
sleep_time = 10
def get_db():
try:
database.db.connect()
yield
finally:
if not database.db.is_closed():
database.db.close()
@app.middleware("http")
async def reset_db_middleware(request: Request, call_next):
database.db._state._state.set(db_state_default.copy())
database.db._state.reset()
response = await call_next(request)
return response
@app.post("/users/", response_model=schemas.User, dependencies=[Depends(get_db)])
def create_user(user: schemas.UserCreate):
db_user = crud.get_user_by_email(email=user.email)
if db_user:
raise HTTPException(status_code=400, detail="Email already registered")
return crud.create_user(user=user)
@app.get("/users/", response_model=List[schemas.User], dependencies=[Depends(get_db)])
def read_users(skip: int = 0, limit: int = 100):
users = crud.get_users(skip=skip, limit=limit)
return users
@app.get(
"/users/{user_id}", response_model=schemas.User, dependencies=[Depends(get_db)]
)
def read_user(user_id: int):
db_user = crud.get_user(user_id=user_id)
if db_user is None:
raise HTTPException(status_code=404, detail="User not found")
return db_user
@app.post(
"/users/{user_id}/items/",
response_model=schemas.Item,
dependencies=[Depends(get_db)],
)
def create_item_for_user(user_id: int, item: schemas.ItemCreate):
return crud.create_user_item(item=item, user_id=user_id)
@app.get("/items/", response_model=List[schemas.Item], dependencies=[Depends(get_db)])
def read_items(skip: int = 0, limit: int = 100):
items = crud.get_items(skip=skip, limit=limit)
return items
@app.get(
"/slowusers/", response_model=List[schemas.User], dependencies=[Depends(get_db)]
)
def read_slow_users(skip: int = 0, limit: int = 100):
global sleep_time
sleep_time = max(0, sleep_time - 1)
time.sleep(sleep_time) # Fake long processing request
users = crud.get_users(skip=skip, limit=limit)
return users

View File

@@ -0,0 +1,21 @@
import peewee
from .database import db
class User(peewee.Model):
email = peewee.CharField(unique=True, index=True)
hashed_password = peewee.CharField()
is_active = peewee.BooleanField(default=True)
class Meta:
database = db
class Item(peewee.Model):
title = peewee.CharField(index=True)
description = peewee.CharField(index=True)
owner = peewee.ForeignKeyField(User, backref="items")
class Meta:
database = db

View File

@@ -0,0 +1,49 @@
from typing import Any, List
import peewee
from pydantic import BaseModel
from pydantic.utils import GetterDict
class PeeweeGetterDict(GetterDict):
def get(self, key: Any, default: Any = None):
res = getattr(self._obj, key, default)
if isinstance(res, peewee.ModelSelect):
return list(res)
return res
class ItemBase(BaseModel):
title: str
description: str = None
class ItemCreate(ItemBase):
pass
class Item(ItemBase):
id: int
owner_id: int
class Config:
orm_mode = True
getter_dict = PeeweeGetterDict
class UserBase(BaseModel):
email: str
class UserCreate(UserBase):
password: str
class User(UserBase):
id: int
is_active: bool
items: List[Item] = []
class Config:
orm_mode = True
getter_dict = PeeweeGetterDict

View File

@@ -19,10 +19,6 @@ First, import `BackgroundTasks` and define a parameter in your *path operation f
**FastAPI** will create the object of type `BackgroundTasks` for you and pass it as that parameter.
!!! tip
You declare a parameter of `BackgroundTasks` and use it in a very similar way as to when <a href="/tutorial/using-request-directly/" target="_blank">using the `Request` directly</a>.
## Create a task function
Create a function to be run as the background task.
@@ -31,7 +27,7 @@ It is just a standard function that can receive parameters.
It can be an `async def` or normal `def` function, **FastAPI** will know how to handle it correctly.
In this case, the task function will write to a file (simulating sending an email).
In this case, the task function will write to a file (simulating sending an email).
And as the write operation doesn't use `async` and `await`, we define the function with normal `def`:
@@ -71,7 +67,7 @@ And then another background task generated at the *path operation function* will
## Technical Details
The class `BackgroundTasks` comes directly from <a href="https://www.starlette.io/background/" target="_blank">`starlette.background`</a>.
The class `BackgroundTasks` comes directly from <a href="https://www.starlette.io/background/" class="external-link" target="_blank">`starlette.background`</a>.
It is imported/included directly into FastAPI so that you can import it from `fastapi` and avoid accidentally importing the alternative `BackgroundTask` (without the `s` at the end) from `starlette.background`.
@@ -79,15 +75,15 @@ By only using `BackgroundTasks` (and not `BackgroundTask`), it's then possible t
It's still possible to use `BackgroundTask` alone in FastAPI, but you have to create the object in your code and return a Starlette `Response` including it.
You can see more details in <a href="https://www.starlette.io/background/" target="_blank">Starlette's official docs for Background Tasks</a>.
You can see more details in <a href="https://www.starlette.io/background/" class="external-link" target="_blank">Starlette's official docs for Background Tasks</a>.
## Caveat
If you need to perform heavy background computation and you don't necessarily need it to be run by the same process (for example, you don't need to share memory, variables, etc), you might benefit from using other bigger tools like <a href="http://www.celeryproject.org/" target="_blank">Celery</a>.
If you need to perform heavy background computation and you don't necessarily need it to be run by the same process (for example, you don't need to share memory, variables, etc), you might benefit from using other bigger tools like <a href="http://www.celeryproject.org/" class="external-link" target="_blank">Celery</a>.
They tend to require more complex configurations, a message/job queue manager, like RabbitMQ or Redis, but they allow you to run background tasks in multiple processes, and especially, in multiple servers.
To see an example, check the <a href="https://fastapi.tiangolo.com/project-generation/" target="_blank">Project Generators</a>, they all include Celery already configured.
To see an example, check the [Project Generators](../project-generation.md){.internal-link target=_blank}, they all include Celery already configured.
But if you need to access variables and objects from the same **FastAPI** app, or you need to perform small background tasks (like sending an email notification), you can simply just use `BackgroundTasks`.

View File

@@ -44,7 +44,6 @@ Let's say you have a file structure like this:
* The file `app/routers/users.py` is beside the `app/routers/__init__.py`.
* So, it's a submodule: `app.routers.users`.
## `APIRouter`
Let's say the file dedicated to handling just users is the submodule at `/app/routers/users.py`.
@@ -55,7 +54,6 @@ But it's still part of the same **FastAPI** application/web API (it's part of th
You can create the *path operations* for that module using `APIRouter`.
### Import `APIRouter`
You import it and create an "instance" the same way you would with the class `FastAPI`:
@@ -64,8 +62,7 @@ You import it and create an "instance" the same way you would with the class `Fa
{!./src/bigger_applications/app/routers/users.py!}
```
### Path operations with `APIRouter`
### *Path operations* with `APIRouter`
And then you use it to declare your *path operations*.
@@ -86,12 +83,11 @@ All the same parameters, responses, dependencies, tags, etc.
We are going to include this `APIrouter` in the main `FastAPI` app, but first, let's add another `APIRouter`.
## Another module with `APIRouter`
Let's say you also have the endpoints dedicated to handling "Items" from your application in the module at `app/routers/items.py`.
You have path operations for:
You have *path operations* for:
* `/items/`
* `/items/{item_id}`
@@ -144,7 +140,6 @@ We import the other submodules that have `APIRouter`s:
As the file `app/routers/items.py` is part of the same Python package, we can import it using "dot notation".
### How the importing works
The section:
@@ -172,7 +167,7 @@ from app.routers import items, users
The second version is an "absolute import".
To learn more about Python Packages and Modules, read <a href="https://docs.python.org/3/tutorial/modules.html" target="_blank">the official Python documentation about Modules</a>.
To learn more about Python Packages and Modules, read <a href="https://docs.python.org/3/tutorial/modules.html" class="external-link" target="_blank">the official Python documentation about Modules</a>.
### Avoid name collisions
@@ -228,9 +223,9 @@ Now, let's include the router from the `items` submodule.
But, remember that we were lazy and didn't add `/items/` nor `tags` to all the *path operations*?
We can add a prefix to all the path operations using the parameter `prefix` of `app.include_router()`.
We can add a prefix to all the *path operations* using the parameter `prefix` of `app.include_router()`.
As the path of each path operation has to start with `/`, like in:
As the path of each *path operation* has to start with `/`, like in:
```Python hl_lines="1"
@router.get("/{item_id}")
@@ -266,8 +261,8 @@ The end result is that the item paths are now:
* The *path operation* that declared a custom `403` response will have both the predefined responses (`404`) and the `403` declared in it directly.
* All these *path operations* will have the list of `dependencies` evaluated/executed before them.
* If you also declare dependencies in a specific *path operation*, **they will be executed too**.
* The router dependencies are executed first, then the <a href="https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-decorator/" target="_blank">`dependencies` in the decorator</a>, and then the normal parameter dependencies.
* You can also add <a href="https://fastapi.tiangolo.com/tutorial/security/oauth2-scopes/" target="_blank">`Security` dependencies with `scopes`</a>.
* The router dependencies are executed first, then the [`dependencies` in the decorator](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, and then the normal parameter dependencies.
* You can also add [`Security` dependencies with `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
!!! tip
Having `dependencies` in a decorator can be used, for example, to require authentication for a whole group of *path operations*. Even if the dependencies are not added individually to each one of them.
@@ -276,7 +271,7 @@ The end result is that the item paths are now:
The `prefix`, `tags`, `responses` and `dependencies` parameters are (as in many other cases) just a feature from **FastAPI** to help you avoid code duplication.
!!! tip
You could also add path operations directly, for example with: `@app.get(...)`.
You could also add *path operations* directly, for example with: `@app.get(...)`.
Apart from `app.include_router()`, in the same **FastAPI** app.
@@ -289,9 +284,9 @@ The end result is that the item paths are now:
The `APIRouter`s are not "mounted", they are not isolated from the rest of the application.
This is because we want to include their path operations in the OpenAPI schema and the user interfaces.
This is because we want to include their *path operations* in the OpenAPI schema and the user interfaces.
As we cannot just isolate them and "mount" them independently of the rest, the path operations are "cloned" (re-created), not included directly.
As we cannot just isolate them and "mount" them independently of the rest, the *path operations* are "cloned" (re-created), not included directly.
## Check the automatic API docs
@@ -301,7 +296,7 @@ Now, run `uvicorn`, using the module `app.main` and the variable `app`:
uvicorn app.main:app --reload
```
And open the docs at <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
And open the docs at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
You will see the automatic API docs, including the paths from all the submodules, using the correct paths (and prefixes) and the correct tags:

View File

@@ -1,4 +1,4 @@
The same way you can declare additional validation and metadata in path operation function parameters with `Query`, `Path` and `Body`, you can declare validation and metadata inside of Pydantic models using Pydantic's `Field`.
The same way you can declare additional validation and metadata in *path operation function* parameters with `Query`, `Path` and `Body`, you can declare validation and metadata inside of Pydantic models using Pydantic's `Field`.
## Import `Field`
@@ -11,7 +11,6 @@ First, you have to import it:
!!! warning
Notice that `Field` is imported directly from `pydantic`, not from `fastapi` as are all the rest (`Query`, `Path`, `Body`, etc).
## Declare model attributes
You can then use `Field` with model attributes:
@@ -29,10 +28,10 @@ You can then use `Field` with model attributes:
`Body` also returns objects of a subclass of `FieldInfo` directly. And there are others you will see later that are subclasses of the `Body` class.
Remember that when you import `Query`, `Path`, and others from `fastapi`, <a href="https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#recap" target="_blank">those are actually functions that return classes of the same name</a>.
Remember that when you import `Query`, `Path`, and others from `fastapi`, those are actually functions that return special classes.
!!! tip
Notice how each model's attribute with a type, default value and `Field` has the same structure as a path operation function's parameter, with `Field` instead of `Path`, `Query` and `Body`.
Notice how each model's attribute with a type, default value and `Field` has the same structure as a *path operation function's* parameter, with `Field` instead of `Path`, `Query` and `Body`.
## JSON Schema extras
@@ -45,7 +44,7 @@ If you know JSON Schema and want to add extra information apart from what we hav
!!! warning
Have in mind that extra parameters passed won't add any validation, only annotation, for documentation purposes.
For example, you can use that functionality to pass a <a href="http://json-schema.org/latest/json-schema-validation.html#rfc.section.8.5" target="_blank">JSON Schema example</a> field to a body request JSON Schema:
For example, you can use that functionality to pass a <a href="http://json-schema.org/latest/json-schema-validation.html#rfc.section.8.5" class="external-link" target="_blank">JSON Schema example</a> field to a body request JSON Schema:
```Python hl_lines="20 21 22 23 24 25"
{!./src/body_fields/tutorial002.py!}

View File

@@ -13,10 +13,9 @@ And you can also declare body parameters as optional, by setting the default to
!!! note
Notice that, in this case, the `item` that would be taken from the body is optional. As it has a `None` default value.
## Multiple body parameters
In the previous example, the path operations would expect a JSON body with the attributes of an `Item`, like:
In the previous example, the *path operations* would expect a JSON body with the attributes of an `Item`, like:
```JSON
{
@@ -160,9 +159,9 @@ instead of:
## Recap
You can add multiple body parameters to your path operation function, even though a request can only have a single body.
You can add multiple body parameters to your *path operation function*, even though a request can only have a single body.
But **FastAPI** will handle it, give you the correct data in your function, and validate and document the correct schema in the path operation.
But **FastAPI** will handle it, give you the correct data in your function, and validate and document the correct schema in the *path operation*.
You can also declare singular values to be received as part of the body.

View File

@@ -116,9 +116,9 @@ Again, doing just that declaration, with **FastAPI** you get:
Apart from normal singular types like `str`, `int`, `float`, etc. You can use more complex singular types that inherit from `str`.
To see all the options you have, checkout the docs for <a href="https://pydantic-docs.helpmanual.io/#exotic-types" target="_blank">Pydantic's exotic types</a>. You will see some examples in the next chapter.
To see all the options you have, checkout the docs for <a href="https://pydantic-docs.helpmanual.io/usage/types/" class="external-link" target="_blank">Pydantic's exotic types</a>. You will see some examples in the next chapter.
For example, as in the `Image` model we have a `url` field, we can declare it to be instead of a `str`, a Pydantic's `UrlStr`:
For example, as in the `Image` model we have a `url` field, we can declare it to be instead of a `str`, a Pydantic's `HttpUrl`:
```Python hl_lines="4 10"
{!./src/body_nested_models/tutorial005.py!}
@@ -231,7 +231,7 @@ In this case, you would accept any `dict` as long as it has `int` keys with `flo
## Recap
With **FastAPI** you have the maximum flexibility provided by Pydantic models, while keeping your code simple, short and elegant.
With **FastAPI** you have the maximum flexibility provided by Pydantic models, while keeping your code simple, short and elegant.
But with all the benefits:

View File

@@ -1,6 +1,6 @@
## Update replacing with `PUT`
To update an item you can use the [HTTP `PUT`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT) operation.
To update an item you can use the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT" class="external-link" target="_blank">HTTP `PUT`</a> operation.
You can use the `jsonable_encoder` to convert the input data to data that can be stored as JSON (e.g. with a NoSQL database). For example, converting `datetime` to `str`.
@@ -28,7 +28,7 @@ And the data would be saved with that "new" `tax` of `10.5`.
## Partial updates with `PATCH`
You can also use the [HTTP `PATCH`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) operation to *partially* update data.
You can also use the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> operation to *partially* update data.
This means that you can send only the data that you want to update, leaving the rest intact.
@@ -94,4 +94,4 @@ In summary, to apply partial updates you would:
So, if you want to receive partial updates that can omit all the attributes, you need to have a model with all the attributes marked as optional (with default values or `None`).
To distinguish from the models with all optional values for **updates** and models with required values for **creation**, you can use the ideas described in <a href="https://fastapi.tiangolo.com/tutorial/extra-models/" target="_blank">Extra Models</a>.
To distinguish from the models with all optional values for **updates** and models with required values for **creation**, you can use the ideas described in [Extra Models](extra-models.md){.internal-link target=_blank}.

View File

@@ -4,7 +4,7 @@ A **request** body is data sent by the client to your API. A **response** body i
Your API almost always has to send a **response** body. But clients don't necessarily need to send **request** bodies all the time.
To declare a **request** body, you use <a href="https://pydantic-docs.helpmanual.io/" target="_blank">Pydantic</a> models with all their power and benefits.
To declare a **request** body, you use <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> models with all their power and benefits.
!!! info
You cannot send a request body using a `GET` operation (HTTP method).
@@ -53,7 +53,7 @@ For example, this model above declares a JSON "`object`" (or Python `dict`) like
## Declare it as a parameter
To add it to your path operation, declare it the same way you declared path and query parameters:
To add it to your *path operation*, declare it the same way you declared path and query parameters:
```Python hl_lines="16"
{!./src/body/tutorial001.py!}
@@ -71,7 +71,7 @@ With just that Python type declaration, **FastAPI** will:
* If the data is invalid, it will return a nice and clear error, indicating exactly where and what was the incorrect data.
* Give you the received data in the parameter `item`.
* As you declared it in the function to be of type `Item`, you will also have all the editor support (completion, etc) for all of the attributes and their types.
* Generate <a href="http://json-schema.org" target="_blank">JSON Schema</a> definitions for your model, you can also use them anywhere else you like if it makes sense for your project.
* Generate <a href="http://json-schema.org" class="external-link" target="_blank">JSON Schema</a> definitions for your model, you can also use them anywhere else you like if it makes sense for your project.
* Those schemas will be part of the generated OpenAPI schema, and used by the automatic documentation <abbr title="User Interfaces">UIs</abbr>.
## Automatic docs
@@ -80,7 +80,7 @@ The JSON Schemas of your models will be part of your OpenAPI generated schema, a
<img src="/img/tutorial/body/image01.png">
And will be also used in the API docs inside each path operation that needs them:
And will be also used in the API docs inside each *path operation* that needs them:
<img src="/img/tutorial/body/image02.png">
@@ -100,13 +100,12 @@ And it was thoroughly tested at the design phase, before any implementation, to
There were even some changes to Pydantic itself to support this.
The previous screenshots were taken with <a href="https://code.visualstudio.com" target="_blank">Visual Studio Code</a>.
The previous screenshots were taken with <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a>.
But you would get the same editor support with <a href="https://www.jetbrains.com/pycharm/" target="_blank">PyCharm</a> and most of the other Python editors:
But you would get the same editor support with <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> and most of the other Python editors:
<img src="/img/tutorial/body/image05.png">
## Use the model
Inside of the function, you can access all the attributes of the model object directly:
@@ -139,4 +138,4 @@ The function parameters will be recognized as follows:
* If the parameter is also declared in the **path**, it will be used as a path parameter.
* If the parameter is of a **singular type** (like `int`, `float`, `str`, `bool`, etc) it will be interpreted as a **query** parameter.
* If the parameter is declared to be of the type of a **Pydantic model**, it will be interpreted as a request **body**.
* If the parameter is declared to be of the type of a **Pydantic model**, it will be interpreted as a request **body**.

View File

@@ -21,7 +21,7 @@ The first value is the default value, you can pass all the extra validation or a
!!! note "Technical Details"
`Cookie` is a "sister" class of `Path` and `Query`. It also inherits from the same common `Param` class.
But remember that when you import `Query`, `Path`, `Cookie` and others from `fastapi`, <a href="https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#recap" target="_blank">those are actually functions that return classes of the same name</a>.
But remember that when you import `Query`, `Path`, `Cookie` and others from `fastapi`, those are actually functions that return special classes.
!!! info
To declare cookies, you need to use `Cookie`, because otherwise the parameters would be interpreted as query parameters.

View File

@@ -1,4 +1,4 @@
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" target="_blank">CORS or "Cross-Origin Resource Sharing"</a> refers to the situations when a frontend running in a browser has JavaScript code that communicates with a backend, and the backend is in a different "origin" than the frontend.
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">CORS or "Cross-Origin Resource Sharing"</a> refers to the situations when a frontend running in a browser has JavaScript code that communicates with a backend, and the backend is in a different "origin" than the frontend.
## Origin
@@ -32,7 +32,7 @@ So, for everything to work correctly, it's better to specify explicitly the allo
## Use `CORSMiddleware`
You can configure it in your **FastAPI** application using Starlette's <a href="https://www.starlette.io/middleware/#corsmiddleware" target="_blank">`CORSMiddleware`</a>.
You can configure it in your **FastAPI** application using Starlette's <a href="https://www.starlette.io/middleware/#corsmiddleware" class="external-link" target="_blank">`CORSMiddleware`</a>.
* Import it from Starlette.
* Create a list of allowed origins (as strings).
@@ -50,6 +50,6 @@ You can also specify if your backend allows:
## More info
For more details of what you can specify in `CORSMiddleware`, check <a href="https://www.starlette.io/middleware/#corsmiddleware" target="_blank">Starlette's `CORSMiddleware` docs</a>.
For more details of what you can specify in `CORSMiddleware`, check <a href="https://www.starlette.io/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette's `CORSMiddleware` docs</a>.
For more info about <abbr title="Cross-Origin Resource Sharing">CORS</abbr>, check the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" target="_blank">Mozilla CORS documentation</a>.
For more info about <abbr title="Cross-Origin Resource Sharing">CORS</abbr>, check the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">Mozilla CORS documentation</a>.

View File

@@ -65,7 +65,7 @@ So, the line:
will not be executed.
!!! info
For more information, check <a href="https://docs.python.org/3/library/__main__.html" target="_blank">the official Python docs</a>.
For more information, check <a href="https://docs.python.org/3/library/__main__.html" class="external-link" target="_blank">the official Python docs</a>.
## Run your code with your debugger

View File

@@ -2,13 +2,13 @@ Before diving deeper into the **Dependency Injection** system, let's upgrade the
## A `dict` from the previous example
In the previous example, we are returning a `dict` from our dependency ("dependable"):
In the previous example, we were returning a `dict` from our dependency ("dependable"):
```Python hl_lines="7"
{!./src/dependencies/tutorial001.py!}
```
But then we get a `dict` in the parameter `commons` of the path operation function.
But then we get a `dict` in the parameter `commons` of the *path operation function*.
And we know that editors can't provide a lot of support (like completion) for `dict`s, because they can't know their keys and value types.
@@ -63,9 +63,9 @@ Then, in **FastAPI**, you could use a Python class as a dependency.
What FastAPI actually checks is that it is a "callable" (function, class or anything else) and the parameters defined.
If you pass a "callable" as a dependency in **FastAPI**, it will analyze the parameters for that "callable", and process them in the same way as the parameters for a path operation function. Including sub-dependencies.
If you pass a "callable" as a dependency in **FastAPI**, it will analyze the parameters for that "callable", and process them in the same way as the parameters for a *path operation function*. Including sub-dependencies.
That also applies to callables with no parameters at all. The same as it would be for path operation functions with no parameters.
That also applies to callables with no parameters at all. The same as it would be for *path operation functions* with no parameters.
Then, we can change the dependency "dependable" `common_parameters` from above to the class `CommonQueryParameters`:
@@ -173,7 +173,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
commons: CommonQueryParams = Depends()
```
So, you can declare the dependency as the type of the variable, and use `Depends()` as the "default" value, without any parameter, instead of having to write the full class *again* inside of `Depends(CommonQueryParams)`.
So, you can declare the dependency as the type of the variable, and use `Depends()` as the "default" value (the value after the `=`) for that function's parameter, without any parameter, instead of having to write the full class *again* inside of `Depends(CommonQueryParams)`.
So, the same example would look like:

View File

@@ -57,4 +57,4 @@ So, you can re-use a normal dependency (that returns a value) you already use so
## Dependencies for a group of *path operations*
Later, when reading about how to <a href="https://fastapi.tiangolo.com/tutorial/bigger-applications/" target="_blank">structure bigger applications</a>, possibly with multiple files, you will learn how to declare a single `dependencies` parameter for a group of *path operations*.
Later, when reading about how to structure bigger applications ([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md){.internal-link target=_blank}), possibly with multiple files, you will learn how to declare a single `dependencies` parameter for a group of *path operations*.

View File

@@ -10,17 +10,17 @@ To do this, use `yield` instead of `return`, and write the extra steps after.
!!! info
For this to work, you need to use **Python 3.7** or above, or in **Python 3.6**, install the "backports":
```bash
```
pip install async-exit-stack async-generator
```
This installs <a href="https://github.com/sorcio/async_exit_stack" target="_blank">async-exit-stack</a> and <a href="https://github.com/python-trio/async_generator" target="_blank">async-generator</a>.
This installs <a href="https://github.com/sorcio/async_exit_stack" class="external-link" target="_blank">async-exit-stack</a> and <a href="https://github.com/python-trio/async_generator" class="external-link" target="_blank">async-generator</a>.
!!! note "Technical Details"
Any function that is valid to use with:
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" target="_blank">`@contextlib.contextmanager`</a> or
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager" target="_blank">`@contextlib.asynccontextmanager`</a>
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" class="external-link" target="_blank">`@contextlib.contextmanager`</a> or
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager" class="external-link" target="_blank">`@contextlib.asynccontextmanager`</a>
would be valid to use as a **FastAPI** dependency.
@@ -98,7 +98,7 @@ You can have any combinations of dependencies that you want.
**FastAPI** will make sure everything is run in the correct order.
!!! note "Technical Details"
This works thanks to Python's <a href="https://docs.python.org/3/library/contextlib.html" target="_blank">Context Managers</a>.
This works thanks to Python's <a href="https://docs.python.org/3/library/contextlib.html" class="external-link" target="_blank">Context Managers</a>.
**FastAPI** uses them internally to achieve this.
@@ -108,7 +108,7 @@ You can have any combinations of dependencies that you want.
"Context Managers" are any of those Python objects that you can use in a `with` statement.
For example, <a href="https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files" target="_blank">you can use `with` to read a file</a>:
For example, <a href="https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files" class="external-link" target="_blank">you can use `with` to read a file</a>:
```Python
with open("./somefile.txt") as f:
@@ -116,7 +116,7 @@ with open("./somefile.txt") as f:
print(contents)
```
Underneath, the `open("./somefile.txt")` returns an object that is a called a "Context Manager".
Underneath, the `open("./somefile.txt")` creates an object that is a called a "Context Manager".
When the `with` block finishes, it makes sure to close the file, even if there were exceptions.
@@ -129,9 +129,9 @@ When you create a dependency with `yield`, **FastAPI** will internally convert i
If you are just starting with **FastAPI** you might want to skip it for now.
In Python, you can create context managers by <a href="https://docs.python.org/3/reference/datamodel.html#context-managers" target="_blank">creating a class with two methods: `__enter__()` and `__exit__()`</a>.
In Python, you can create Context Managers by <a href="https://docs.python.org/3/reference/datamodel.html#context-managers" class="external-link" target="_blank">creating a class with two methods: `__enter__()` and `__exit__()`</a>.
You can also use them with **FastAPI** dependencies with `yield` by using
You can also use them inside of **FastAPI** dependencies with `yield` by using
`with` or `async with` statements inside of the dependency function:
```Python hl_lines="1 2 3 4 5 6 7 8 9 13"
@@ -141,8 +141,8 @@ You can also use them with **FastAPI** dependencies with `yield` by using
!!! tip
Another way to create a context manager is with:
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" target="_blank">`@contextlib.contextmanager`</a> or
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager" target="_blank">`@contextlib.asynccontextmanager`</a>
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" class="external-link" target="_blank">`@contextlib.contextmanager`</a> or
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager" class="external-link" target="_blank">`@contextlib.asynccontextmanager`</a>
using them to decorate a function with a single `yield`.

View File

@@ -2,9 +2,9 @@
It is designed to be very simple to use, and to make it very easy for any developer to integrate other components with **FastAPI**.
## "Dependency Injection"?
## What is "Dependency Injection"
**"Dependency Injection"** means, in programming, that there is a way for your code (in this case, your path operation functions) to declare things that it requires to work and use: "dependencies".
**"Dependency Injection"** means, in programming, that there is a way for your code (in this case, your *path operation functions*) to declare things that it requires to work and use: "dependencies".
And then, that system (in this case **FastAPI**) will take care of doing whatever is needed to provide your code with those needed dependencies ("inject" the dependencies).
@@ -13,7 +13,7 @@ This is very useful when you need to:
* Have shared logic (the same code logic again and again).
* Share database connections.
* Enforce security, authentication, role requirements, etc.
* etc.
* And many other things...
All these, while minimizing code repetition.
@@ -27,7 +27,7 @@ But this way we can focus on how the **Dependency Injection** system works.
Let's first focus on the dependency.
It is just a function that can take all the same parameters that a path operation function can take:
It is just a function that can take all the same parameters that a *path operation function* can take:
```Python hl_lines="6 7"
{!./src/dependencies/tutorial001.py!}
@@ -37,9 +37,9 @@ That's it.
**2 lines**.
And it has the same shape and structure that all your path operation functions.
And it has the same shape and structure that all your *path operation functions*.
You can think of it as a path operation function without the "decorator" (without the `@app.get("/some-path")`).
You can think of it as a *path operation function* without the "decorator" (without the `@app.get("/some-path")`).
And it can return anything you want.
@@ -59,7 +59,7 @@ And then it just returns a `dict` containing those values.
### Declare the dependency, in the "dependant"
The same way you use `Body`, `Query`, etc. with your path operation function parameters, use `Depends` with a new parameter:
The same way you use `Body`, `Query`, etc. with your *path operation function* parameters, use `Depends` with a new parameter:
```Python hl_lines="11 16"
{!./src/dependencies/tutorial001.py!}
@@ -71,7 +71,7 @@ You only give `Depends` a single parameter.
This parameter must be something like a function.
And that function takes parameters in the same way that path operation functions do.
And that function takes parameters in the same way that *path operation functions* do.
!!! tip
You'll see what other "things", apart from functions, can be used as dependencies in the next chapter.
@@ -80,26 +80,25 @@ Whenever a new request arrives, **FastAPI** will take care of:
* Calling your dependency ("dependable") function with the correct parameters.
* Get the result from your function.
* Assign that result to the parameter in your path operation function.
* Assign that result to the parameter in your *path operation function*.
!!! note
!!! check
Notice that you don't have to create a special class and pass it somewhere to **FastAPI** to "register" it or anything similar.
You just pass it to `Depends` and **FastAPI** knows how to do the rest.
## To `async` or not to `async`
As dependencies will also be called by **FastAPI** (the same as your path operation functions), the same rules apply while defining your functions.
As dependencies will also be called by **FastAPI** (the same as your *path operation functions*), the same rules apply while defining your functions.
You can use `async def` or normal `def`.
And you can declare dependencies with `async def` inside of normal `def` path operation functions, or `def` dependencies inside of `async def` path operation functions, etc.
And you can declare dependencies with `async def` inside of normal `def` *path operation functions*, or `def` dependencies inside of `async def` *path operation functions*, etc.
It doesn't matter. **FastAPI** will know what to do.
!!! note
If you don't know, check the _"In a hurry?"_ section about <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">`async` and `await` in the docs</a>.
If you don't know, check the [Async: *"In a hurry?"*](../../async.md){.internal-link target=_blank} section about `async` and `await` in the docs.
## Integrated with OpenAPI
@@ -118,7 +117,7 @@ Actually, all (or most) of the web frameworks work in this same way.
You never call those functions directly. They are called by your framework (in this case, **FastAPI**).
With the Dependency Injection system, you can also tell **FastAPI** that your path operation function also "depends" on something else that should be executed before your *path operation function*, and **FastAPI** will take care of executing it and "injecting" the results.
With the Dependency Injection system, you can also tell **FastAPI** that your *path operation function* also "depends" on something else that should be executed before your *path operation function*, and **FastAPI** will take care of executing it and "injecting" the results.
Other common terms for this same idea of "dependency injection" are:
@@ -130,9 +129,9 @@ Other common terms for this same idea of "dependency injection" are:
## **FastAPI** plug-ins
Integrations and "plug-in"s can be built using the **Dependency Injection** system. But in fact, there is actually **no need to create "plug-ins"**, as by using dependencies it's possible to declare an infinite number of integrations and interactions that become available to your path operation functions.
Integrations and "plug-in"s can be built using the **Dependency Injection** system. But in fact, there is actually **no need to create "plug-ins"**, as by using dependencies it's possible to declare an infinite number of integrations and interactions that become available to your *path operation functions*.
And dependencies can be created in a very simple and intuitive way that allow you to just import the Python packages you need, and integrate them with your API functions in a couple of lines of code, _literally_.
And dependencies can be created in a very simple and intuitive way that allow you to just import the Python packages you need, and integrate them with your API functions in a couple of lines of code, *literally*.
You will see examples of this in the next chapters, about relational and NoSQL databases, security, etc.
@@ -159,6 +158,6 @@ In the end, a hierarchical tree of dependencies is built, and the **Dependency I
## Integrated with **OpenAPI**
All these dependencies, while declaring their requirements, add parameters, validations, etc. to your path operations.
All these dependencies, while declaring their requirements, also add parameters, validations, etc. to your *path operations*.
**FastAPI** will take care of adding it all to the OpenAPI schema, so that it is shown in the interactive documentation systems.

View File

@@ -1,6 +1,6 @@
You can create dependencies that have sub-dependencies.
You can create dependencies that have **sub-dependencies**.
They can be as "deep" as you need them to be.
They can be as **deep** as you need them to be.
**FastAPI** will take care of solving them.
@@ -40,7 +40,7 @@ Then we can use the dependency with:
```
!!! info
Notice that we are only declaring one dependency in the path operation function, the `query_or_cookie_extractor`.
Notice that we are only declaring one dependency in the *path operation function*, the `query_or_cookie_extractor`.
But **FastAPI** will know that it has to solve `query_extractor` first, to pass the results of that to `query_or_cookie_extractor` while calling it.
@@ -61,7 +61,7 @@ async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False
Apart from all the fancy words used here, the **Dependency Injection** system is quite simple.
Just functions that look the same as the path operation functions.
Just functions that look the same as the *path operation functions*.
But still, it is very powerful, and allows you to declare arbitrarily deeply nested dependency "graphs" (trees).

View File

@@ -10,7 +10,7 @@ Let's imagine that you have a database `fake_db` that only receives JSON compati
For example, it doesn't receive `datetime` objects, as those are not compatible with JSON.
So, a `datetime` object would have to be converted to a `str` containing the data in <a href="https://en.wikipedia.org/wiki/ISO_8601" target="_blank">ISO format</a>.
So, a `datetime` object would have to be converted to a `str` containing the data in <a href="https://en.wikipedia.org/wiki/ISO_8601" class="external-link" target="_blank">ISO format</a>.
The same way, this database wouldn't receive a Pydantic model (an object with attributes), only a `dict`.
@@ -24,7 +24,7 @@ It receives an object, like a Pydantic model, and returns a JSON compatible vers
In this example, it would convert the Pydantic model to a `dict`, and the `datetime` to a `str`.
The result of calling it is something that can be encoded with the Python standard <a href="https://docs.python.org/3/library/json.html#json.dumps" target="_blank">`json.dumps()`</a>.
The result of calling it is something that can be encoded with the Python standard <a href="https://docs.python.org/3/library/json.html#json.dumps" class="external-link" target="_blank">`json.dumps()`</a>.
It doesn't return a large `str` containing the data in JSON format (as a string). It returns a Python standard data structure (e.g. a `dict`) with values and sub-values that are all compatible with JSON.

View File

@@ -19,10 +19,10 @@ And you will still have the same features as seen up to now:
Here are some of the additional data types you can use:
* `UUID`:
* `UUID`:
* A standard "Universally Unique Identifier", common as an ID in many databases and systems.
* In requests and responses will be represented as a `str`.
* `datetime.datetime`:
* `datetime.datetime`:
* A Python `datetime.datetime`.
* In requests and responses will be represented as a `str` in ISO 8601 format, like: `2008-09-15T15:53:00+05:00`.
* `datetime.date`:
@@ -34,7 +34,7 @@ Here are some of the additional data types you can use:
* `datetime.timedelta`:
* A Python `datetime.timedelta`.
* In requests and responses will be represented as a `float` of total seconds.
* Pydantic also allows representing it as a "ISO 8601 time diff encoding", <a href="https://pydantic-docs.helpmanual.io/#json-serialisation" target="_blank">see the docs for more info</a>.
* Pydantic also allows representing it as a "ISO 8601 time diff encoding", <a href="https://pydantic-docs.helpmanual.io/#json-serialisation" class="external-link" target="_blank">see the docs for more info</a>.
* `frozenset`:
* In requests and responses, treated the same as a `set`:
* In requests, a list will be read, eliminating duplicates and converting it to a `set`.
@@ -48,10 +48,9 @@ Here are some of the additional data types you can use:
* Standard Python `Decimal`.
* In requests and responses, handled the same as a `float`.
## Example
Here's an example path operation with parameters using some of the above types.
Here's an example *path operation* with parameters using some of the above types.
```Python hl_lines="1 2 11 12 13 14 15"
{!./src/extra_data_types/tutorial001.py!}

View File

@@ -9,7 +9,7 @@ This is especially the case for user models, because:
!!! danger
Never store user's plaintext passwords. Always store a "secure hash" that you can then verify.
If you don't know, you will learn what a "password hash" is in the <a href="/tutorial/security/simple-oauth2/#password-hashing" target="_blank">security chapters</a>.
If you don't know, you will learn what a "password hash" is in the [security chapters](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}.
## Multiple models
@@ -158,7 +158,7 @@ You can declare a response to be the `Union` of two types, that means, that the
It will be defined in OpenAPI with `anyOf`.
To do that, use the standard Python type hint <a href="https://docs.python.org/3/library/typing.html#typing.Union" target="_blank">`typing.Union`</a>:
To do that, use the standard Python type hint <a href="https://docs.python.org/3/library/typing.html#typing.Union" class="external-link" target="_blank">`typing.Union`</a>:
```Python hl_lines="1 14 15 18 19 20 33"
{!./src/extra_models/tutorial003.py!}

View File

@@ -32,7 +32,7 @@ That last line shows the URL where your app is being served, in your local machi
### Check it
Open your browser at <a href="http://127.0.0.1:8000" target="_blank">http://127.0.0.1:8000</a>.
Open your browser at <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
You will see the JSON response as:
@@ -42,18 +42,17 @@ You will see the JSON response as:
### Interactive API docs
Now go to <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" target="_blank">Swagger UI</a>):
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### Alternative API docs
And now, go to <a href="http://127.0.0.1:8000/redoc" target="_blank">http://127.0.0.1:8000/redoc</a>.
And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" target="_blank">ReDoc</a>):
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
@@ -81,11 +80,11 @@ In that case, it would mean the JSON attributes, and data types they have, etc.
OpenAPI defines an API schema for your API. And that schema includes definitions (or "schemas") of the data sent and received by your API using **JSON Schema**, the standard for JSON data schemas.
#### Check it
#### Check the `openapi.json`
If you are curious about how the raw OpenAPI schema looks like, it is just an automatically generated JSON with the descriptions of all your API.
You can see it directly at: <a href="http://127.0.0.1:8000/openapi.json" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
You can see it directly at: <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
It will show a JSON starting with something like:
@@ -110,7 +109,7 @@ It will show a JSON starting with something like:
...
```
#### What for?
#### What is OpenAPI for
This OpenAPI schema is what powers the 2 interactive documentation systems included.
@@ -161,7 +160,7 @@ And put it in a file `main.py`, then you would call `uvicorn` like:
uvicorn main:my_awesome_api --reload
```
### Step 3: create a path operation
### Step 3: create a *path operation*
#### Path
@@ -219,7 +218,7 @@ So, in OpenAPI, each of the HTTP methods is called an "operation".
We are going to call them "**operations**" too.
#### Define a path operation function
#### Define a *path operation function*
```Python hl_lines="6"
{!./src/first_steps/tutorial001.py!}
@@ -256,7 +255,7 @@ And the more exotic ones:
!!! tip
You are free to use each operation (HTTP method) as you wish.
**FastAPI** doesn't enforce any specific meaning.
The information here is presented as a guideline, not a requirement.
@@ -275,7 +274,7 @@ This is our "**path operation function**":
{!./src/first_steps/tutorial001.py!}
```
This is a Python function.
This is a Python function.
It will be called by **FastAPI** whenever it receives a request to the URL "`/`" using `GET`.
@@ -290,7 +289,7 @@ You could also define it as a normal function instead of `async def`:
```
!!! note
If you don't know the difference, check the _"In a hurry?"_ section about <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">`async` and `await` in the docs</a>.
If you don't know the difference, check the [Async: *"In a hurry?"*](../async.md#in-a-hurry){.internal-link target=_blank}.
### Step 5: return the content
@@ -304,11 +303,10 @@ You can also return Pydantic models (you'll see more about that later).
There are many other objects and models that will be automatically converted to JSON (including ORMs, etc). Try using your favorite ones, it's highly probable that they are already supported.
## Recap
* Import `FastAPI`.
* Create an `app` instance.
* Write a **path operation decorator** (like `@app.get("/")`).
* Write a **path operation function** (like `def root(): ...` above).
* Run the development server (like `uvicorn main:app --reload`).
* Run the development server (like `uvicorn main:app --reload`).

View File

@@ -33,7 +33,7 @@ To return HTTP responses with errors to the client you use `HTTPException`.
Because it's a Python exception, you don't `return` it, you `raise` it.
This also means that if you are inside a utility function that you are calling inside of your path operation function, and you raise the `HTTPException` from inside of that utility function, it won't run the rest of the code in the path operation function, it will terminate that request right away and send the HTTP error from the `HTTPException` to the client.
This also means that if you are inside a utility function that you are calling inside of your *path operation function*, and you raise the `HTTPException` from inside of that utility function, it won't run the rest of the code in the *path operation function*, it will terminate that request right away and send the HTTP error from the `HTTPException` to the client.
The benefit of raising an exception over `return`ing a value will be more evident in the section about Dependencies and Security.
@@ -82,7 +82,7 @@ But in case you needed it for an advanced scenario, you can add custom headers:
## Install custom exception handlers
You can add custom exception handlers with <a href="https://www.starlette.io/exceptions/" target="_blank">the same exception utilities from Starlette</a>.
You can add custom exception handlers with <a href="https://www.starlette.io/exceptions/" class="external-link" target="_blank">the same exception utilities from Starlette</a>.
Let's say you have a custom exception `UnicornException` that you (or a library you use) might `raise`.
@@ -156,7 +156,7 @@ path -> item_id
!!! warning
These are technical details that you might skip if it's not important for you now.
`RequestValidationError` is a sub-class of Pydantic's <a href="https://pydantic-docs.helpmanual.io/#error-handling" target="_blank">`ValidationError`</a>.
`RequestValidationError` is a sub-class of Pydantic's <a href="https://pydantic-docs.helpmanual.io/#error-handling" class="external-link" target="_blank">`ValidationError`</a>.
**FastAPI** uses it so that, if you use a Pydantic model in `response_model`, and your data has an error, you will see the error in your log.
@@ -176,6 +176,47 @@ For example, you could want to return a plain text response instead of JSON for
{!./src/handling_errors/tutorial004.py!}
```
### Use the `RequestValidationError` body
The `RequestValidationError` contains the `body` it received with invalid data.
You could use it while developing your app to log the body and debug it, return it to the user, etc.
```Python hl_lines="16"
{!./src/handling_errors/tutorial005.py!}
```
Now try sending an invalid item like:
```JSON
{
"title": "towel",
"size": "XL"
}
```
You will receive a response telling you that the data is invalid containing the received body:
```JSON hl_lines="13 14 15 16"
{
"detail": [
{
"loc": [
"body",
"item",
"size"
],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
],
"body": {
"title": "towel",
"size": "XL"
}
}
```
#### FastAPI's `HTTPException` vs Starlette's `HTTPException`
**FastAPI** has its own `HTTPException`.
@@ -190,7 +231,7 @@ So, you can keep raising **FastAPI**'s `HTTPException` as normally in your code.
But when you register an exception handler, you should register it for Starlette's `HTTPException`.
This way, if any part of Starlette's internal code, or a Starlette extension or plug-in, raises an `HTTPException`, your handler will be able to catch handle it.
This way, if any part of Starlette's internal code, or a Starlette extension or plug-in, raises an `HTTPException`, your handler will be able to catch and handle it.
In this example, to be able to have both `HTTPException`s in the same code, Starlette's exceptions is renamed to `StarletteHTTPException`:
@@ -205,9 +246,9 @@ You could also just want to use the exception somehow, but then use the same def
You can import and re-use the default exception handlers from `fastapi.exception_handlers`:
```Python hl_lines="2 3 4 5 15 21"
{!./src/handling_errors/tutorial005.py!}
{!./src/handling_errors/tutorial006.py!}
```
In this example, you are just `print`ing the error with a very expressive notification.
In this example, you are just `print`ing the error with a very expressive message.
But you get the idea, you can use the exception and then just re-use the default exception handlers.

View File

@@ -21,7 +21,7 @@ The first value is the default value, you can pass all the extra validation or a
!!! note "Technical Details"
`Header` is a "sister" class of `Path`, `Query` and `Cookie`. It also inherits from the same common `Param` class.
But remember that when you import `Query`, `Path`, `Header`, and others from `fastapi`, <a href="https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#recap" target="_blank">those are actually functions that return classes of the same name</a>.
But remember that when you import `Query`, `Path`, `Header`, and others from `fastapi`, those are actually functions that return special classes.
!!! info
To declare headers, you need to use `Header`, because otherwise the parameters would be interpreted as query parameters.

View File

@@ -1,4 +1,4 @@
This tutorial shows you how to use **FastAPI** with all its features, step by step.
This tutorial shows you how to use **FastAPI** with most of its features, step by step.
Each section gradually builds on the previous ones, but it's structured to separate topics, so that you can go directly to any specific one to solve your specific API needs.
@@ -36,7 +36,7 @@ pip install fastapi[all]
!!! note
You can also install it part by part.
This is what you would probably do once you want to deploy your application to production:
```
@@ -50,3 +50,13 @@ pip install fastapi[all]
```
And the same for each of the optional dependencies that you want to use.
## Advanced User Guide
There is also an **Advanced User Guide** that you can read later after this **Tutorial - User guide**.
The **Advanced User Guide**, builds on this, uses the same concepts, and teaches you some extra features.
But you should first read the **Tutorial - User guide** (what you are reading right now).
It's designed so that you can build a complete application with just the **Tutorial - User guide**, and then extend it in different ways, depending on your needs, using some of the additional ideas from the **Advanced User Guide**.

View File

@@ -26,17 +26,14 @@ The middleware function receives:
```
!!! tip
This technique is used in the tutorial about <a href="https://fastapi.tiangolo.com/tutorial/sql-databases/" target="_blank">SQL (Relational) Databases</a>.
Have in mind that custom proprietary headers can be added <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">using the 'X-' prefix</a>.
!!! tip
Have in mind that custom proprietary headers can be added <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" target="_blank">using the 'X-' prefix</a>.
But if you have custom headers that you want a client in a browser to be able to see, you need to add them to your <a href="https://fastapi.tiangolo.com/tutorial/cors/" target="_blank">CORS configurations</a>, using the parameter `expose_headers` documented in <a href="https://www.starlette.io/middleware/#corsmiddleware" target="_blank">Starlette's CORS docs</a>.
But if you have custom headers that you want a client in a browser to be able to see, you need to add them to your CORS configurations ([CORS (Cross-Origin Resource Sharing)
](cors.md){.internal-link target=_blank}) using the parameter `expose_headers` documented in <a href="https://www.starlette.io/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette's CORS docs</a>.
### Before and after the `response`
You can add code to be run with the `request`, before any *path operation* receives it.
You can add code to be run with the `request`, before any *path operation* receives it.
And also after the `response` is generated, before returning it.
@@ -48,7 +45,7 @@ For example, you could add a custom header `X-Process-Time` containing the time
## Starlette's Middleware
You can also add any other <a href="https://www.starlette.io/middleware/" target="_blank">Starlette Middleware</a>.
You can also add any other <a href="https://www.starlette.io/middleware/" class="external-link" target="_blank">Starlette Middleware</a>.
These are classes instead of plain functions.

View File

@@ -1,11 +1,11 @@
There are several parameters that you can pass to your path operation decorator to configure it.
There are several parameters that you can pass to your *path operation decorator* to configure it.
!!! warning
Notice that these parameters are passed directly to the path operation decorator, not to your path operation function.
Notice that these parameters are passed directly to the *path operation decorator*, not to your *path operation function*.
## Response Status Code
You can define the (HTTP) `status_code` to be used in the response of your path operation.
You can define the (HTTP) `status_code` to be used in the response of your *path operation*.
You can pass directly the `int` code, like `404`.
@@ -17,10 +17,9 @@ But if you don't remember what each number code is for, you can use the shortcut
That status code will be used in the response and will be added to the OpenAPI schema.
## Tags
You can add tags to your path operation, pass the parameter `tags` with a `list` of `str` (commonly just one `str`):
You can add tags to your *path operation*, pass the parameter `tags` with a `list` of `str` (commonly just one `str`):
```Python hl_lines="17 22 27"
{!./src/path_operation_configuration/tutorial002.py!}
@@ -40,9 +39,9 @@ You can add a `summary` and `description`:
## Description from docstring
As descriptions tend to be long and cover multiple lines, you can declare the path operation description in the function <abbr title="a multi-line string as the first expression inside a function (not assigned to any variable) used for documentation">docstring</abbr> and **FastAPI** will read it from there.
As descriptions tend to be long and cover multiple lines, you can declare the *path operation* description in the function <abbr title="a multi-line string as the first expression inside a function (not assigned to any variable) used for documentation">docstring</abbr> and **FastAPI** will read it from there.
You can write <a href="https://en.wikipedia.org/wiki/Markdown" target="_blank">Markdown</a> in the docstring, it will be interpreted and displayed correctly (taking into account docstring indentation).
You can write <a href="https://en.wikipedia.org/wiki/Markdown" class="external-link" target="_blank">Markdown</a> in the docstring, it will be interpreted and displayed correctly (taking into account docstring indentation).
```Python hl_lines="19 20 21 22 23 24 25 26 27"
{!./src/path_operation_configuration/tutorial004.py!}
@@ -61,19 +60,18 @@ You can specify the response description with the parameter `response_descriptio
```
!!! info
Notice that `response_description` refers specifically to the response, the `description` refers to the path operation in general.
Notice that `response_description` refers specifically to the response, the `description` refers to the *path operation* in general.
!!! check
OpenAPI specifies that each *path operation* requires a response description.
!!! info
OpenAPI specifies that each path operation requires a response description.
So, if you don't provide one, **FastAPI** will automatically generate one of "Successful response".
<img src="/img/tutorial/path-operation-configuration/image03.png">
## Deprecate a path operation
If you need to mark a path operation as <abbr title="obsolete, recommended not to use it">deprecated</abbr>, but without removing it, pass the parameter `deprecated`:
## Deprecate a *path operation*
If you need to mark a *path operation* as <abbr title="obsolete, recommended not to use it">deprecated</abbr>, but without removing it, pass the parameter `deprecated`:
```Python hl_lines="16"
{!./src/path_operation_configuration/tutorial006.py!}
@@ -83,10 +81,10 @@ It will be clearly marked as deprecated in the interactive docs:
<img src="/img/tutorial/path-operation-configuration/image04.png">
Check how deprecated and non-deprecated path operations look like:
Check how deprecated and non-deprecated *path operations* look like:
<img src="/img/tutorial/path-operation-configuration/image05.png">
## Recap
You can configure and add metadata for your path operations easily by passing parameters to the path operation decorators.
You can configure and add metadata for your *path operations* easily by passing parameters to the *path operation decorators*.

View File

@@ -66,6 +66,7 @@ Here, with `ge=1`, `item_id` will need to be an integer number "`g`reater than o
```Python hl_lines="8"
{!./src/path_params_numeric_validations/tutorial004.py!}
```
## Number validations: greater than and less than or equal
The same applies for:
@@ -93,7 +94,7 @@ And the same for <abbr title="less than"><code>lt</code></abbr>.
## Recap
With `Query`, `Path` (and others you haven't seen yet) you can declare [metadata and string validations (the previous chapter)](/tutorial/query-params-str-validations).
With `Query`, `Path` (and others you haven't seen yet) you can declare metadata and string validations in the same ways as with [Query Parameters and String Validations](query-params-str-validations.md){.internal-link target=_blank}.
And you can also declare numeric validations:

View File

@@ -6,7 +6,7 @@ You can declare path "parameters" or "variables" with the same syntax used by Py
The value of the path parameter `item_id` will be passed to your function as the argument `item_id`.
So, if you run this example and go to <a href="http://127.0.0.1:8000/items/foo" target="_blank">http://127.0.0.1:8000/items/foo</a>, you will see a response of:
So, if you run this example and go to <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>, you will see a response of:
```JSON
{"item_id":"foo"}
@@ -27,7 +27,7 @@ In this case, `item_id` is declared to be an `int`.
## Data <abbr title="also known as: serialization, parsing, marshalling">conversion</abbr>
If you run this example and open your browser at <a href="http://127.0.0.1:8000/items/3" target="_blank">http://127.0.0.1:8000/items/3</a>, you will see a response of:
If you run this example and open your browser at <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a>, you will see a response of:
```JSON
{"item_id":3}
@@ -40,7 +40,7 @@ If you run this example and open your browser at <a href="http://127.0.0.1:8000/
## Data validation
But if you go to the browser at <a href="http://127.0.0.1:8000/items/foo" target="_blank">http://127.0.0.1:8000/items/foo</a>, you will see a nice HTTP error of:
But if you go to the browser at <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>, you will see a nice HTTP error of:
```JSON
{
@@ -59,7 +59,7 @@ But if you go to the browser at <a href="http://127.0.0.1:8000/items/foo" target
because the path parameter `item_id` had a value of `"foo"`, which is not an `int`.
The same error would appear if you provided a `float` instead of an int, as in: <a href="http://127.0.0.1:8000/items/4.2" target="_blank">http://127.0.0.1:8000/items/4.2</a>
The same error would appear if you provided a `float` instead of an int, as in: <a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a>
!!! check
So, with the same Python type declaration, **FastAPI** gives you data validation.
@@ -70,7 +70,7 @@ The same error would appear if you provided a `float` instead of an int, as in:
## Documentation
And when you open your browser at <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>, you will see an automatic, interactive, API documentation like:
And when you open your browser at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, you will see an automatic, interactive, API documentation like:
<img src="/img/tutorial/path-params/image01.png">
@@ -81,7 +81,7 @@ And when you open your browser at <a href="http://127.0.0.1:8000/docs" target="_
## Standards-based benefits, alternative documentation
And because the generated schema is from the <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md" target="_blank">OpenAPI</a> standard, there are many compatible tools.
And because the generated schema is from the <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md" class="external-link" target="_blank">OpenAPI</a> standard, there are many compatible tools.
Because of this, **FastAPI** itself provides an alternative API documentation (using ReDoc):
@@ -91,7 +91,7 @@ The same way, there are many compatible tools. Including code generation tools f
## Pydantic
All the data validation is performed under the hood by <a href="https://pydantic-docs.helpmanual.io/" target="_blank">Pydantic</a>, so you get all the benefits from it. And you know you are in good hands.
All the data validation is performed under the hood by <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a>, so you get all the benefits from it. And you know you are in good hands.
You can use the same type declarations with `str`, `float`, `bool` and many other complex data types.
@@ -105,7 +105,7 @@ Like `/users/me`, let's say that it's to get data about the current user.
And then you can also have a path `/users/{user_id}` to get data about a specific user by some user ID.
Because path operations are evaluated in order, you need to make sure that the path for `/users/me` is declared before the one for `/users/{user_id}`:
Because *path operations* are evaluated in order, you need to make sure that the path for `/users/me` is declared before the one for `/users/{user_id}`:
```Python hl_lines="6 11"
{!./src/path_params/tutorial003.py!}
@@ -130,7 +130,7 @@ And create class attributes with fixed values, those fixed values will be the av
```
!!! info
<a href="https://docs.python.org/3/library/enum.html" target="_blank">Enumerations (or enums) are available in Python</a> since version 3.4.
<a href="https://docs.python.org/3/library/enum.html" class="external-link" target="_blank">Enumerations (or enums) are available in Python</a> since version 3.4.
!!! tip
If you are wondering, "AlexNet", "ResNet", and "LeNet" are just names of Machine Learning <abbr title="Technically, Deep Learning model architectures">models</abbr>.

View File

@@ -50,7 +50,7 @@ And then, we can pass more parameters to `Query`. In this case, the `max_length`
q: str = Query(None, max_length=50)
```
This will validate the data, show a clear error when the data is not valid, and document the parameter in the OpenAPI schema path operation.
This will validate the data, show a clear error when the data is not valid, and document the parameter in the OpenAPI schema *path operation*.
## Add more validations
@@ -118,7 +118,7 @@ So, when you need to declare a value as required while using `Query`, you can us
```
!!! info
If you hadn't seen that `...` before: it is a a special single value, it is <a href="https://docs.python.org/3/library/constants.html#Ellipsis" target="_blank">part of Python and is called "Ellipsis"</a>.
If you hadn't seen that `...` before: it is a a special single value, it is <a href="https://docs.python.org/3/library/constants.html#Ellipsis" class="external-link" target="_blank">part of Python and is called "Ellipsis"</a>.
This will let **FastAPI** know that this parameter is required.
@@ -276,4 +276,4 @@ Validations specific for strings:
In these examples you saw how to declare validations for `str` values.
See the next chapters to see how to declare validations for other types, like numbers.
See the next chapters to see how to declare validations for other types, like numbers.

View File

@@ -188,7 +188,7 @@ In this case, there are 3 query parameters:
* `limit`, an optional `int`.
!!! tip
You could also use `Enum`s <a href="https://fastapi.tiangolo.com/tutorial/path-params/#predefined-values" target="_blank">the same way as with *path parameters*</a>.
You could also use `Enum`s the same way as with [Path Parameters](path-params.md#predefined-values){.internal-link target=_blank}.
## Optional type declarations

View File

@@ -1,7 +1,7 @@
You can define files to be uploaded by the client using `File`.
!!! info
To receive uploaded files, first install [`python-multipart`](https://andrew-d.github.io/python-multipart/).
To receive uploaded files, first install <a href="https://andrew-d.github.io/python-multipart/" class="external-link" target="_blank">`python-multipart`</a>.
E.g. `pip install python-multipart`.
@@ -26,9 +26,9 @@ Create file parameters the same way you would for `Body` or `Form`:
!!! info
`File` is a class that inherits directly from `Form`.
But remember that when you import `Query`, `Path`, `File` and others from `fastapi`, <a href="https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#recap" target="_blank">those are actually functions that return classes of the same name</a>.
But remember that when you import `Query`, `Path`, `File` and others from `fastapi`, those are actually functions that return special classes.
!!! info
!!! tip
To declare File bodies, you need to use `File`, because otherwise the parameters would be interpreted as query parameters or body (JSON) parameters.
The files will be uploaded as "form data".
@@ -39,7 +39,6 @@ Have in mind that this means that the whole contents will be stored in memory. T
But there are several cases in where you might benefit from using `UploadFile`.
## `File` parameters with `UploadFile`
Define a `File` parameter with a type of `UploadFile`:
@@ -54,9 +53,8 @@ Using `UploadFile` has several advantages over `bytes`:
* A file stored in memory up to a maximum size limit, and after passing this limit it will be stored in disk.
* This means that it will work well for large files like images, videos, large binaries, etc. without consuming all the memory.
* You can get metadata from the uploaded file.
* It has a <a href="https://docs.python.org/3/glossary.html#term-file-like-object" target="_blank">file-like</a> `async` interface.
* It exposes an actual Python <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" target="_blank">`SpooledTemporaryFile`</a> object that you can pass directly to other libraries that expect a file-like object.
* It has a <a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> `async` interface.
* It exposes an actual Python <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a> object that you can pass directly to other libraries that expect a file-like object.
### `UploadFile`
@@ -64,8 +62,7 @@ Using `UploadFile` has several advantages over `bytes`:
* `filename`: A `str` with the original file name that was uploaded (e.g. `myimage.jpg`).
* `content_type`: A `str` with the content type (MIME type / media type) (e.g. `image/jpeg`).
* `file`: A <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" target="_blank">`SpooledTemporaryFile`</a> (a <a href="https://docs.python.org/3/glossary.html#term-file-like-object" target="_blank">file-like</a> object). This is the actual Python file that you can pass directly to other functions or libraries that expect a "file-like" object.
* `file`: A <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a> (a <a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> object). This is the actual Python file that you can pass directly to other functions or libraries that expect a "file-like" object.
`UploadFile` has the following `async` methods. They all call the corresponding file methods underneath (using the internal `SpooledTemporaryFile`).
@@ -93,11 +90,10 @@ contents = myfile.file.read()
!!! note "`async` Technical Details"
When you use the `async` methods, **FastAPI** runs the file methods in a threadpool and awaits for them.
!!! note "Starlette Technical Details"
**FastAPI**'s `UploadFile` inherits directly from **Starlette**'s `UploadFile`, but adds some necessary parts to make it compatible with **Pydantic** and the other parts of FastAPI.
## "Form Data"?
## What is "Form Data"
The way HTML forms (`<form></form>`) sends the data to the server normally uses a "special" encoding for that data, it's different from JSON.
@@ -108,11 +104,10 @@ The way HTML forms (`<form></form>`) sends the data to the server normally uses
But when the form includes files, it is encoded as `multipart/form-data`. If you use `File`, **FastAPI** will know it has to get the files from the correct part of the body.
If you want to read more about these encodings and form fields, head to the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> web docs for <code>POST</code></a>.
If you want to read more about these encodings and form fields, head to the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> web docs for <code>POST</code></a>.
!!! warning
You can declare multiple `File` and `Form` parameters in a path operation, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `multipart/form-data` instead of `application/json`.
You can declare multiple `File` and `Form` parameters in a *path operation*, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `multipart/form-data` instead of `application/json`.
This is not a limitation of **FastAPI**, it's part of the HTTP protocol.
@@ -131,7 +126,7 @@ To use that, declare a `List` of `bytes` or `UploadFile`:
You will receive, as declared, a `list` of `bytes` or `UploadFile`s.
!!! note
Notice that, as of 2019-04-14, Swagger UI doesn't support multiple file uploads in the same form field. For more information, check <a href="https://github.com/swagger-api/swagger-ui/issues/4276" target="_blank">#4276</a> and <a href="https://github.com/swagger-api/swagger-ui/issues/3641" target="_blank">#3641</a>.
Notice that, as of 2019-04-14, Swagger UI doesn't support multiple file uploads in the same form field. For more information, check <a href="https://github.com/swagger-api/swagger-ui/issues/4276" class="external-link" target="_blank">#4276</a> and <a href="https://github.com/swagger-api/swagger-ui/issues/3641" class="external-link" target="_blank">#3641</a>.
Nevertheless, **FastAPI** is already compatible with it, using the standard OpenAPI.

View File

@@ -1,7 +1,7 @@
You can define files and form fields at the same time using `File` and `Form`.
!!! info
To receive uploaded files and/or form data, first install [`python-multipart`](https://andrew-d.github.io/python-multipart/).
To receive uploaded files and/or form data, first install <a href="https://andrew-d.github.io/python-multipart/" class="external-link" target="_blank">`python-multipart`</a>.
E.g. `pip install python-multipart`.
@@ -24,7 +24,7 @@ The files and form fields will be uploaded as form data and you will receive the
And you can declare some of the files as `bytes` and some as `UploadFile`.
!!! warning
You can declare multiple `File` and `Form` parameters in a path operation, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `multipart/form-data` instead of `application/json`.
You can declare multiple `File` and `Form` parameters in a *path operation*, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `multipart/form-data` instead of `application/json`.
This is not a limitation of **FastAPI**, it's part of the HTTP protocol.

View File

@@ -1,7 +1,7 @@
When you need to receive form fields instead of JSON, you can use `Form`.
!!! info
To use forms, first install [`python-multipart`](https://andrew-d.github.io/python-multipart/).
To use forms, first install <a href="https://andrew-d.github.io/python-multipart/" class="external-link" target="_blank">`python-multipart`</a>.
E.g. `pip install python-multipart`.
@@ -30,10 +30,10 @@ With `Form` you can declare the same metadata and validation as with `Body` (and
!!! info
`Form` is a class that inherits directly from `Body`.
!!! info
!!! tip
To declare form bodies, you need to use `Form` explicitly, because without it the parameters would be interpreted as query parameters or body (JSON) parameters.
## "Form Fields"?
## About "Form Fields"
The way HTML forms (`<form></form>`) sends the data to the server normally uses a "special" encoding for that data, it's different from JSON.
@@ -44,11 +44,10 @@ The way HTML forms (`<form></form>`) sends the data to the server normally uses
But when the form includes files, it is encoded as `multipart/form-data`. You'll read about handling files in the next chapter.
If you want to read more about these encodings and form fields, head to the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> web docs for <code>POST</code></a>.
If you want to read more about these encodings and form fields, head to the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> web docs for <code>POST</code></a>.
!!! warning
You can declare multiple `Form` parameters in a path operation, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `application/x-www-form-urlencoded` instead of `application/json`.
You can declare multiple `Form` parameters in a *path operation*, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `application/x-www-form-urlencoded` instead of `application/json`.
This is not a limitation of **FastAPI**, it's part of the HTTP protocol.

View File

@@ -1,4 +1,4 @@
You can declare the model used for the response with the parameter `response_model` in any of the path operations:
You can declare the model used for the response with the parameter `response_model` in any of the *path operations*:
* `@app.get()`
* `@app.post()`
@@ -11,7 +11,7 @@ You can declare the model used for the response with the parameter `response_mod
```
!!! note
Notice that `response_model` is a parameter of the "decorator" method (`get`, `post`, etc). Not of your path operation function, like all the parameters and body.
Notice that `response_model` is a parameter of the "decorator" method (`get`, `post`, etc). Not of your *path operation function*, like all the parameters and body.
It receives the same type you would declare for a Pydantic model attribute, so, it can be a Pydantic model, but it can also be, e.g. a `list` of Pydantic models, like `List[Item]`.
@@ -19,7 +19,7 @@ FastAPI will use this `response_model` to:
* Convert the output data to its type declaration.
* Validate the data.
* Add a JSON Schema for the response, in the OpenAPI path operation.
* Add a JSON Schema for the response, in the OpenAPI *path operation*.
* Will be used by the automatic documentation systems.
But most importantly:
@@ -47,7 +47,7 @@ Now, whenever a browser is creating a user with a password, the API will return
In this case, it might not be a problem, because the user himself is sending the password.
But if we use the same model for another path operation, we could be sending our user's passwords to every client.
But if we use the same model for another *path operation*, we could be sending our user's passwords to every client.
!!! danger
Never send the plain password of a user in a response.
@@ -60,7 +60,7 @@ We can instead create an input model with the plaintext password and an output m
{!./src/response_model/tutorial003.py!}
```
Here, even though our path operation function is returning the same input user that contains the password:
Here, even though our *path operation function* is returning the same input user that contains the password:
```Python hl_lines="22"
{!./src/response_model/tutorial003.py!}
@@ -120,7 +120,7 @@ So, if you send a request to that *path operation* for the item with ID `foo`, t
```
!!! info
FastAPI uses Pydantic model's `.dict()` with <a href="https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeldict" target="_blank">its `exclude_unset` parameter</a> to achieve this.
FastAPI uses Pydantic model's `.dict()` with <a href="https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeldict" class="external-link" target="_blank">its `exclude_unset` parameter</a> to achieve this.
#### Data with values for fields with defaults
@@ -192,6 +192,6 @@ If you forget to use a `set` and use a `list` or `tuple` instead, FastAPI will s
## Recap
Use the path operation decorator's parameter `response_model` to define response models and especially to ensure private data is filtered out.
Use the *path operation decorator's* parameter `response_model` to define response models and especially to ensure private data is filtered out.
Use `response_model_exclude_unset` to return only the values explicitly set.

View File

@@ -1,4 +1,4 @@
The same way you can specify a response model, you can also declare the HTTP status code used for the response with the parameter `status_code` in any of the path operations:
The same way you can specify a response model, you can also declare the HTTP status code used for the response with the parameter `status_code` in any of the *path operations*:
* `@app.get()`
* `@app.post()`
@@ -11,7 +11,7 @@ The same way you can specify a response model, you can also declare the HTTP sta
```
!!! note
Notice that `status_code` is a parameter of the "decorator" method (`get`, `post`, etc). Not of your path operation function, like all the parameters and body.
Notice that `status_code` is a parameter of the "decorator" method (`get`, `post`, etc). Not of your *path operation function*, like all the parameters and body.
The `status_code` parameter receives a number with the HTTP status code.
@@ -50,7 +50,7 @@ In short:
* `500` and above are for server errors. You almost never use them directly. When something goes wrong at some part in your application code, or server, it will automatically return one of these status codes.
!!! tip
To know more about each status code and which code is for what, check the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> documentation about HTTP status codes</a>.
To know more about each status code and which code is for what, check the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> documentation about HTTP status codes</a>.
## Shortcut to remember the names
@@ -76,4 +76,4 @@ They are just a convenience, they hold the same number, but that way you can use
## Changing the default
Later, in a more advanced part of the tutorial/user guide, you will see how to <a href="https://fastapi.tiangolo.com/tutorial/response-change-status-code/" target="_blank">return a different status code than the default</a> you are declaring here.
Later, in the **Advanced User Guide**, you will see how to return a different status code than the default you are declaring here.

View File

@@ -25,7 +25,7 @@ Copy the example in a file `main.py`:
## Run it
!!! info
First install [`python-multipart`](https://andrew-d.github.io/python-multipart/).
First install <a href="https://andrew-d.github.io/python-multipart/" class="external-link" target="_blank">`python-multipart`</a>.
E.g. `pip install python-multipart`.
@@ -39,7 +39,7 @@ uvicorn main:app --reload
## Check it
Go to the interactive docs at: <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
Go to the interactive docs at: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
You will see something like this:
@@ -48,8 +48,7 @@ You will see something like this:
!!! check "Authorize button!"
You already have a shinny new "Authorize" button.
And your path operation has a little lock in the top-right corner that you can click.
And your *path operation* has a little lock in the top-right corner that you can click.
And if you click it, you have a little authorization form to type a `username` and `password` (and other optional fields):
@@ -66,7 +65,6 @@ It can be used by third party applications and systems.
And it can also be used by yourself, to debug, check and test the same application.
## The `password` flow
Now let's go back a bit and understand what is all that.
@@ -99,10 +97,9 @@ So, let's review it from that simplified point of view:
In this example we are going to use **OAuth2**, with the **Password** flow, using a **Bearer** token.
!!! info
A "bearer" token is not the only option.
But it's the best one for our use case.
And it might be the best for most use cases, unless you are an OAuth2 expert and know exactly why there's another option that suits better your needs.
@@ -115,7 +112,7 @@ In this example we are going to use **OAuth2**, with the **Password** flow, usin
{!./src/security/tutorial001.py!}
```
It doesn't create that endpoint / path operation, but declares that that URL is the one that the client should use to get the token. That information is used in OpenAPI, and then in the interactive API documentation systems.
It doesn't create that endpoint / *path operation*, but declares that that URL is the one that the client should use to get the token. That information is used in OpenAPI, and then in the interactive API documentation systems.
!!! info
If you are a very strict "Pythonista" you might dislike the style of the parameter name `tokenUrl` instead of `token_url`.

View File

@@ -1,4 +1,4 @@
In the previous chapter the security system (which is based on the dependency injection system) was giving the path operation function a `token` as a `str`:
In the previous chapter the security system (which is based on the dependency injection system) was giving the *path operation function* a `token` as a `str`:
```Python hl_lines="10"
{!./src/security/tutorial001.py!}
@@ -26,7 +26,7 @@ Remember that dependencies can have sub-dependencies?
`get_current_user` will have a dependency with the same `oauth2_scheme` we created before.
The same as we were doing before in the path operation directly, our new dependency `get_current_user` will receive a `token` as a `str` from the sub-dependency `oauth2_scheme`:
The same as we were doing before in the *path operation* directly, our new dependency `get_current_user` will receive a `token` as a `str` from the sub-dependency `oauth2_scheme`:
```Python hl_lines="25"
{!./src/security/tutorial002.py!}
@@ -42,7 +42,7 @@ The same as we were doing before in the path operation directly, our new depende
## Inject the current user
So now we can use the same `Depends` with our `get_current_user` in the path operation:
So now we can use the same `Depends` with our `get_current_user` in the *path operation*:
```Python hl_lines="31"
{!./src/security/tutorial002.py!}
@@ -65,7 +65,7 @@ This will help us inside of the function with all the completion and type checks
## Other models
You can now get the current user directly in the path operation functions and deal with the security mechanisms at the **Dependency Injection** level, using `Depends`.
You can now get the current user directly in the *path operation functions* and deal with the security mechanisms at the **Dependency Injection** level, using `Depends`.
And you can use any model or data for the security requirements (in this case, a Pydantic model `User`).
@@ -82,7 +82,7 @@ Just use any kind of model, any kind of class, any kind of database that you nee
## Code size
This example might seem verbose. Have in mind that we are mixing security, data models utility functions and path operations in the same file.
This example might seem verbose. Have in mind that we are mixing security, data models utility functions and *path operations* in the same file.
But here's the key point.
@@ -90,11 +90,11 @@ The security and dependency injection stuff is written once.
And you can make it as complex as you want. And still, have it written only once, in a single place. With all the flexibility.
But you can have thousands of endpoints (path operations) using the same security system.
But you can have thousands of endpoints (*path operations*) using the same security system.
And all of them (or any portion of them that you want) can take the advantage of re-using these dependencies or any other dependencies you create.
And all these thousands of path operations can be as small as 3 lines:
And all these thousands of *path operations* can be as small as 3 lines:
```Python hl_lines="30 31 32"
{!./src/security/tutorial002.py!}
@@ -102,10 +102,10 @@ And all these thousands of path operations can be as small as 3 lines:
## Recap
You can now get the current user directly in your path operation function.
You can now get the current user directly in your *path operation function*.
We are already halfway there.
We just need to add a path operation for the user/client to actually send the `username` and `password`.
We just need to add a *path operation* for the user/client to actually send the `username` and `password`.
That comes next.
That comes next.

View File

@@ -1,40 +0,0 @@
For the simplest cases, you can use HTTP Basic Auth.
In HTTP Basic Auth, the application expects a header that contains a username and a password.
If it doesn't receive it, it returns an HTTP 401 "Unauthorized" error.
And returns a header `WWW-Authenticate` with a value of `Basic`, and an optional `realm` parameter.
That tells the browser to show the integrated prompt for a username and password.
Then, when you type that username and password, the browser sends them in the header automatically.
## Simple HTTP Basic Auth
* Import `HTTPBasic` and `HTTPBasicCredentials`.
* Create a "`security` scheme" using `HTTPBasic`.
* Use that `security` with a dependency in your *path operation*.
* It returns an object of type `HTTPBasicCredentials`:
* It contains the `username` and `password` sent.
```Python hl_lines="2 6 10"
{!./src/security/tutorial006.py!}
```
When you try to open the URL for the first time (or click the "Execute" button in the docs) the browser will ask you for your username and password:
<img src="/img/tutorial/security/image12.png">
## Check the username
Here's a more complete example.
Use a dependency to check if the username and password are correct.
If the credentials are incorrect, return an `HTTPException` with a status code 401 (the same returned when no credentials are provided) and add the header `WWW-Authenticate` to make the browser show the login prompt again:
```Python hl_lines="10 11 12 13 14 15 16 17 21"
{!./src/security/tutorial007.py!}
```

View File

@@ -18,11 +18,11 @@ It is not encrypted, so, anyone could recover the information from the contents.
But it's signed. So, when you receive a token that you emitted, you can verify that you actually emitted it.
That way, you can create a token with an expiration of, let's say, 1 week, and then, after a week, when the user comes back with the token, you know he's still signed into your system.
That way, you can create a token with an expiration of, let's say, 1 week. And then when the user comes back the next day with the token, you know she/he is still signed into your system.
And after a week, the token will be expired. And if the user (or a third party) tried to modify the token to change the expiration, you would be able to discover it, because the signatures would not match.
And after a week, the token will be expired and the user will not be authorized and will have to sign in again to get a new token. And if the user (or a third party) tried to modify the token to change the expiration, you would be able to discover it, because the signatures would not match.
If you want to play with JWT tokens and see how they work, check <a href="https://jwt.io/" target="_blank">https://jwt.io</a>.
If you want to play with JWT tokens and see how they work, check <a href="https://jwt.io/" class="external-link" target="_blank">https://jwt.io</a>.
## Install `PyJWT`
@@ -40,7 +40,7 @@ Whenever you pass exactly the same content (exactly the same password) you get e
But you cannot convert from the gibberish back to the password.
### What for?
### Why use password hashing
If your database is stolen, the thief won't have your users' plaintext passwords, only the hashes.
@@ -131,7 +131,7 @@ If the token is invalid, return an HTTP error right away.
{!./src/security/tutorial004.py!}
```
## Update the `/token` path operation
## Update the `/token` *path operation*
Create a `timedelta` with the expiration time of the token.
@@ -141,7 +141,6 @@ Create a real JWT access token and return it.
{!./src/security/tutorial004.py!}
```
### Technical details about the JWT "subject" `sub`
The JWT specification says that there's a key `sub`, with the subject of the token.
@@ -166,7 +165,7 @@ The important thing to have in mind is that the `sub` key should have a unique i
## Check it
Run the server and go to the docs: <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
Run the server and go to the docs: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
You'll see the user interface like:
@@ -212,7 +211,7 @@ You can use them to add a specific set of permissions to a JWT token.
Then you can give this token to a user directly or a third party, to interact with your API with a set of restrictions.
You can learn how to use them and how they are integrated into **FastAPI** in the next chapter.
You can learn how to use them and how they are integrated into **FastAPI** later in the **Advanced User Guide**.
## Recap
@@ -230,10 +229,8 @@ It gives you all the flexibility to choose the ones that fit your project the be
And you can use directly many well maintained and widely used packages like `passlib` and `pyjwt`, because **FastAPI** doesn't require any complex mechanisms to integrate external packages.
But it provides you the tools to simplify the process as much as possible without compromising flexibility, robustness or security.
But it provides you the tools to simplify the process as much as possible without compromising flexibility, robustness, or security.
And you can use and implement secure, standard protocols, like OAuth2 in a relatively simple way.
In the next (optional) section you can see how to extend this even further, using OAuth2 "scopes", for a more fine-grained permission system, following these same standards.
OAuth2 with scopes (explained in the next section) is the mechanism used by many big authentication providers, like Facebook, Google, GitHub, Microsoft, Twitter, etc.
You can learn more in the **Advanced User Guide** about how to use OAuth2 "scopes", for a more fine-grained permission system, following these same standards. OAuth2 with scopes is the mechanism used by many big authentication providers, like Facebook, Google, GitHub, Microsoft, Twitter, etc. to authorize third party applications to interact with their APIs on behalf of their users.

Some files were not shown because too many files have changed in this diff Show More