* :globe_with_meridians: Refactor file structure to support internationalization
* :white_check_mark: Update tests changed after i18n
* :twisted_rightwards_arrows: Merge Typer style from master
* :wrench: Update MkConfig with Typer-styles
* :art: Format mkdocs.yml with cannonical form
* :art: Format mkdocs.yml
* :wrench: Update MkDocs config
* :heavy_plus_sign: Add docs translation scripts dependencies
* :sparkles: Add Typer scripts to handle translations
* :sparkles: Add missing translation snippet to include
* :sparkles: Update contributing docs, add docs for translations
* :see_no_evil: Add docs_build to gitignore
* :wrench: Update scripts with new locations and docs scripts
* :construction_worker: Update docs deploy action with translations
* :memo: Add note about languages not supported in the theme
* :sparkles: Add first translation, for Spanish
run: python3.7 -m pip install flit
- name: Install docs extras
run: python3.7 -m flit install --extras doc
- - name: Build MkDocs
- run: python3.7 -m mkdocs build
+ - name: Build Docs
+ run: python3.7 ./scripts/docs.py build-all
- name: Deploy to Netlify
uses: nwtgck/actions-netlify@v1.0.3
with:
log.txt
Pipfile.lock
env3.*
+docs_build
+++ /dev/null
-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`
-
-You can create a virtual environment in a directory using Python's `venv` module:
-
-```console
-$ python -m venv env
-```
-
-That will create a directory `./env/` with the Python binaries and then you will be able to install packages for that isolated environment.
-
-### Activate the environment
-
-Activate the new environment with:
-
-```console
-$ source ./env/bin/activate
-```
-
-Or in Windows' PowerShell:
-
-```console
-$ .\env\Scripts\Activate.ps1
-```
-
-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" class="external-link" target="_blank">Flit</a> to build, package and publish the project.
-
-After activating the environment as described above, install `flit`:
-
-```console
-$ pip install flit
-```
-
-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
-
-If you create a Python file that imports and uses FastAPI, and run it with the Python from your local environment, it will use your local FastAPI source code.
-
-And if you update that local FastAPI source code, as it is installed with `--symlink`, when you run that Python file again, it will use the fresh version of FastAPI you just edited.
-
-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:
-
-```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:
-
-```console
-$ flit install --symlink
-```
-
-### Format imports
-
-There is another script that formats all the imports and makes sure you don't have unused imports:
-
-```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`.
-
-Many of the tutorials have blocks of code.
-
-In most of the cases, these blocks of code are actual complete applications that can be run as is.
-
-In fact, those blocks of code are not written inside the Markdown, they are Python files in the `./docs/src/` directory.
-
-And those Python files are included/injected in the documentation when generating the site.
-
-### Docs for tests
-
-Most of the tests actually run against the example source files in the documentation.
-
-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 test coverage.
-
-During local development, there is a script that builds the site and checks for any changes, live-reloading:
-
-```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
-
-If you run the examples with, e.g.:
-
-```console
-$ uvicorn tutorial001:app --reload
-```
-
-as Uvicorn by default will use the port `8000`, the documentation on port `8008` won't clash.
-
-## Tests
-
-There is a script that you can run locally to test all the code and generate coverage reports in HTML:
-
-```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
-```
+# Additional Responses in OpenAPI
+
!!! warning
This is a rather advanced topic.
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!}
+{!../../../docs_src/additional_responses/tutorial001.py!}
```
!!! note
For example, you can add an additional media type of `image/png`, declaring that your *path operation* can return a JSON object (with media type `application/json`) or a PNG image:
```Python hl_lines="17 18 19 20 21 22 23 24 28"
-{!./src/additional_responses/tutorial002.py!}
+{!../../../docs_src/additional_responses/tutorial002.py!}
```
!!! note
And a response with a status code `200` that uses your `response_model`, but includes a custom `example`:
```Python hl_lines="20 21 22 23 24 25 26 27 28 29 30 31"
-{!./src/additional_responses/tutorial003.py!}
+{!../../../docs_src/additional_responses/tutorial003.py!}
```
It will all be combined and included in your OpenAPI, and shown in the API docs:
For example:
```Python hl_lines="11 12 13 14 15 24"
-{!./src/additional_responses/tutorial004.py!}
+{!../../../docs_src/additional_responses/tutorial004.py!}
```
## More information about OpenAPI responses
+# Additional Status Codes
+
By default, **FastAPI** will return the responses using a `JSONResponse`, putting the content you return from your *path operation* inside of that `JSONResponse`.
It will use the default status code or the one you set in your *path operation*.
To achieve that, import `JSONResponse`, and return your content there directly, setting the `status_code` that you want:
```Python hl_lines="2 19"
-{!./src/additional_status_codes/tutorial001.py!}
+{!../../../docs_src/additional_status_codes/tutorial001.py!}
```
!!! warning
+# Advanced Dependencies
+
## Parameterized dependencies
All the dependencies we have seen are a fixed function or class.
To do that, we declare a method `__call__`:
```Python hl_lines="10"
-{!./src/dependencies/tutorial011.py!}
+{!../../../docs_src/dependencies/tutorial011.py!}
```
In this case, this `__call__` is what **FastAPI** will use to check for additional parameters and sub-dependencies, and this is what will be called to pass a value to the parameter in your *path operation function* later.
And now, we can use `__init__` to declare the parameters of the instance that we can use to "parameterize" the dependency:
```Python hl_lines="7"
-{!./src/dependencies/tutorial011.py!}
+{!../../../docs_src/dependencies/tutorial011.py!}
```
In this case, **FastAPI** won't ever touch or care about `__init__`, we will use it directly in our code.
We could create an instance of this class with:
```Python hl_lines="16"
-{!./src/dependencies/tutorial011.py!}
+{!../../../docs_src/dependencies/tutorial011.py!}
```
And that way we are able to "parameterize" our dependency, that now has `"bar"` inside of it, as the attribute `checker.fixed_content`.
...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!}
+{!../../../docs_src/dependencies/tutorial011.py!}
```
!!! tip
+# Async SQL (Relational) Databases
+
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:
* Create a table `notes` using the `metadata` object.
```Python hl_lines="4 14 16 17 18 19 20 21 22"
-{!./src/async_sql_databases/tutorial001.py!}
+{!../../../docs_src/async_sql_databases/tutorial001.py!}
```
!!! tip
* Create a `database` object.
```Python hl_lines="3 9 12"
-{!./src/async_sql_databases/tutorial001.py!}
+{!../../../docs_src/async_sql_databases/tutorial001.py!}
```
!!! tip
* Create all the tables from the `metadata` object.
```Python hl_lines="25 26 27 28"
-{!./src/async_sql_databases/tutorial001.py!}
+{!../../../docs_src/async_sql_databases/tutorial001.py!}
```
## Create models
* Notes to be returned (`Note`).
```Python hl_lines="31 32 33 36 37 38 39"
-{!./src/async_sql_databases/tutorial001.py!}
+{!../../../docs_src/async_sql_databases/tutorial001.py!}
```
By creating these Pydantic models, the input data will be validated, serialized (converted), and annotated (documented).
* Create event handlers to connect and disconnect from the database.
```Python hl_lines="42 45 46 47 50 51 52"
-{!./src/async_sql_databases/tutorial001.py!}
+{!../../../docs_src/async_sql_databases/tutorial001.py!}
```
## Read notes
Create the *path operation function* to read notes:
```Python hl_lines="55 56 57 58"
-{!./src/async_sql_databases/tutorial001.py!}
+{!../../../docs_src/async_sql_databases/tutorial001.py!}
```
!!! Note
Create the *path operation function* to create notes:
```Python hl_lines="61 62 63 64 65"
-{!./src/async_sql_databases/tutorial001.py!}
+{!../../../docs_src/async_sql_databases/tutorial001.py!}
```
!!! Note
+# Custom Request and APIRoute class
+
In some cases, you may want to override the logic used by the `Request` and `APIRoute` classes.
In particular, this may be a good alternative to logic in a middleware.
That way, the same route class can handle gzip compressed or uncompressed requests.
```Python hl_lines="8 9 10 11 12 13 14 15"
-{!./src/custom_request_and_route/tutorial001.py!}
+{!../../../docs_src/custom_request_and_route/tutorial001.py!}
```
### Create a custom `GzipRoute` class
Here we use it to create a `GzipRequest` from the original request.
```Python hl_lines="18 19 20 21 22 23 24 25 26"
-{!./src/custom_request_and_route/tutorial001.py!}
+{!../../../docs_src/custom_request_and_route/tutorial001.py!}
```
!!! note "Technical Details"
All we need to do is handle the request inside a `try`/`except` block:
```Python hl_lines="13 15"
-{!./src/custom_request_and_route/tutorial002.py!}
+{!../../../docs_src/custom_request_and_route/tutorial002.py!}
```
If an exception occurs, the`Request` instance will still be in scope, so we can read and make use of the request body when handling the error:
```Python hl_lines="16 17 18"
-{!./src/custom_request_and_route/tutorial002.py!}
+{!../../../docs_src/custom_request_and_route/tutorial002.py!}
```
## Custom `APIRoute` class in a router
You can also set the `route_class` parameter of an `APIRouter`:
```Python hl_lines="26"
-{!./src/custom_request_and_route/tutorial003.py!}
+{!../../../docs_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="13 14 15 16 17 18 19 20"
-{!./src/custom_request_and_route/tutorial003.py!}
+{!../../../docs_src/custom_request_and_route/tutorial003.py!}
```
+# Custom Response - HTML, Stream, File, others
+
By default, **FastAPI** will return the responses using `JSONResponse`.
You can override it by returning a `Response` directly as seen in [Return a Response directly](response-directly.md){.internal-link target=_blank}.
Import the `Response` class (sub-class) you want to use and declare it in the *path operation decorator*.
```Python hl_lines="2 7"
-{!./src/custom_response/tutorial001b.py!}
+{!../../../docs_src/custom_response/tutorial001b.py!}
```
!!! info
* Pass `HTMLResponse` as the parameter `content_type` of your *path operation*.
```Python hl_lines="2 7"
-{!./src/custom_response/tutorial002.py!}
+{!../../../docs_src/custom_response/tutorial002.py!}
```
!!! info
The same example from above, returning an `HTMLResponse`, could look like:
```Python hl_lines="2 7 19"
-{!./src/custom_response/tutorial003.py!}
+{!../../../docs_src/custom_response/tutorial003.py!}
```
!!! warning
For example, it could be something like:
```Python hl_lines="7 23 21"
-{!./src/custom_response/tutorial004.py!}
+{!../../../docs_src/custom_response/tutorial004.py!}
```
In this example, the function `generate_html_response()` already generates and returns a `Response` instead of returning the HTML in a `str`.
FastAPI (actually Starlette) will automatically include a Content-Length header. It will also include a Content-Type header, based on the media_type and appending a charset for text types.
```Python hl_lines="1 18"
-{!./src/response_directly/tutorial002.py!}
+{!../../../docs_src/response_directly/tutorial002.py!}
```
### `HTMLResponse`
Takes some text or bytes and returns an plain text response.
```Python hl_lines="2 7 9"
-{!./src/custom_response/tutorial005.py!}
+{!../../../docs_src/custom_response/tutorial005.py!}
```
### `JSONResponse`
`ujson` is less careful than Python's built-in implementation in how it handles some edge-cases.
```Python hl_lines="2 7"
-{!./src/custom_response/tutorial001.py!}
+{!../../../docs_src/custom_response/tutorial001.py!}
```
!!! tip
Returns an HTTP redirect. Uses a 307 status code (Temporary Redirect) by default.
```Python hl_lines="2 9"
-{!./src/custom_response/tutorial006.py!}
+{!../../../docs_src/custom_response/tutorial006.py!}
```
### `StreamingResponse`
Takes an async generator or a normal generator/iterator and streams the response body.
```Python hl_lines="2 14"
-{!./src/custom_response/tutorial007.py!}
+{!../../../docs_src/custom_response/tutorial007.py!}
```
#### Using `StreamingResponse` with file-like objects
This includes many libraries to interact with cloud storage, video processing, and others.
```Python hl_lines="2 10 11"
-{!./src/custom_response/tutorial008.py!}
+{!../../../docs_src/custom_response/tutorial008.py!}
```
!!! tip
File responses will include appropriate `Content-Length`, `Last-Modified` and `ETag` headers.
```Python hl_lines="2 10"
-{!./src/custom_response/tutorial009.py!}
+{!../../../docs_src/custom_response/tutorial009.py!}
```
## Additional documentation
+# Events: startup - shutdown
You can define event handlers (functions) that need to be executed before the application starts up, or when the application is shutting down.
To add a function that should be run before the application starts, declare it with the event `"startup"`:
```Python hl_lines="8"
-{!./src/events/tutorial001.py!}
+{!../../../docs_src/events/tutorial001.py!}
```
In this case, the `startup` event handler function will initialize the items "database" (just a `dict`) with some values.
To add a function that should be run when the application is shutting down, declare it with the event `"shutdown"`:
```Python hl_lines="6"
-{!./src/events/tutorial002.py!}
+{!../../../docs_src/events/tutorial002.py!}
```
Here, the `shutdown` event handler function will write a text line `"Application shutdown"` to a file `log.txt`.
+# Extending OpenAPI
+
!!! warning
This is a rather advanced feature. You probably can skip it.
First, write all your **FastAPI** application as normally:
```Python hl_lines="1 4 7 8 9"
-{!./src/extending_openapi/tutorial001.py!}
+{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### Generate the OpenAPI schema
Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function:
```Python hl_lines="2 15 16 17 18 19 20"
-{!./src/extending_openapi/tutorial001.py!}
+{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### Modify the OpenAPI schema
Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema:
```Python hl_lines="21 22 23"
-{!./src/extending_openapi/tutorial001.py!}
+{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### Cache the OpenAPI schema
It will be generated only once, and then the same cached schema will be used for the next requests.
```Python hl_lines="13 14 24 25"
-{!./src/extending_openapi/tutorial001.py!}
+{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### Override the method
Now you can replace the `.openapi()` method with your new function.
```Python hl_lines="28"
-{!./src/extending_openapi/tutorial001.py!}
+{!../../../docs_src/extending_openapi/tutorial001.py!}
```
### Check it
* "Mount" a `StaticFiles()` instance in a specific path.
```Python hl_lines="7 11"
-{!./src/extending_openapi/tutorial002.py!}
+{!../../../docs_src/extending_openapi/tutorial002.py!}
```
### Test the static files
To disable them, set their URLs to `None` when creating your `FastAPI` app:
```Python hl_lines="9"
-{!./src/extending_openapi/tutorial002.py!}
+{!../../../docs_src/extending_openapi/tutorial002.py!}
```
### Include the custom docs
And similarly for ReDoc...
```Python hl_lines="2 3 4 5 6 14 15 16 17 18 19 20 21 22 25 26 27 30 31 32 33 34 35 36"
-{!./src/extending_openapi/tutorial002.py!}
+{!../../../docs_src/extending_openapi/tutorial002.py!}
```
!!! tip
Now, to be able to test that everything works, create a *path operation*:
```Python hl_lines="39 40 41"
-{!./src/extending_openapi/tutorial002.py!}
+{!../../../docs_src/extending_openapi/tutorial002.py!}
```
### Test it
+# GraphQL
**FastAPI** has optional support for GraphQL (provided by Starlette directly), using the `graphene` library.
Import `graphene` and define your GraphQL data:
```Python hl_lines="1 6 7 8 9 10"
-{!./src/graphql/tutorial001.py!}
+{!../../../docs_src/graphql/tutorial001.py!}
```
## Add Starlette's `GraphQLApp`
Then import and add Starlette's `GraphQLApp`:
```Python hl_lines="3 14"
-{!./src/graphql/tutorial001.py!}
+{!../../../docs_src/graphql/tutorial001.py!}
```
!!! info
+# Advanced User Guide - Intro
+
## 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**.
+# Advanced Middleware
+
In the main tutorial you read how to add [Custom Middleware](../tutorial/middleware.md){.internal-link target=_blank} to your application.
And then you also read how to handle [CORS with the `CORSMiddleware`](../tutorial/cors.md){.internal-link target=_blank}.
Any incoming requests to `http` or `ws` will be redirected to the secure scheme instead.
```Python hl_lines="2 6"
-{!./src/advanced_middleware/tutorial001.py!}
+{!../../../docs_src/advanced_middleware/tutorial001.py!}
```
## `TrustedHostMiddleware`
Enforces that all incoming requests have a correctly set `Host` header, in order to guard against HTTP Host Header attacks.
```Python hl_lines="2 6 7 8"
-{!./src/advanced_middleware/tutorial002.py!}
+{!../../../docs_src/advanced_middleware/tutorial002.py!}
```
The following arguments are supported:
The middleware will handle both standard and streaming responses.
```Python hl_lines="2 6 7 8"
-{!./src/advanced_middleware/tutorial002.py!}
+{!../../../docs_src/advanced_middleware/tutorial002.py!}
```
The following arguments are supported:
+# NoSQL (Distributed / Big Data) Databases
+
**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/" 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.
For now, don't pay attention to the rest, only the imports:
```Python hl_lines="6 7 8"
-{!./src/nosql_databases/tutorial001.py!}
+{!../../../docs_src/nosql_databases/tutorial001.py!}
```
## Define a constant to use as a "document type"
This is not required by Couchbase, but is a good practice that will help you afterwards.
```Python hl_lines="10"
-{!./src/nosql_databases/tutorial001.py!}
+{!../../../docs_src/nosql_databases/tutorial001.py!}
```
## Add a function to get a `Bucket`
* Return it.
```Python hl_lines="13 14 15 16 17 18 19 20 21 22"
-{!./src/nosql_databases/tutorial001.py!}
+{!../../../docs_src/nosql_databases/tutorial001.py!}
```
## Create Pydantic models
First, let's create a `User` model:
```Python hl_lines="25 26 27 28 29"
-{!./src/nosql_databases/tutorial001.py!}
+{!../../../docs_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 don't create it as a subclass of Pydantic's `BaseModel` but as a subclass of our own `User`, because it will have all the attributes in `User` plus a couple more:
```Python hl_lines="32 33 34"
-{!./src/nosql_databases/tutorial001.py!}
+{!../../../docs_src/nosql_databases/tutorial001.py!}
```
!!! note
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!}
+{!../../../docs_src/nosql_databases/tutorial001.py!}
```
### f-strings
### Create the `FastAPI` app
```Python hl_lines="47"
-{!./src/nosql_databases/tutorial001.py!}
+{!../../../docs_src/nosql_databases/tutorial001.py!}
```
### Create the *path operation function*
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:
```Python hl_lines="50 51 52 53 54"
-{!./src/nosql_databases/tutorial001.py!}
+{!../../../docs_src/nosql_databases/tutorial001.py!}
```
## Recap
+# OpenAPI Callbacks
+
You could create an API with a *path operation* that could trigger a request to an *external API* created by someone else (probably the same developer that would be *using* your API).
The process that happens when your API app calls the *external API* is named a "callback". Because the software that the external developer wrote sends a request to your API and then your API *calls back*, sending a request to an *external API* (that was probably created by the same developer).
This part is pretty normal, most of the code is probably already familiar to you:
```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!}
+{!../../../docs_src/openapi_callbacks/tutorial001.py!}
```
!!! tip
But as we are never calling `app.include_router(some_router)`, we need to set the `default_response_class` during creation of the `APIRouter`.
```Python hl_lines="3 24"
-{!./src/openapi_callbacks/tutorial001.py!}
+{!../../../docs_src/openapi_callbacks/tutorial001.py!}
```
### Create the callback *path operation*
* 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"
-{!./src/openapi_callbacks/tutorial001.py!}
+{!../../../docs_src/openapi_callbacks/tutorial001.py!}
```
There are 2 main differences from a normal *path operation*:
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="34"
-{!./src/openapi_callbacks/tutorial001.py!}
+{!../../../docs_src/openapi_callbacks/tutorial001.py!}
```
!!! tip
+# Path Operation Advanced Configuration
+
## OpenAPI operationId
!!! warning
You would have to make sure that it is unique for each operation.
```Python hl_lines="6"
-{!./src/path_operation_advanced_configuration/tutorial001.py!}
+{!../../../docs_src/path_operation_advanced_configuration/tutorial001.py!}
```
### Using the *path operation function* name as the operationId
You should do it after adding all your *path operations*.
```Python hl_lines="2 12 13 14 15 16 17 18 19 20 21 24"
-{!./src/path_operation_advanced_configuration/tutorial002.py!}
+{!../../../docs_src/path_operation_advanced_configuration/tutorial002.py!}
```
!!! tip
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!}
+{!../../../docs_src/path_operation_advanced_configuration/tutorial003.py!}
```
## Advanced description from docstring
It won't show up in the documentation, but other tools (such as Sphinx) will be able to use the rest.
```Python hl_lines="19 20 21 22 23 24 25 26 27 28 29"
-{!./src/path_operation_advanced_configuration/tutorial004.py!}
+{!../../../docs_src/path_operation_advanced_configuration/tutorial004.py!}
```
+# Response - Change Status Code
+
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.
And then you can set the `status_code` in that *temporal* response object.
```Python hl_lines="1 9 12"
-{!./src/response_change_status_code/tutorial001.py!}
+{!../../../docs_src/response_change_status_code/tutorial001.py!}
```
And then you can return any object you need, as you normally would (a `dict`, a database model, etc).
+# Response Cookies
+
## Use a `Response` parameter
You can declare a parameter of type `Response` in your *path operation function*.
And then you can set cookies in that *temporal* response object.
```Python hl_lines="1 8 9"
-{!./src/response_cookies/tutorial002.py!}
+{!../../../docs_src/response_cookies/tutorial002.py!}
```
And then you can return any object you need, as you normally would (a `dict`, a database model, etc).
Then set Cookies in it, and then return it:
```Python hl_lines="10 11 12"
-{!./src/response_cookies/tutorial001.py!}
+{!../../../docs_src/response_cookies/tutorial001.py!}
```
!!! tip
+# Return a Response Directly
+
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 `jsonable_encoder` explained in [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}.
For those cases, you can use the `jsonable_encoder` to convert your data before passing it to a response:
```Python hl_lines="4 6 20 21"
-{!./src/response_directly/tutorial001.py!}
+{!../../../docs_src/response_directly/tutorial001.py!}
```
!!! note "Technical Details"
You could put your XML content in a string, put it in a `Response`, and return it:
```Python hl_lines="1 18"
-{!./src/response_directly/tutorial002.py!}
+{!../../../docs_src/response_directly/tutorial002.py!}
```
## Notes
+# Response Headers
+
## Use a `Response` 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.
```Python hl_lines="1 7 8"
-{!./src/response_headers/tutorial002.py!}
+{!../../../docs_src/response_headers/tutorial002.py!}
```
And then you can return any object you need, as you normally would (a `dict`, a database model, etc).
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!}
+{!../../../docs_src/response_headers/tutorial001.py!}
```
!!! note "Technical Details"
+# HTTP Basic Auth
+
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.
* It contains the `username` and `password` sent.
```Python hl_lines="2 6 10"
-{!./src/security/tutorial006.py!}
+{!../../../docs_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:
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 11 12 13"
-{!./src/security/tutorial007.py!}
+{!../../../docs_src/security/tutorial007.py!}
```
This will ensure that `credentials.username` is `"stanleyjobson"`, and that `credentials.password` is `"swordfish"`. This would be similar to:
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="15 16 17 18 19"
-{!./src/security/tutorial007.py!}
+{!../../../docs_src/security/tutorial007.py!}
```
+# Advanced Security - Intro
+
## 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}.
+# OAuth2 scopes
+
You can use OAuth2 scopes directly with **FastAPI**, they are integrated to work seamlessly.
This would allow you to have a more fine-grained permission system, following the OAuth2 standard, integrated into your OpenAPI application (and the API docs).
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 47 65 106 108 109 110 111 112 113 114 115 116 122 123 124 125 129 130 131 132 133 134 135 140 154"
-{!./src/security/tutorial005.py!}
+{!../../../docs_src/security/tutorial005.py!}
```
Now let's review those changes step by step.
The `scopes` parameter receives a `dict` with each scope as a key and the description as the value:
```Python hl_lines="63 64 65 66"
-{!./src/security/tutorial005.py!}
+{!../../../docs_src/security/tutorial005.py!}
```
Because we are now declaring those scopes, they will show up in the API docs when you log-in/authorize.
But in your application, for security, you should make sure you only add the scopes that the user is actually able to have, or the ones you have predefined.
```Python hl_lines="155"
-{!./src/security/tutorial005.py!}
+{!../../../docs_src/security/tutorial005.py!}
```
## Declare scopes in *path operations* and dependencies
We are doing it here to demonstrate how **FastAPI** handles scopes declared at different levels.
```Python hl_lines="5 140 167"
-{!./src/security/tutorial005.py!}
+{!../../../docs_src/security/tutorial005.py!}
```
!!! info "Technical Details"
This `SecurityScopes` class is similar to `Request` (`Request` was used to get the request object directly).
```Python hl_lines="9 106"
-{!./src/security/tutorial005.py!}
+{!../../../docs_src/security/tutorial005.py!}
```
## Use the `scopes`
In this exception, we include the scopes required (if any) as a string separated by spaces (using `scope_str`). We put that string containing the scopes in in the `WWW-Authenticate` header (this is part of the spec).
```Python hl_lines="106 108 109 110 111 112 113 114 115 116"
-{!./src/security/tutorial005.py!}
+{!../../../docs_src/security/tutorial005.py!}
```
## Verify the `username` and data shape
We also verify that we have a user with that username, and if not, we raise that same exception we created before.
```Python hl_lines="47 117 118 119 120 121 122 123 124 125 126 127 128"
-{!./src/security/tutorial005.py!}
+{!../../../docs_src/security/tutorial005.py!}
```
## Verify the `scopes`
For this, we use `security_scopes.scopes`, that contains a `list` with all these scopes as `str`.
```Python hl_lines="129 130 131 132 133 134 135"
-{!./src/security/tutorial005.py!}
+{!../../../docs_src/security/tutorial005.py!}
```
## Dependency tree and scopes
+# SQL (Relational) Databases with Peewee
+
!!! 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.
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!}
+{!../../../docs_src/sql_databases_peewee/sql_app/database.py!}
```
!!! tip
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!}
+{!../../../docs_src/sql_databases_peewee/sql_app/database.py!}
```
This class inherits from a special internal class used by Peewee.
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!}
+{!../../../docs_src/sql_databases_peewee/sql_app/database.py!}
```
!!! tip
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!}
+{!../../../docs_src/sql_databases_peewee/sql_app/models.py!}
```
!!! tip
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!}
+{!../../../docs_src/sql_databases_peewee/sql_app/schemas.py!}
```
!!! tip
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!}
+{!../../../docs_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`.
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!}
+{!../../../docs_src/sql_databases_peewee/sql_app/crud.py!}
```
There are some differences with the code for the SQLAlchemy tutorial.
In a very simplistic way create the database tables:
```Python hl_lines="9 10 11"
-{!./src/sql_databases_peewee/sql_app/main.py!}
+{!../../../docs_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="23 24 25 26 27 28 29"
-{!./src/sql_databases_peewee/sql_app/main.py!}
+{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
```
Here we have an empty `yield` because we are actually not using the database object directly.
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="32 40 47 59 65 72"
-{!./src/sql_databases_peewee/sql_app/main.py!}
+{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
```
### Context variable sub-dependency
For that, we need to create another `async` dependency `reset_db_state()` that is used as a sub-dependency in `get_db()`. It will set the value for the context variable (with just a default `dict`) that will be used as the database state for the whole request. And then the dependency `get_db()` will store in it the database state (connection, transactions, etc).
```Python hl_lines="18 19 20"
-{!./src/sql_databases_peewee/sql_app/main.py!}
+{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
```
For the **next request**, as we will reset that context variable again in the `async` dependency `reset_db_state()` and then create a new connection in the `get_db()` dependency, that new request will have its own database state (connection, transactions, etc).
Now, finally, here's the standard **FastAPI** *path operations* code.
```Python hl_lines="32 33 34 35 36 37 40 41 42 43 46 47 48 49 50 51 52 53 56 57 58 59 60 61 62 65 66 67 68 71 72 73 74 75 76 77 78 79"
-{!./src/sql_databases_peewee/sql_app/main.py!}
+{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
```
### About `def` vs `async def`
* `sql_app/database.py`:
```Python
-{!./src/sql_databases_peewee/sql_app/database.py!}
+{!../../../docs_src/sql_databases_peewee/sql_app/database.py!}
```
* `sql_app/models.py`:
```Python
-{!./src/sql_databases_peewee/sql_app/models.py!}
+{!../../../docs_src/sql_databases_peewee/sql_app/models.py!}
```
* `sql_app/schemas.py`:
```Python
-{!./src/sql_databases_peewee/sql_app/schemas.py!}
+{!../../../docs_src/sql_databases_peewee/sql_app/schemas.py!}
```
* `sql_app/crud.py`:
```Python
-{!./src/sql_databases_peewee/sql_app/crud.py!}
+{!../../../docs_src/sql_databases_peewee/sql_app/crud.py!}
```
* `sql_app/main.py`:
```Python
-{!./src/sql_databases_peewee/sql_app/main.py!}
+{!../../../docs_src/sql_databases_peewee/sql_app/main.py!}
```
## Technical Details
+# Sub Applications - Behind a Proxy, Mounts
+
There are at least two situations where you could need to create your **FastAPI** application using some specific paths.
But then you need to set them up to be served with a path prefix.
First, create the main, top-level, **FastAPI** application, and its *path operations*:
```Python hl_lines="3 6 7 8"
-{!./src/sub_applications/tutorial001.py!}
+{!../../../docs_src/sub_applications/tutorial001.py!}
```
### Sub-application
When creating the sub-application, use the parameter `openapi_prefix`. In this case, with a prefix of `/subapi`:
```Python hl_lines="11 14 15 16"
-{!./src/sub_applications/tutorial001.py!}
+{!../../../docs_src/sub_applications/tutorial001.py!}
```
### Mount the sub-application
Here you need to make sure you use the same path that you used for the `openapi_prefix`, in this case, `/subapi`:
```Python hl_lines="11 19"
-{!./src/sub_applications/tutorial001.py!}
+{!../../../docs_src/sub_applications/tutorial001.py!}
```
## Check the automatic API docs
+# Templates
+
You can use any template engine you want with **FastAPI**.
A common election is Jinja2, the same one used by Flask and other tools.
* Use the `templates` you created to render and return a `TemplateResponse`, passing the `request` as one of the key-value pairs in the Jinja2 "context".
```Python hl_lines="3 10 14 15"
-{!./src/templates/tutorial001.py!}
+{!../../../docs_src/templates/tutorial001.py!}
```
!!! note
Then you can write a template at `templates/item.html` with:
```jinja hl_lines="7"
-{!./src/templates/templates/item.html!}
+{!../../../docs_src/templates/templates/item.html!}
```
It will show the `id` taken from the "context" `dict` you passed:
And you can also use `url_for()` inside of the template, and use it, for example, with the `StaticFiles` you mounted.
```jinja hl_lines="4"
-{!./src/templates/templates/item.html!}
+{!../../../docs_src/templates/templates/item.html!}
```
In this example, it would link to a CSS file at `static/styles.css` with:
```CSS hl_lines="4"
-{!./src/templates/static/styles.css!}
+{!../../../docs_src/templates/static/styles.css!}
```
And because you are using `StaticFiles`, that CSS file would be served automatically by your **FastAPI** application at the URL `/static/styles.css`.
+# Testing Dependencies with Overrides
+
## Overriding dependencies during testing
There are some scenarios where you might want to override a dependency during testing.
And then **FastAPI** will call that override instead of the original dependency.
```Python hl_lines="24 25 28"
-{!./src/dependency_testing/tutorial001.py!}
+{!../../../docs_src/dependency_testing/tutorial001.py!}
```
!!! tip
-## Testing Events, `startup` and `shutdown`
+# Testing Events: startup - 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!}
-```
\ No newline at end of file
+{!../../../docs_src/app_testing/tutorial003.py!}
+```
-## Testing WebSockets
+# 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!}
+{!../../../docs_src/app_testing/tutorial002.py!}
```
+# Using the Request Directly
+
Up to now, you have been declaring the parts of the request that you need with their types.
Taking data from:
For that you need to access the request directly.
```Python hl_lines="1 7 8"
-{!./src/using_request_directly/tutorial001.py!}
+{!../../../docs_src/using_request_directly/tutorial001.py!}
```
By declaring a *path operation function* parameter with the type being the `Request` **FastAPI** will know to pass the `Request` in that parameter.
+# WebSockets
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**.
But it's the simplest way to focus on the server-side of WebSockets and have a working example:
```Python hl_lines="2 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 41 42 43"
-{!./src/websockets/tutorial001.py!}
+{!../../../docs_src/websockets/tutorial001.py!}
```
## Create a `websocket`
In your **FastAPI** application, create a `websocket`:
```Python hl_lines="1 46 47"
-{!./src/websockets/tutorial001.py!}
+{!../../../docs_src/websockets/tutorial001.py!}
```
!!! note "Technical Details"
In your WebSocket route you can `await` for messages and send messages.
```Python hl_lines="48 49 50 51 52"
-{!./src/websockets/tutorial001.py!}
+{!../../../docs_src/websockets/tutorial001.py!}
```
You can receive and send binary, text, and JSON data.
They work the same way as for other FastAPI endpoints/*path operations*:
```Python hl_lines="53 54 55 56 57 58 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76"
-{!./src/websockets/tutorial002.py!}
+{!../../../docs_src/websockets/tutorial002.py!}
```
!!! info
+# Including WSGI - Flask, Django, others
+
You can mount WSGI applications as you saw with [Sub Applications - Behind a Proxy, Mounts](./sub-applications-proxy.md){.internal-link target=_blank}.
For that, you can use the `WSGIMiddleware` and use it to wrap your WSGI application, for example, Flask, Django, etc.
And then mount that under a path.
```Python hl_lines="1 3 22"
-{!./src/wsgi/tutorial001.py!}
+{!../../../docs_src/wsgi/tutorial001.py!}
```
## Check it
+# Alternatives, Inspiration and Comparisons
+
What inspired **FastAPI**, how it compares to other alternatives and what it learned from them.
## Intro
+# Concurrency and async / await
+
Details about the `async def` syntax for *path operation functions* and some background about asynchronous code, concurrency, and parallelism.
## In a hurry?
+# Benchmarks
+
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.
--- /dev/null
+# Development - Contributing
+
+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`
+
+You can create a virtual environment in a directory using Python's `venv` module:
+
+<div class="termy">
+
+```console
+$ python -m venv env
+```
+
+</div>
+
+That will create a directory `./env/` with the Python binaries and then you will be able to install packages for that isolated environment.
+
+### Activate the environment
+
+Activate the new environment with:
+
+<div class="termy">
+
+```console
+$ source ./env/bin/activate
+```
+
+</div>
+
+Or in Windows' PowerShell:
+
+<div class="termy">
+
+```console
+$ .\env\Scripts\Activate.ps1
+```
+
+</div>
+
+Or if you use Bash for Windows (e.g. <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
+
+<div class="termy">
+
+```console
+$ source ./env/Scripts/activate
+```
+
+</div>
+
+To check it worked, use:
+
+<div class="termy">
+
+```console
+$ which pip
+
+some/directory/fastapi/env/bin/pip
+```
+
+</div>
+
+If it shows the `pip` binary at `env/bin/pip` then it worked. 🎉
+
+Or in Windows PowerShell:
+
+<div class="termy">
+
+```console
+$ Get-Command pip
+
+some/directory/fastapi/env/bin/pip
+```
+
+</div>
+
+!!! 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" class="external-link" target="_blank">Flit</a> to build, package and publish the project.
+
+After activating the environment as described above, install `flit`:
+
+<div class="termy">
+
+```console
+$ pip install flit
+
+---> 100%
+```
+
+</div>
+
+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:
+
+<div class="termy">
+
+```console
+$ flit install --deps develop --symlink
+
+---> 100%
+```
+
+</div>
+
+It will install all the dependencies and your local FastAPI in your local environment.
+
+#### Using your local FastAPI
+
+If you create a Python file that imports and uses FastAPI, and run it with the Python from your local environment, it will use your local FastAPI source code.
+
+And if you update that local FastAPI source code, as it is installed with `--symlink`, when you run that Python file again, it will use the fresh version of FastAPI you just edited.
+
+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:
+
+<div class="termy">
+
+```console
+$ bash scripts/format.sh
+```
+
+</div>
+
+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:
+
+<div class="termy">
+
+```console
+$ flit install --symlink
+
+---> 100%
+```
+
+</div>
+
+### Format imports
+
+There is another script that formats all the imports and makes sure you don't have unused imports:
+
+<div class="termy">
+
+```console
+$ bash scripts/format-imports.sh
+```
+
+</div>
+
+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
+
+First, make sure you set up your environment as described above, that will install all the requirements.
+
+The documentation uses <a href="https://www.mkdocs.org/" class="external-link" target="_blank">MkDocs</a>.
+
+And there are extra tools/scripts in place to handle translations in `./scripts/docs.py`.
+
+!!! tip
+ You don't need to see the code in `./scripts/docs.py`, you just use it in the command line.
+
+All the documentation is in Markdown format in the directory `./docs/en/`.
+
+Many of the tutorials have blocks of code.
+
+In most of the cases, these blocks of code are actual complete applications that can be run as is.
+
+In fact, those blocks of code are not written inside the Markdown, they are Python files in the `./docs_src/` directory.
+
+And those Python files are included/injected in the documentation when generating the site.
+
+### Docs for tests
+
+Most of the tests actually run against the example source files in the documentation.
+
+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 test coverage.
+
+During local development, there is a script that builds the site and checks for any changes, live-reloading:
+
+<div class="termy">
+
+```console
+$ python ./scripts/docs.py live
+
+<span style="color: green;">[INFO]</span> Serving on http://0.0.0.0:8008
+<span style="color: green;">[INFO]</span> Start watching changes
+<span style="color: green;">[INFO]</span> Start detecting changes
+```
+
+</div>
+
+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.
+
+#### Typer CLI (optional)
+
+The instructions here show you how to use the script at `./scripts/docs.py` with the `python` program directly.
+
+But you can also use <a href="https://typer.tiangolo.com/typer-cli/" class="external-link" target="_blank">Typer CLI</a>, and you will get autocompletion in your terminal for the commands after installing completion.
+
+If you install Typer CLI, you can install completion with:
+
+<div class="termy">
+
+```console
+$ typer --install-completion
+
+zsh completion installed in /home/user/.bashrc.
+Completion will take effect once you restart the terminal.
+```
+
+</div>
+
+### Apps and docs at the same time
+
+If you run the examples with, e.g.:
+
+<div class="termy">
+
+```console
+$ uvicorn tutorial001:app --reload
+
+<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+</div>
+
+as Uvicorn by default will use the port `8000`, the documentation on port `8008` won't clash.
+
+### Translations
+
+Help with translations is VERY MUCH appreciated! And it can't be done without the help from the community. 🌎 🚀
+
+Here are the steps to help with translations.
+
+#### Tips
+
+✨ Add a single Pull Request per page translated. That will make it much easier for others to review it.
+
+For the languages I don't speak, I'll wait for several others to review the translation before merging.
+
+✨ You can also check if there are translations for your language and add a review to them, that will help me know that the translation is correct and I can merge it.
+
+✨ To check the 2-letter code for the language you want to translate you can use the table <a href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes" class="external-link" target="_blank">List of ISO 639-1 codes</a>.
+
+#### Existing language
+
+Let's say you want to translate a page for a language that already has translations for some pages, like Spanish.
+
+In the case of Spanish, the 2-letter code is `es`. So, the directory for Spanish translations is located at `docs/es/`.
+
+!!! tip
+ The main ("official") language is English, located at `docs/en/`.
+
+Now run the live server for the docs in Spanish:
+
+<div class="termy">
+
+```console
+// Use the command "live" and pass the language code as a CLI argument
+$ python ./scripts/docs.py live es
+
+<span style="color: green;">[INFO]</span> Serving on http://0.0.0.0:8008
+<span style="color: green;">[INFO]</span> Start watching changes
+<span style="color: green;">[INFO]</span> Start detecting changes
+```
+
+</div>
+
+Now you can go to <a href="http://0.0.0.0:8008" class="external-link" target="_blank">http://0.0.0.0:8008</a> and see your changes live.
+
+If you look at the FastAPI docs website, you will see that every language has all the pages. But some are not translated and have a notification about the the translation is missing.
+
+But when you run it locally like this, you will only see the pages that are already translated.
+
+Now let's say that you want to add a translation for the section [Advanced User Guide: Extending OpenAPI](advanced/extending-openapi.md){.internal-link target=_blank}.
+
+* Copy the file at:
+
+```
+docs/en/docs/advanced/extending-openapi.md
+```
+
+* Paste it in exactly the same location but for the language you want to translate, e.g.:
+
+```
+docs/es/docs/advanced/extending-openapi.md
+```
+
+!!! tip
+ Notice that the only change in the path and file name is the language code, from `en` to `es`.
+
+* Now open the MkDocs config file at:
+
+```
+docs/en/docs/mkdocs.yml
+```
+
+* Find the place where that `advanced/extending-openapi.md` is located in the config file. Somewhere like:
+
+```YAML hl_lines="9"
+site_name: FastAPI
+# More stuff
+nav:
+- FastAPI: index.md
+# More stuff
+- Advanced User Guide:
+ # More stuff
+ - advanced/testing-dependencies.md
+ - advanced/extending-openapi.md
+ - advanced/openapi-callbacks.md
+```
+
+* Open the MkDocs config file for the language you are editing, e.g.:
+
+```
+docs/es/docs/mkdocs.yml
+```
+
+* Add the equivalent structure code and add it at the exact same location it would be, e.g.:
+
+```YAML hl_lines="6 9"
+site_name: FastAPI
+# More stuff
+nav:
+- FastAPI: index.md
+# More stuff
+- Guía de Usuario Avanzada:
+ # More stuff
+ - advanced/testing-dependencies.md
+ - advanced/extending-openapi.md
+ - advanced/openapi-callbacks.md
+```
+
+Notice that the `Advanced User Guide` is translated to `Guía de Usuario Avanzada`.
+
+Also, make sure that if there are other entries, the new entry with your translation is in exactly in the same order as in the English version.
+
+If you go to your browser you will see that now the docs show your new section. 🎉
+
+Now you can translate it all and see how it looks as you save the file.
+
+#### New Language
+
+Let's say that you want to add translations for a language that is not yet translated, not even some pages.
+
+Let's say you want to add translations for Creole, and it's not yet there in the docs.
+
+Checking the link from above, the code for "Creole" is `ht`.
+
+The next step is to run the script to generate a new translation directory:
+
+<div class="termy">
+
+```console
+// Use the command new-lang, pass the language code as a CLI argument
+$ python ./scripts/docs.py new-lang ht
+
+Successfully initialized: docs/ht
+Updating ht
+Updating en
+```
+
+</div>
+
+Now you can check in your code editor the newly created directory `docs/ht/`.
+
+Start by translating the main page, `docs/ht/index.md`.
+
+Then you can continue with the previous instructions, for an "Existing Language".
+
+##### New Language not supported
+
+If when running the live server script you get an error about the language not being supported, something like:
+
+```
+ raise TemplateNotFound(template)
+jinja2.exceptions.TemplateNotFound: partials/language/xx.html
+```
+
+That means that the theme doesn't support that language (in this case, with a fake 2-letter code of `xx`).
+
+But don't worry, you can set the theme language to English and then translate the content of the docs.
+
+If you need to do that, edit the `mkdocs.yml` for your new language, it will have something like:
+
+```YAML hl_lines="5"
+site_name: FastAPI
+# More stuff
+theme:
+ # More stuff
+ language: xx
+```
+
+Change that language from `xx` (from your language code) to `en`.
+
+Then you can start the live server again.
+
+## Tests
+
+There is a script that you can run locally to test all the code and generate coverage reports in HTML:
+
+<div class="termy">
+
+```console
+$ bash scripts/test-cov-html.sh
+```
+
+</div>
+
+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
+```
+# Deployment
+
Deploying a **FastAPI** application is relatively easy.
There are several ways to do it depending on your specific use case and the tools that you use.
+# External Links and Articles
+
**FastAPI** has a great community constantly growing.
There are many posts, articles, tools, and projects, related to **FastAPI**.
+# Features
## FastAPI features
* <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.
-
+
* Alternative API documentation with <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank"><strong>ReDoc</strong></a>.
-
+
### Just Modern Python
* in <a href="https://code.visualstudio.com/" class="external-link" target="_blank">Visual Studio Code</a>:
-
+
* in <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a>:
-
+
You will get completion in code you might even consider impossible before. As for example, the `price` key inside a JSON body (that could have been nested) that comes from a request.
+# Help FastAPI - Get Help
+
Do you like **FastAPI**?
Would you like to help FastAPI, other users, and the author?
+# History, Design and Future
+
Some time ago, <a href="https://github.com/tiangolo/fastapi/issues/3#issuecomment-454956920" class="external-link" target="_blank">a **FastAPI** user asked</a>:
> What’s the history of this project? It seems to have come from nowhere to awesome in a few weeks [...]
+# Project Generation - Template
+
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
+# Python Types Intro
+
**Python 3.6+** has support for optional "type hints".
These **"type hints"** are a new syntax (since Python 3.6+) that allow declaring the <abbr title="for example: str, int, float, bool">type</abbr> of a variable.
Let's start with a simple example:
```Python
-{!./src/python_types/tutorial001.py!}
+{!../../../docs_src/python_types/tutorial001.py!}
```
Calling this program outputs:
* <abbr title="Puts them together, as one. With the contents of one after the other.">Concatenates</abbr> them with a space in the middle.
```Python hl_lines="2"
-{!./src/python_types/tutorial001.py!}
+{!../../../docs_src/python_types/tutorial001.py!}
```
### Edit it
Those are the "type hints":
```Python hl_lines="1"
-{!./src/python_types/tutorial002.py!}
+{!../../../docs_src/python_types/tutorial002.py!}
```
That is not the same as declaring default values like would be with:
Check this function, it already has type hints:
```Python hl_lines="1"
-{!./src/python_types/tutorial003.py!}
+{!../../../docs_src/python_types/tutorial003.py!}
```
Because the editor knows the types of the variables, you don't only get completion, you also get error checks:
Now you know that you have to fix it, convert `age` to a string with `str(age)`:
```Python hl_lines="2"
-{!./src/python_types/tutorial004.py!}
+{!../../../docs_src/python_types/tutorial004.py!}
```
## Declaring types
* `bytes`
```Python hl_lines="1"
-{!./src/python_types/tutorial005.py!}
+{!../../../docs_src/python_types/tutorial005.py!}
```
### Types with subtypes
From `typing`, import `List` (with a capital `L`):
```Python hl_lines="1"
-{!./src/python_types/tutorial006.py!}
+{!../../../docs_src/python_types/tutorial006.py!}
```
Declare the variable, with the same colon (`:`) syntax.
As the list is a type that takes a "subtype", you put the subtype in square brackets:
```Python hl_lines="4"
-{!./src/python_types/tutorial006.py!}
+{!../../../docs_src/python_types/tutorial006.py!}
```
That means: "the variable `items` is a `list`, and each of the items in this list is a `str`".
You would do the same to declare `tuple`s and `set`s:
```Python hl_lines="1 4"
-{!./src/python_types/tutorial007.py!}
+{!../../../docs_src/python_types/tutorial007.py!}
```
This means:
The second subtype is for the values of the `dict`:
```Python hl_lines="1 4"
-{!./src/python_types/tutorial008.py!}
+{!../../../docs_src/python_types/tutorial008.py!}
```
This means:
Let's say you have a class `Person`, with a name:
```Python hl_lines="1 2 3"
-{!./src/python_types/tutorial009.py!}
+{!../../../docs_src/python_types/tutorial009.py!}
```
Then you can declare a variable to be of type `Person`:
```Python hl_lines="6"
-{!./src/python_types/tutorial009.py!}
+{!../../../docs_src/python_types/tutorial009.py!}
```
And then, again, you get all the editor support:
Taken from the official Pydantic docs:
```Python
-{!./src/python_types/tutorial010.py!}
+{!../../../docs_src/python_types/tutorial010.py!}
```
!!! info
+# Release Notes
+
## Latest changes
* Update terminal styles in docs and add note about [**Typer**, the FastAPI of CLIs](https://typer.tiangolo.com/). PR [#1139](https://github.com/tiangolo/fastapi/pull/1139).
+# Application Configuration
+
There are several things that you can configure in your FastAPI application.
## Title, description, and version
To set them, use the parameters `title`, `description`, and `version`:
```Python hl_lines="4 5 6"
-{!./src/application_configuration/tutorial001.py!}
+{!../../../docs_src/application_configuration/tutorial001.py!}
```
With this configuration, the automatic API docs would look like:
For example, to set it to be served at `/api/v1/openapi.json`:
```Python hl_lines="3"
-{!./src/application_configuration/tutorial002.py!}
+{!../../../docs_src/application_configuration/tutorial002.py!}
```
If you want to disable the OpenAPI schema completely you can set `openapi_url=None`.
For example, to set Swagger UI to be served at `/documentation` and disable ReDoc:
```Python hl_lines="3"
-{!./src/application_configuration/tutorial003.py!}
+{!../../../docs_src/application_configuration/tutorial003.py!}
```
+# Background Tasks
+
You can define background tasks to be run *after* returning a response.
This is useful for operations that need to happen after a request, but that the client doesn't really have to be waiting for the operation to complete before receiving his response.
First, import `BackgroundTasks` and define a parameter in your *path operation function* with a type declaration of `BackgroundTasks`:
```Python hl_lines="1 13"
-{!./src/background_tasks/tutorial001.py!}
+{!../../../docs_src/background_tasks/tutorial001.py!}
```
**FastAPI** will create the object of type `BackgroundTasks` for you and pass it as that parameter.
And as the write operation doesn't use `async` and `await`, we define the function with normal `def`:
```Python hl_lines="6 7 8 9"
-{!./src/background_tasks/tutorial001.py!}
+{!../../../docs_src/background_tasks/tutorial001.py!}
```
## Add the background task
Inside of your *path operation function*, pass your task function to the *background tasks* object with the method `.add_task()`:
```Python hl_lines="14"
-{!./src/background_tasks/tutorial001.py!}
+{!../../../docs_src/background_tasks/tutorial001.py!}
```
`.add_task()` receives as arguments:
**FastAPI** knows what to do in each case and how to re-use the same object, so that all the background tasks are merged together and are run in the background afterwards:
```Python hl_lines="11 14 20 23"
-{!./src/background_tasks/tutorial002.py!}
+{!../../../docs_src/background_tasks/tutorial002.py!}
```
In this example, the messages will be written to the `log.txt` file *after* the response is sent.
+# Bigger Applications - Multiple Files
+
If you are building an application or a web API, it's rarely the case that you can put everything on a single file.
**FastAPI** provides a convenience tool to structure your application while keeping all the flexibility.
You import it and create an "instance" the same way you would with the class `FastAPI`:
```Python hl_lines="1 3"
-{!./src/bigger_applications/app/routers/users.py!}
+{!../../../docs_src/bigger_applications/app/routers/users.py!}
```
### *Path operations* with `APIRouter`
Use it the same way you would use the `FastAPI` class:
```Python hl_lines="6 11 16"
-{!./src/bigger_applications/app/routers/users.py!}
+{!../../../docs_src/bigger_applications/app/routers/users.py!}
```
You can think of `APIRouter` as a "mini `FastAPI`" class.
And we don't want to have to explicitly type `/items/` and `tags=["items"]` in every *path operation* (we will be able to do it later):
```Python hl_lines="6 11"
-{!./src/bigger_applications/app/routers/items.py!}
+{!../../../docs_src/bigger_applications/app/routers/items.py!}
```
### Add some custom `tags`, `responses`, and `dependencies`
But we can add custom `tags` and `responses` that will be applied to a specific *path operation*:
```Python hl_lines="18 19"
-{!./src/bigger_applications/app/routers/items.py!}
+{!../../../docs_src/bigger_applications/app/routers/items.py!}
```
## The main `FastAPI`
You import and create a `FastAPI` class as normally:
```Python hl_lines="1 5"
-{!./src/bigger_applications/app/main.py!}
+{!../../../docs_src/bigger_applications/app/main.py!}
```
### Import the `APIRouter`
We import the other submodules that have `APIRouter`s:
```Python hl_lines="3"
-{!./src/bigger_applications/app/main.py!}
+{!../../../docs_src/bigger_applications/app/main.py!}
```
As the file `app/routers/items.py` is part of the same Python package, we can import it using "dot notation".
So, to be able to use both of them in the same file, we import the submodules directly:
```Python hl_lines="3"
-{!./src/bigger_applications/app/main.py!}
+{!../../../docs_src/bigger_applications/app/main.py!}
```
### Include an `APIRouter`
Now, let's include the `router` from the submodule `users`:
```Python hl_lines="13"
-{!./src/bigger_applications/app/main.py!}
+{!../../../docs_src/bigger_applications/app/main.py!}
```
!!! info
And we can add a list of `dependencies` that will be added to all the *path operations* in the router and will be executed/solved for each request made to them. Note that, much like dependencies in *path operation decorators*, no value will be passed to your *path operation function*.
```Python hl_lines="8 9 10 14 15 16 17 18 19 20"
-{!./src/bigger_applications/app/main.py!}
+{!../../../docs_src/bigger_applications/app/main.py!}
```
The end result is that the item paths are now:
+# Body - Fields
+
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`
First, you have to import it:
```Python hl_lines="2"
-{!./src/body_fields/tutorial001.py!}
+{!../../../docs_src/body_fields/tutorial001.py!}
```
!!! warning
You can then use `Field` with model attributes:
```Python hl_lines="9 10"
-{!./src/body_fields/tutorial001.py!}
+{!../../../docs_src/body_fields/tutorial001.py!}
```
`Field` works the same way as `Query`, `Path` and `Body`, it has all the same parameters, etc.
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!}
+{!../../../docs_src/body_fields/tutorial002.py!}
```
And it would look in the `/docs` like this:
+# Body - Multiple Parameters
+
Now that we have seen how to use `Path` and `Query`, let's see more advanced uses of request body declarations.
## Mix `Path`, `Query` and body parameters
And you can also declare body parameters as optional, by setting the default to `None`:
```Python hl_lines="17 18 19"
-{!./src/body_multiple_params/tutorial001.py!}
+{!../../../docs_src/body_multiple_params/tutorial001.py!}
```
!!! note
But you can also declare multiple body parameters, e.g. `item` and `user`:
```Python hl_lines="20"
-{!./src/body_multiple_params/tutorial002.py!}
+{!../../../docs_src/body_multiple_params/tutorial002.py!}
```
In this case, **FastAPI** will notice that there are more than one body parameters in the function (two parameters that are Pydantic models).
```Python hl_lines="21"
-{!./src/body_multiple_params/tutorial003.py!}
+{!../../../docs_src/body_multiple_params/tutorial003.py!}
```
In this case, **FastAPI** will expect a body like:
as in:
```Python hl_lines="25"
-{!./src/body_multiple_params/tutorial004.py!}
+{!../../../docs_src/body_multiple_params/tutorial004.py!}
```
!!! info
as in:
```Python hl_lines="15"
-{!./src/body_multiple_params/tutorial005.py!}
+{!../../../docs_src/body_multiple_params/tutorial005.py!}
```
In this case **FastAPI** will expect a body like:
+# Body - Nested Models
+
With **FastAPI**, you can define, validate, document, and use arbitrarily deeply nested models (thanks to Pydantic).
## List fields
You can define an attribute to be a subtype. For example, a Python `list`:
```Python hl_lines="12"
-{!./src/body_nested_models/tutorial001.py!}
+{!../../../docs_src/body_nested_models/tutorial001.py!}
```
This will make `tags` be a list of items. Although it doesn't declare the type of each of the items.
First, import `List` from standard Python's `typing` module:
```Python hl_lines="1"
-{!./src/body_nested_models/tutorial002.py!}
+{!../../../docs_src/body_nested_models/tutorial002.py!}
```
### Declare a `List` with a subtype
So, in our example, we can make `tags` be specifically a "list of strings":
```Python hl_lines="14"
-{!./src/body_nested_models/tutorial002.py!}
+{!../../../docs_src/body_nested_models/tutorial002.py!}
```
## Set types
Then we can import `Set` and declare `tags` as a `set` of `str`:
```Python hl_lines="1 14"
-{!./src/body_nested_models/tutorial003.py!}
+{!../../../docs_src/body_nested_models/tutorial003.py!}
```
With this, even if you receive a request with duplicate data, it will be converted to a set of unique items.
For example, we can define an `Image` model:
```Python hl_lines="9 10 11"
-{!./src/body_nested_models/tutorial004.py!}
+{!../../../docs_src/body_nested_models/tutorial004.py!}
```
### Use the submodel as a type
And then we can use it as the type of an attribute:
```Python hl_lines="20"
-{!./src/body_nested_models/tutorial004.py!}
+{!../../../docs_src/body_nested_models/tutorial004.py!}
```
This would mean that **FastAPI** would expect a body similar to:
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!}
+{!../../../docs_src/body_nested_models/tutorial005.py!}
```
The string will be checked to be a valid URL, and documented in JSON Schema / OpenAPI as such.
You can also use Pydantic models as subtypes of `list`, `set`, etc:
```Python hl_lines="20"
-{!./src/body_nested_models/tutorial006.py!}
+{!../../../docs_src/body_nested_models/tutorial006.py!}
```
This will expect (convert, validate, document, etc) a JSON body like:
You can define arbitrarily deeply nested models:
```Python hl_lines="9 14 20 23 27"
-{!./src/body_nested_models/tutorial007.py!}
+{!../../../docs_src/body_nested_models/tutorial007.py!}
```
!!! info
as in:
```Python hl_lines="15"
-{!./src/body_nested_models/tutorial008.py!}
+{!../../../docs_src/body_nested_models/tutorial008.py!}
```
## Editor support everywhere
In this case, you would accept any `dict` as long as it has `int` keys with `float` values:
```Python hl_lines="15"
-{!./src/body_nested_models/tutorial009.py!}
+{!../../../docs_src/body_nested_models/tutorial009.py!}
```
!!! tip
+# Body - Updates
+
## Update replacing with `PUT`
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`.
```Python hl_lines="30 31 32 33 34 35"
-{!./src/body_updates/tutorial001.py!}
+{!../../../docs_src/body_updates/tutorial001.py!}
```
`PUT` is used to receive data that should replace the existing data.
Then you can use this to generate a `dict` with only the data that was set (sent in the request), omitting default values:
```Python hl_lines="34"
-{!./src/body_updates/tutorial002.py!}
+{!../../../docs_src/body_updates/tutorial002.py!}
```
### Using Pydantic's `update` parameter
Like `stored_item_model.copy(update=update_data)`:
```Python hl_lines="35"
-{!./src/body_updates/tutorial002.py!}
+{!../../../docs_src/body_updates/tutorial002.py!}
```
### Partial updates recap
* Return the updated model.
```Python hl_lines="30 31 32 33 34 35 36 37"
-{!./src/body_updates/tutorial002.py!}
+{!../../../docs_src/body_updates/tutorial002.py!}
```
!!! tip
+# Request Body
+
When you need to send data from a client (let's say, a browser) to your API, you send it as a **request body**.
A **request** body is data sent by the client to your API. A **response** body is the data your API sends to the client.
First, you need to import `BaseModel` from `pydantic`:
```Python hl_lines="2"
-{!./src/body/tutorial001.py!}
+{!../../../docs_src/body/tutorial001.py!}
```
## Create your data model
Use standard Python types for all the attributes:
```Python hl_lines="5 6 7 8 9"
-{!./src/body/tutorial001.py!}
+{!../../../docs_src/body/tutorial001.py!}
```
The same as when declaring query parameters, when a model attribute has a default value, it is not required. Otherwise, it is required. Use `None` to make it just optional.
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!}
+{!../../../docs_src/body/tutorial001.py!}
```
...and declare its type as the model you created, `Item`.
Inside of the function, you can access all the attributes of the model object directly:
```Python hl_lines="19"
-{!./src/body/tutorial002.py!}
+{!../../../docs_src/body/tutorial002.py!}
```
## Request body + path parameters
**FastAPI** will recognize that the function parameters that match path parameters should be **taken from the path**, and that function parameters that are declared to be Pydantic models should be **taken from the request body**.
```Python hl_lines="15 16"
-{!./src/body/tutorial003.py!}
+{!../../../docs_src/body/tutorial003.py!}
```
## Request body + path + query parameters
**FastAPI** will recognize each of them and take the data from the correct place.
```Python hl_lines="16"
-{!./src/body/tutorial004.py!}
+{!../../../docs_src/body/tutorial004.py!}
```
The function parameters will be recognized as follows:
+# Cookie Parameters
+
You can define Cookie parameters the same way you define `Query` and `Path` parameters.
## Import `Cookie`
First import `Cookie`:
```Python hl_lines="1"
-{!./src/cookie_params/tutorial001.py!}
+{!../../../docs_src/cookie_params/tutorial001.py!}
```
## Declare `Cookie` parameters
The first value is the default value, you can pass all the extra validation or annotation parameters:
```Python hl_lines="7"
-{!./src/cookie_params/tutorial001.py!}
+{!../../../docs_src/cookie_params/tutorial001.py!}
```
!!! note "Technical Details"
+# CORS (Cross-Origin Resource Sharing)
+
<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
* Specific HTTP headers or all of them with the wildcard `"*"`.
```Python hl_lines="2 6 7 8 9 10 11 13 14 15 16 17 18 19"
-{!./src/cors/tutorial001.py!}
+{!../../../docs_src/cors/tutorial001.py!}
```
The default parameters used by the `CORSMiddleware` implementation are restrictive by default, so you'll need to explicitly enable particular origins, methods, or headers, in order for browsers to be permitted to use them in a Cross-Domain context.
+# Debugging
+
You can connect the debugger in your editor, for example with Visual Studio Code or PyCharm.
## Call `uvicorn`
In your FastAPI application, import and run `uvicorn` directly:
```Python hl_lines="1 15"
-{!./src/debugging/tutorial001.py!}
+{!../../../docs_src/debugging/tutorial001.py!}
```
### About `__name__ == "__main__"`
+# Classes as Dependencies
+
Before diving deeper into the **Dependency Injection** system, let's upgrade the previous example.
## A `dict` from the previous example
In the previous example, we were returning a `dict` from our dependency ("dependable"):
```Python hl_lines="7"
-{!./src/dependencies/tutorial001.py!}
+{!../../../docs_src/dependencies/tutorial001.py!}
```
But then we get a `dict` in the parameter `commons` of the *path operation function*.
Then, we can change the dependency "dependable" `common_parameters` from above to the class `CommonQueryParameters`:
```Python hl_lines="9 10 11 12 13"
-{!./src/dependencies/tutorial002.py!}
+{!../../../docs_src/dependencies/tutorial002.py!}
```
Pay attention to the `__init__` method used to create the instance of the class:
```Python hl_lines="10"
-{!./src/dependencies/tutorial002.py!}
+{!../../../docs_src/dependencies/tutorial002.py!}
```
...it has the same parameters as our previous `common_parameters`:
```Python hl_lines="6"
-{!./src/dependencies/tutorial001.py!}
+{!../../../docs_src/dependencies/tutorial001.py!}
```
Those parameters are what **FastAPI** will use to "solve" the dependency.
And as when **FastAPI** calls that class the value that will be passed as `commons` to your function will be an "instance" of the class, you can declare that parameter `commons` to be of type of the class, `CommonQueryParams`.
```Python hl_lines="17"
-{!./src/dependencies/tutorial002.py!}
+{!../../../docs_src/dependencies/tutorial002.py!}
```
## Type annotation vs `Depends`
..as in:
```Python hl_lines="17"
-{!./src/dependencies/tutorial003.py!}
+{!../../../docs_src/dependencies/tutorial003.py!}
```
But declaring the type is encouraged as that way your editor will know what will be passed as the parameter `commons`, and then it can help you with code completion, type checks, etc:
So, the same example would look like:
```Python hl_lines="17"
-{!./src/dependencies/tutorial004.py!}
+{!../../../docs_src/dependencies/tutorial004.py!}
```
...and **FastAPI** will know what to do.
+# Dependencies in path operation decorators
+
In some cases you don't really need the return value of a dependency inside your *path operation function*.
Or the dependency doesn't return a value.
It should be a `list` of `Depends()`:
```Python hl_lines="17"
-{!./src/dependencies/tutorial006.py!}
+{!../../../docs_src/dependencies/tutorial006.py!}
```
These dependencies will be executed/solved the same way normal dependencies. But their value (if they return any) won't be passed to your *path operation function*.
They can declare request requirements (like headers) or other sub-dependencies:
```Python hl_lines="6 11"
-{!./src/dependencies/tutorial006.py!}
+{!../../../docs_src/dependencies/tutorial006.py!}
```
### Raise exceptions
These dependencies can `raise` exceptions, the same as normal dependencies:
```Python hl_lines="8 13"
-{!./src/dependencies/tutorial006.py!}
+{!../../../docs_src/dependencies/tutorial006.py!}
```
### Return values
So, you can re-use a normal dependency (that returns a value) you already use somewhere else, and even though the value won't be used, the dependency will be executed:
```Python hl_lines="9 14"
-{!./src/dependencies/tutorial006.py!}
+{!../../../docs_src/dependencies/tutorial006.py!}
```
## Dependencies for a group of *path operations*
-# Dependencies with `yield`
+# Dependencies with yield
FastAPI supports dependencies that do some <abbr title='sometimes also called "exit", "cleanup", "teardown", "close", "context managers", ...'>extra steps after finishing</abbr>.
Only the code prior to and including the `yield` statement is executed before sending a response:
```Python hl_lines="2 3 4"
-{!./src/dependencies/tutorial007.py!}
+{!../../../docs_src/dependencies/tutorial007.py!}
```
The yielded value is what is injected into *path operations* and other dependencies:
```Python hl_lines="4"
-{!./src/dependencies/tutorial007.py!}
+{!../../../docs_src/dependencies/tutorial007.py!}
```
The code following the `yield` statement is executed after the response has been delivered:
```Python hl_lines="5 6"
-{!./src/dependencies/tutorial007.py!}
+{!../../../docs_src/dependencies/tutorial007.py!}
```
!!! tip
In the same way, you can use `finally` to make sure the exit steps are executed, no matter if there was an exception or not.
```Python hl_lines="3 5"
-{!./src/dependencies/tutorial007.py!}
+{!../../../docs_src/dependencies/tutorial007.py!}
```
## Sub-dependencies with `yield`
For example, `dependency_c` can have a dependency on `dependency_b`, and `dependency_b` on `dependency_a`:
```Python hl_lines="4 12 20"
-{!./src/dependencies/tutorial008.py!}
+{!../../../docs_src/dependencies/tutorial008.py!}
```
And all of them can use `yield`.
And, in turn, `dependency_b` needs the value from `dependency_a` (here named `dep_a`) to be available for its exit code.
```Python hl_lines="16 17 24 25"
-{!./src/dependencies/tutorial008.py!}
+{!../../../docs_src/dependencies/tutorial008.py!}
```
The same way, you could have dependencies with `yield` and `return` mixed.
`with` or `async with` statements inside of the dependency function:
```Python hl_lines="1 2 3 4 5 6 7 8 9 13"
-{!./src/dependencies/tutorial010.py!}
+{!../../../docs_src/dependencies/tutorial010.py!}
```
!!! tip
+# Dependencies - First Steps
+
**FastAPI** has a very powerful but intuitive **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** system.
It is designed to be very simple to use, and to make it very easy for any developer to integrate other components with **FastAPI**.
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!}
+{!../../../docs_src/dependencies/tutorial001.py!}
```
That's it.
### Import `Depends`
```Python hl_lines="1"
-{!./src/dependencies/tutorial001.py!}
+{!../../../docs_src/dependencies/tutorial001.py!}
```
### 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:
```Python hl_lines="11 16"
-{!./src/dependencies/tutorial001.py!}
+{!../../../docs_src/dependencies/tutorial001.py!}
```
Although you use `Depends` in the parameters of your function the same way you use `Body`, `Query`, etc, `Depends` works a bit differently.
+# Sub-dependencies
+
You can create dependencies that have **sub-dependencies**.
They can be as **deep** as you need them to be.
You could create a first dependency ("dependable") like:
```Python hl_lines="6 7"
-{!./src/dependencies/tutorial005.py!}
+{!../../../docs_src/dependencies/tutorial005.py!}
```
It declares an optional query parameter `q` as a `str`, and then it just returns it.
Then you can create another dependency function (a "dependable") that at the same time declares a dependency of its own (so it is a "dependant" too):
```Python hl_lines="11"
-{!./src/dependencies/tutorial005.py!}
+{!../../../docs_src/dependencies/tutorial005.py!}
```
Let's focus on the parameters declared:
Then we can use the dependency with:
```Python hl_lines="19"
-{!./src/dependencies/tutorial005.py!}
+{!../../../docs_src/dependencies/tutorial005.py!}
```
!!! info
+# JSON Compatible Encoder
+
There are some cases where you might need to convert a data type (like a Pydantic model) to something compatible with JSON (like a `dict`, `list`, etc).
For example, if you need to store it in a database.
It receives an object, like a Pydantic model, and returns a JSON compatible version:
```Python hl_lines="4 21"
-{!./src/encoder/tutorial001.py!}
+{!../../../docs_src/encoder/tutorial001.py!}
```
In this example, it would convert the Pydantic model to a `dict`, and the `datetime` to a `str`.
+# Extra Data Types
+
Up to now, you have been using common data types, like:
* `int`
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!}
+{!../../../docs_src/extra_data_types/tutorial001.py!}
```
Note that the parameters inside the function have their natural data type, and you can, for example, perform normal date manipulations, like:
```Python hl_lines="17 18"
-{!./src/extra_data_types/tutorial001.py!}
+{!../../../docs_src/extra_data_types/tutorial001.py!}
```
+# Extra Models
+
Continuing with the previous example, it will be common to have more than one related model.
This is especially the case for user models, because:
Here's a general idea of how the models could look like with their password fields and the places where they are used:
```Python hl_lines="7 9 14 20 22 27 28 31 32 33 38 39"
-{!./src/extra_models/tutorial001.py!}
+{!../../../docs_src/extra_models/tutorial001.py!}
```
### About `**user_in.dict()`
That way, we can declare just the differences between the models (with plaintext `password`, with `hashed_password` and without password):
```Python hl_lines="7 13 14 17 18 21 22"
-{!./src/extra_models/tutorial002.py!}
+{!../../../docs_src/extra_models/tutorial002.py!}
```
## `Union` or `anyOf`
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!}
+{!../../../docs_src/extra_models/tutorial003.py!}
```
## List of models
For that, use the standard Python `typing.List`:
```Python hl_lines="1 20"
-{!./src/extra_models/tutorial004.py!}
+{!../../../docs_src/extra_models/tutorial004.py!}
```
## Response with arbitrary `dict`
In this case, you can use `typing.Dict`:
```Python hl_lines="1 8"
-{!./src/extra_models/tutorial005.py!}
+{!../../../docs_src/extra_models/tutorial005.py!}
```
## Recap
+# First Steps
+
The simplest FastAPI file could look like this:
```Python
-{!./src/first_steps/tutorial001.py!}
+{!../../../docs_src/first_steps/tutorial001.py!}
```
Copy that to a file `main.py`.
### Step 1: import `FastAPI`
```Python hl_lines="1"
-{!./src/first_steps/tutorial001.py!}
+{!../../../docs_src/first_steps/tutorial001.py!}
```
`FastAPI` is a Python class that provides all the functionality for your API.
### Step 2: create a `FastAPI` "instance"
```Python hl_lines="3"
-{!./src/first_steps/tutorial001.py!}
+{!../../../docs_src/first_steps/tutorial001.py!}
```
Here the `app` variable will be an "instance" of the class `FastAPI`.
If you create your app like:
```Python hl_lines="3"
-{!./src/first_steps/tutorial002.py!}
+{!../../../docs_src/first_steps/tutorial002.py!}
```
And put it in a file `main.py`, then you would call `uvicorn` like:
#### Define a *path operation function*
```Python hl_lines="6"
-{!./src/first_steps/tutorial001.py!}
+{!../../../docs_src/first_steps/tutorial001.py!}
```
The `@app.get("/")` tells **FastAPI** that the function right below is in charge of handling requests that go to:
* **function**: is the function below the "decorator" (below `@app.get("/")`).
```Python hl_lines="7"
-{!./src/first_steps/tutorial001.py!}
+{!../../../docs_src/first_steps/tutorial001.py!}
```
This is a Python function.
You could also define it as a normal function instead of `async def`:
```Python hl_lines="7"
-{!./src/first_steps/tutorial003.py!}
+{!../../../docs_src/first_steps/tutorial003.py!}
```
!!! note
### Step 5: return the content
```Python hl_lines="8"
-{!./src/first_steps/tutorial001.py!}
+{!../../../docs_src/first_steps/tutorial001.py!}
```
You can return a `dict`, `list`, singular values as `str`, `int`, etc.
+# Handling Errors
+
There are many situations in where you need to notify an error to a client that is using your API.
This client could be a browser with a frontend, a code from someone else, an IoT device, etc.
### Import `HTTPException`
```Python hl_lines="1"
-{!./src/handling_errors/tutorial001.py!}
+{!../../../docs_src/handling_errors/tutorial001.py!}
```
### Raise an `HTTPException` in your code
In this example, when the client request an item by an ID that doesn't exist, raise an exception with a status code of `404`:
```Python hl_lines="11"
-{!./src/handling_errors/tutorial001.py!}
+{!../../../docs_src/handling_errors/tutorial001.py!}
```
### The resulting response
But in case you needed it for an advanced scenario, you can add custom headers:
```Python hl_lines="14"
-{!./src/handling_errors/tutorial002.py!}
+{!../../../docs_src/handling_errors/tutorial002.py!}
```
## Install custom exception handlers
You could add a custom exception handler with `@app.exception_handler()`:
```Python hl_lines="5 6 7 13 14 15 16 17 18 24"
-{!./src/handling_errors/tutorial003.py!}
+{!../../../docs_src/handling_errors/tutorial003.py!}
```
Here, if you request `/unicorns/yolo`, the *path operation* will `raise` a `UnicornException`.
The exception handler will receive a `Request` and the exception.
```Python hl_lines="2 14 15 16"
-{!./src/handling_errors/tutorial004.py!}
+{!../../../docs_src/handling_errors/tutorial004.py!}
```
Now, if you go to `/items/foo`, instead of getting the default JSON error with:
For example, you could want to return a plain text response instead of JSON for these errors:
```Python hl_lines="3 4 9 10 11 22"
-{!./src/handling_errors/tutorial004.py!}
+{!../../../docs_src/handling_errors/tutorial004.py!}
```
!!! note "Technical Details"
You could use it while developing your app to log the body and debug it, return it to the user, etc.
```Python hl_lines="14"
-{!./src/handling_errors/tutorial005.py!}
+{!../../../docs_src/handling_errors/tutorial005.py!}
```
Now try sending an invalid item like:
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/tutorial006.py!}
+{!../../../docs_src/handling_errors/tutorial006.py!}
```
In this example, you are just `print`ing the error with a very expressive message.
+# Header Parameters
+
You can define Header parameters the same way you define `Query`, `Path` and `Cookie` parameters.
## Import `Header`
First import `Header`:
```Python hl_lines="1"
-{!./src/header_params/tutorial001.py!}
+{!../../../docs_src/header_params/tutorial001.py!}
```
## Declare `Header` parameters
The first value is the default value, you can pass all the extra validation or annotation parameters:
```Python hl_lines="7"
-{!./src/header_params/tutorial001.py!}
+{!../../../docs_src/header_params/tutorial001.py!}
```
!!! note "Technical Details"
If for some reason you need to disable automatic conversion of underscores to hyphens, set the parameter `convert_underscores` of `Header` to `False`:
```Python hl_lines="7"
-{!./src/header_params/tutorial002.py!}
+{!../../../docs_src/header_params/tutorial002.py!}
```
!!! warning
For example, to declare a header of `X-Token` that can appear more than once, you can write:
```Python hl_lines="9"
-{!./src/header_params/tutorial003.py!}
+{!../../../docs_src/header_params/tutorial003.py!}
```
If you communicate with that *path operation* sending two HTTP headers like:
+# Tutorial - User Guide - Intro
+
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.
+# Middleware
+
You can add middleware to **FastAPI** applications.
A "middleware" is a function that works with every **request** before it is processed by any specific *path operation*. And also with every **response** before returning it.
* You can then modify further the `response` before returning it.
```Python hl_lines="8 9 11 14"
-{!./src/middleware/tutorial001.py!}
+{!../../../docs_src/middleware/tutorial001.py!}
```
!!! tip
For example, you could add a custom header `X-Process-Time` containing the time in seconds that it took to process the request and generate a response:
```Python hl_lines="10 12 13"
-{!./src/middleware/tutorial001.py!}
+{!../../../docs_src/middleware/tutorial001.py!}
```
## Other middlewares
+# Path Operation Configuration
+
There are several parameters that you can pass to your *path operation decorator* to configure it.
!!! warning
But if you don't remember what each number code is for, you can use the shortcut constants in `status`:
```Python hl_lines="3 17"
-{!./src/path_operation_configuration/tutorial001.py!}
+{!../../../docs_src/path_operation_configuration/tutorial001.py!}
```
That status code will be used in the response and will be added to the OpenAPI schema.
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!}
+{!../../../docs_src/path_operation_configuration/tutorial002.py!}
```
They will be added to the OpenAPI schema and used by the automatic documentation interfaces:
You can add a `summary` and `description`:
```Python hl_lines="20 21"
-{!./src/path_operation_configuration/tutorial003.py!}
+{!../../../docs_src/path_operation_configuration/tutorial003.py!}
```
## Description from docstring
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!}
+{!../../../docs_src/path_operation_configuration/tutorial004.py!}
```
It will be used in the interactive docs:
You can specify the response description with the parameter `response_description`:
```Python hl_lines="21"
-{!./src/path_operation_configuration/tutorial005.py!}
+{!../../../docs_src/path_operation_configuration/tutorial005.py!}
```
!!! info
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!}
+{!../../../docs_src/path_operation_configuration/tutorial006.py!}
```
It will be clearly marked as deprecated in the interactive docs:
+# Path Parameters and Numeric Validations
+
The same way you can declare more validations and metadata for query parameters with `Query`, you can declare the same type of validations and metadata for path parameters with `Path`.
## Import Path
First, import `Path` from `fastapi`:
```Python hl_lines="1"
-{!./src/path_params_numeric_validations/tutorial001.py!}
+{!../../../docs_src/path_params_numeric_validations/tutorial001.py!}
```
## Declare metadata
For example, to declare a `title` metadata value for the path parameter `item_id` you can type:
```Python hl_lines="8"
-{!./src/path_params_numeric_validations/tutorial001.py!}
+{!../../../docs_src/path_params_numeric_validations/tutorial001.py!}
```
!!! note
So, you can declare your function as:
```Python hl_lines="8"
-{!./src/path_params_numeric_validations/tutorial002.py!}
+{!../../../docs_src/path_params_numeric_validations/tutorial002.py!}
```
## Order the parameters as you need, tricks
Python won't do anything with that `*`, but it will know that all the following parameters should be called as keyword arguments (key-value pairs), also known as <abbr title="From: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>. Even if they don't have a default value.
```Python hl_lines="8"
-{!./src/path_params_numeric_validations/tutorial003.py!}
+{!../../../docs_src/path_params_numeric_validations/tutorial003.py!}
```
## Number validations: greater than or equal
Here, with `ge=1`, `item_id` will need to be an integer number "`g`reater than or `e`qual" to `1`.
```Python hl_lines="8"
-{!./src/path_params_numeric_validations/tutorial004.py!}
+{!../../../docs_src/path_params_numeric_validations/tutorial004.py!}
```
## Number validations: greater than and less than or equal
* `le`: `l`ess than or `e`qual
```Python hl_lines="9"
-{!./src/path_params_numeric_validations/tutorial005.py!}
+{!../../../docs_src/path_params_numeric_validations/tutorial005.py!}
```
## Number validations: floats, greater than and less than
And the same for <abbr title="less than"><code>lt</code></abbr>.
```Python hl_lines="11"
-{!./src/path_params_numeric_validations/tutorial006.py!}
+{!../../../docs_src/path_params_numeric_validations/tutorial006.py!}
```
## Recap
+# Path Parameters
+
You can declare path "parameters" or "variables" with the same syntax used by Python format strings:
```Python hl_lines="6 7"
-{!./src/path_params/tutorial001.py!}
+{!../../../docs_src/path_params/tutorial001.py!}
```
The value of the path parameter `item_id` will be passed to your function as the argument `item_id`.
You can declare the type of a path parameter in the function, using standard Python type annotations:
```Python hl_lines="7"
-{!./src/path_params/tutorial002.py!}
+{!../../../docs_src/path_params/tutorial002.py!}
```
In this case, `item_id` is declared to be an `int`.
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!}
+{!../../../docs_src/path_params/tutorial003.py!}
```
Otherwise, the path for `/users/{user_id}` would match also for `/users/me`, "thinking" that it's receiving a parameter `user_id` with a value of `"me"`.
And create class attributes with fixed values, those fixed values will be the available valid values:
```Python hl_lines="1 6 7 8 9"
-{!./src/path_params/tutorial005.py!}
+{!../../../docs_src/path_params/tutorial005.py!}
```
!!! info
Then create a *path parameter* with a type annotation using the enum class you created (`ModelName`):
```Python hl_lines="16"
-{!./src/path_params/tutorial005.py!}
+{!../../../docs_src/path_params/tutorial005.py!}
```
### Check the docs
You can compare it with the *enumeration member* in your created enum `ModelName`:
```Python hl_lines="17"
-{!./src/path_params/tutorial005.py!}
+{!../../../docs_src/path_params/tutorial005.py!}
```
#### Get the *enumeration value*
You can get the actual value (a `str` in this case) using `model_name.value`, or in general, `your_enum_member.value`:
```Python hl_lines="19"
-{!./src/path_params/tutorial005.py!}
+{!../../../docs_src/path_params/tutorial005.py!}
```
!!! tip
They will be converted to their corresponding values before returning them to the client:
```Python hl_lines="18 20 21"
-{!./src/path_params/tutorial005.py!}
+{!../../../docs_src/path_params/tutorial005.py!}
```
## Path parameters containing paths
So, you can use it with:
```Python hl_lines="6"
-{!./src/path_params/tutorial004.py!}
+{!../../../docs_src/path_params/tutorial004.py!}
```
!!! tip
+# Query Parameters and String Validations
+
**FastAPI** allows you to declare additional information and validation for your parameters.
Let's take this application as example:
```Python hl_lines="7"
-{!./src/query_params_str_validations/tutorial001.py!}
+{!../../../docs_src/query_params_str_validations/tutorial001.py!}
```
The query parameter `q` is of type `str`, and by default is `None`, so it is optional.
To achieve that, first import `Query` from `fastapi`:
```Python hl_lines="1"
-{!./src/query_params_str_validations/tutorial002.py!}
+{!../../../docs_src/query_params_str_validations/tutorial002.py!}
```
## Use `Query` as the default value
And now use it as the default value of your parameter, setting the parameter `max_length` to 50:
```Python hl_lines="7"
-{!./src/query_params_str_validations/tutorial002.py!}
+{!../../../docs_src/query_params_str_validations/tutorial002.py!}
```
As we have to replace the default value `None` with `Query(None)`, the first parameter to `Query` serves the same purpose of defining that default value.
You can also add a parameter `min_length`:
```Python hl_lines="7"
-{!./src/query_params_str_validations/tutorial003.py!}
+{!../../../docs_src/query_params_str_validations/tutorial003.py!}
```
## Add regular expressions
You can define a <abbr title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings.">regular expression</abbr> that the parameter should match:
```Python hl_lines="8"
-{!./src/query_params_str_validations/tutorial004.py!}
+{!../../../docs_src/query_params_str_validations/tutorial004.py!}
```
This specific regular expression checks that the received parameter value:
Let's say that you want to declare the `q` query parameter to have a `min_length` of `3`, and to have a default value of `"fixedquery"`:
```Python hl_lines="7"
-{!./src/query_params_str_validations/tutorial005.py!}
+{!../../../docs_src/query_params_str_validations/tutorial005.py!}
```
!!! note
So, when you need to declare a value as required while using `Query`, you can use `...` as the first argument:
```Python hl_lines="7"
-{!./src/query_params_str_validations/tutorial006.py!}
+{!../../../docs_src/query_params_str_validations/tutorial006.py!}
```
!!! info
For example, to declare a query parameter `q` that can appear multiple times in the URL, you can write:
```Python hl_lines="9"
-{!./src/query_params_str_validations/tutorial011.py!}
+{!../../../docs_src/query_params_str_validations/tutorial011.py!}
```
Then, with a URL like:
And you can also define a default `list` of values if none are provided:
```Python hl_lines="9"
-{!./src/query_params_str_validations/tutorial012.py!}
+{!../../../docs_src/query_params_str_validations/tutorial012.py!}
```
If you go to:
You can also use `list` directly instead of `List[str]`:
```Python hl_lines="7"
-{!./src/query_params_str_validations/tutorial013.py!}
+{!../../../docs_src/query_params_str_validations/tutorial013.py!}
```
!!! note
You can add a `title`:
```Python hl_lines="7"
-{!./src/query_params_str_validations/tutorial007.py!}
+{!../../../docs_src/query_params_str_validations/tutorial007.py!}
```
And a `description`:
```Python hl_lines="11"
-{!./src/query_params_str_validations/tutorial008.py!}
+{!../../../docs_src/query_params_str_validations/tutorial008.py!}
```
## Alias parameters
Then you can declare an `alias`, and that alias is what will be used to find the parameter value:
```Python hl_lines="7"
-{!./src/query_params_str_validations/tutorial009.py!}
+{!../../../docs_src/query_params_str_validations/tutorial009.py!}
```
## Deprecating parameters
Then pass the parameter `deprecated=True` to `Query`:
```Python hl_lines="16"
-{!./src/query_params_str_validations/tutorial010.py!}
+{!../../../docs_src/query_params_str_validations/tutorial010.py!}
```
The docs will show it like this:
+# Query Parameters
+
When you declare other function parameters that are not part of the path parameters, they are automatically interpreted as "query" parameters.
```Python hl_lines="9"
-{!./src/query_params/tutorial001.py!}
+{!../../../docs_src/query_params/tutorial001.py!}
```
The query is the set of key-value pairs that go after the `?` in a URL, separated by `&` characters.
The same way, you can declare optional query parameters, by setting their default to `None`:
```Python hl_lines="7"
-{!./src/query_params/tutorial002.py!}
+{!../../../docs_src/query_params/tutorial002.py!}
```
In this case, the function parameter `q` will be optional, and will be `None` by default.
You can also declare `bool` types, and they will be converted:
```Python hl_lines="7"
-{!./src/query_params/tutorial003.py!}
+{!../../../docs_src/query_params/tutorial003.py!}
```
In this case, if you go to:
They will be detected by name:
```Python hl_lines="6 8"
-{!./src/query_params/tutorial004.py!}
+{!../../../docs_src/query_params/tutorial004.py!}
```
## Required query parameters
But when you want to make a query parameter required, you can just not declare any default value:
```Python hl_lines="6 7"
-{!./src/query_params/tutorial005.py!}
+{!../../../docs_src/query_params/tutorial005.py!}
```
Here the query parameter `needy` is a required query parameter of type `str`.
And of course, you can define some parameters as required, some as having a default value, and some entirely optional:
```Python hl_lines="7"
-{!./src/query_params/tutorial006.py!}
+{!../../../docs_src/query_params/tutorial006.py!}
```
In this case, there are 3 query parameters:
In a *path operation* that could look like:
```Python hl_lines="9"
-{!./src/query_params/tutorial007.py!}
+{!../../../docs_src/query_params/tutorial007.py!}
```
+# Request Files
+
You can define files to be uploaded by the client using `File`.
!!! info
Import `File` and `UploadFile` from `fastapi`:
```Python hl_lines="1"
-{!./src/request_files/tutorial001.py!}
+{!../../../docs_src/request_files/tutorial001.py!}
```
## Define `File` parameters
Create file parameters the same way you would for `Body` or `Form`:
```Python hl_lines="7"
-{!./src/request_files/tutorial001.py!}
+{!../../../docs_src/request_files/tutorial001.py!}
```
!!! info
Define a `File` parameter with a type of `UploadFile`:
```Python hl_lines="12"
-{!./src/request_files/tutorial001.py!}
+{!../../../docs_src/request_files/tutorial001.py!}
```
Using `UploadFile` has several advantages over `bytes`:
To use that, declare a `List` of `bytes` or `UploadFile`:
```Python hl_lines="10 15"
-{!./src/request_files/tutorial002.py!}
+{!../../../docs_src/request_files/tutorial002.py!}
```
You will receive, as declared, a `list` of `bytes` or `UploadFile`s.
+# Request Forms and Files
+
You can define files and form fields at the same time using `File` and `Form`.
!!! info
## Import `File` and `Form`
```Python hl_lines="1"
-{!./src/request_forms_and_files/tutorial001.py!}
+{!../../../docs_src/request_forms_and_files/tutorial001.py!}
```
## Define `File` and `Form` parameters
Create file and form parameters the same way you would for `Body` or `Query`:
```Python hl_lines="8"
-{!./src/request_forms_and_files/tutorial001.py!}
+{!../../../docs_src/request_forms_and_files/tutorial001.py!}
```
The files and form fields will be uploaded as form data and you will receive the files and form fields.
+# Form Data
+
When you need to receive form fields instead of JSON, you can use `Form`.
!!! info
Import `Form` from `fastapi`:
```Python hl_lines="1"
-{!./src/request_forms/tutorial001.py!}
+{!../../../docs_src/request_forms/tutorial001.py!}
```
## Define `Form` parameters
Create form parameters the same way you would for `Body` or `Query`:
```Python hl_lines="7"
-{!./src/request_forms/tutorial001.py!}
+{!../../../docs_src/request_forms/tutorial001.py!}
```
For example, in one of the ways the OAuth2 specification can be used (called "password flow") it is required to send a `username` and `password` as form fields.
+# Response Model
+
You can declare the model used for the response with the parameter `response_model` in any of the *path operations*:
* `@app.get()`
* etc.
```Python hl_lines="17"
-{!./src/response_model/tutorial001.py!}
+{!../../../docs_src/response_model/tutorial001.py!}
```
!!! note
Here we are declaring a `UserIn` model, it will contain a plaintext password:
```Python hl_lines="7 9"
-{!./src/response_model/tutorial002.py!}
+{!../../../docs_src/response_model/tutorial002.py!}
```
And we are using this model to declare our input and the same model to declare our output:
```Python hl_lines="15 16"
-{!./src/response_model/tutorial002.py!}
+{!../../../docs_src/response_model/tutorial002.py!}
```
Now, whenever a browser is creating a user with a password, the API will return the same password in the response.
We can instead create an input model with the plaintext password and an output model without it:
```Python hl_lines="7 9 14"
-{!./src/response_model/tutorial003.py!}
+{!../../../docs_src/response_model/tutorial003.py!}
```
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!}
+{!../../../docs_src/response_model/tutorial003.py!}
```
...we declared the `response_model` to be our model `UserOut`, that doesn't include the password:
```Python hl_lines="20"
-{!./src/response_model/tutorial003.py!}
+{!../../../docs_src/response_model/tutorial003.py!}
```
So, **FastAPI** will take care of filtering out all the data that is not declared in the output model (using Pydantic).
Your response model could have default values, like:
```Python hl_lines="11 13 14"
-{!./src/response_model/tutorial004.py!}
+{!../../../docs_src/response_model/tutorial004.py!}
```
* `description: str = None` has a default of `None`.
You can set the *path operation decorator* parameter `response_model_exclude_unset=True`:
```Python hl_lines="24"
-{!./src/response_model/tutorial004.py!}
+{!../../../docs_src/response_model/tutorial004.py!}
```
and those default values won't be included in the response, only the values actually set.
This is because the JSON Schema generated in your app's OpenAPI (and the docs) will still be the one for the complete model, even if you use `response_model_include` or `response_model_exclude` to omit some attributes.
```Python hl_lines="29 35"
-{!./src/response_model/tutorial005.py!}
+{!../../../docs_src/response_model/tutorial005.py!}
```
!!! tip
If you forget to use a `set` and use a `list` or `tuple` instead, FastAPI will still convert it to a `set` and it will work correctly:
```Python hl_lines="29 35"
-{!./src/response_model/tutorial006.py!}
+{!../../../docs_src/response_model/tutorial006.py!}
```
## Recap
+# Response Status Code
+
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()`
* etc.
```Python hl_lines="6"
-{!./src/response_status_code/tutorial001.py!}
+{!../../../docs_src/response_status_code/tutorial001.py!}
```
!!! note
Let's see the previous example again:
```Python hl_lines="6"
-{!./src/response_status_code/tutorial001.py!}
+{!../../../docs_src/response_status_code/tutorial001.py!}
```
`201` is the status code for "Created".
You can use the convenience variables from `fastapi.status`.
```Python hl_lines="1 6"
-{!./src/response_status_code/tutorial002.py!}
+{!../../../docs_src/response_status_code/tutorial002.py!}
```
They are just a convenience, they hold the same number, but that way you can use the editor's autocomplete to find them:
+# Security - First Steps
+
Let's imagine that you have your **backend** API in some domain.
And you have a **frontend** in another domain or in a different path of the same domain (or in a mobile application).
Copy the example in a file `main.py`:
```Python
-{!./src/security/tutorial001.py!}
+{!../../../docs_src/security/tutorial001.py!}
```
## Run it
`OAuth2PasswordBearer` is a class that we create passing a parameter of the URL in where the client (the frontend running in the user's browser) can use to send the `username` and `password` and get a token.
```Python hl_lines="6"
-{!./src/security/tutorial001.py!}
+{!../../../docs_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.
Now you can pass that `oauth2_scheme` in a dependency with `Depends`.
```Python hl_lines="10"
-{!./src/security/tutorial001.py!}
+{!../../../docs_src/security/tutorial001.py!}
```
This dependency will provide a `str` that is assigned to the parameter `token` of the *path operation function*.
+# Get Current User
+
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!}
+{!../../../docs_src/security/tutorial001.py!}
```
But that is still not that useful.
The same way we use Pydantic to declare bodies, we can use it anywhere else:
```Python hl_lines="5 12 13 14 15 16"
-{!./src/security/tutorial002.py!}
+{!../../../docs_src/security/tutorial002.py!}
```
## Create a `get_current_user` dependency
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!}
+{!../../../docs_src/security/tutorial002.py!}
```
## Get the user
`get_current_user` will use a (fake) utility function we created, that takes a token as a `str` and returns our Pydantic `User` model:
```Python hl_lines="19 20 21 22 26 27"
-{!./src/security/tutorial002.py!}
+{!../../../docs_src/security/tutorial002.py!}
```
## Inject the current user
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!}
+{!../../../docs_src/security/tutorial002.py!}
```
Notice that we declare the type of `current_user` as the Pydantic model `User`.
And all these thousands of *path operations* can be as small as 3 lines:
```Python hl_lines="30 31 32"
-{!./src/security/tutorial002.py!}
+{!../../../docs_src/security/tutorial002.py!}
```
## Recap
+# Security Intro
+
There are many ways to handle security, authentication and authorization.
And it normally is a complex and "difficult" topic.
+# OAuth2 with Password (and hashing), Bearer with JWT tokens
+
Now that we have all the security flow, let's make the application actually secure, using <abbr title="JSON Web Tokens">JWT</abbr> tokens and secure password hashing.
This code is something you can actually use in your application, save the password hashes in your database, etc.
And another one to authenticate and return a user.
```Python hl_lines="7 48 55 56 59 60 69 70 71 72 73 74 75"
-{!./src/security/tutorial004.py!}
+{!../../../docs_src/security/tutorial004.py!}
```
!!! note
Create a utility function to generate a new access token.
```Python hl_lines="3 6 12 13 14 28 29 30 78 79 80 81 82 83 84 85 86"
-{!./src/security/tutorial004.py!}
+{!../../../docs_src/security/tutorial004.py!}
```
## Update the dependencies
If the token is invalid, return an HTTP error right away.
```Python hl_lines="89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106"
-{!./src/security/tutorial004.py!}
+{!../../../docs_src/security/tutorial004.py!}
```
## Update the `/token` *path operation*
Create a real JWT access token and return it.
```Python hl_lines="115 116 117 118 119 120 121 122 123 124 125 126 127 128"
-{!./src/security/tutorial004.py!}
+{!../../../docs_src/security/tutorial004.py!}
```
### Technical details about the JWT "subject" `sub`
+# Simple OAuth2 with Password and Bearer
+
Now let's build from the previous chapter and add the missing parts to have a complete security flow.
## Get the `username` and `password`
First, import `OAuth2PasswordRequestForm`, and use it as a dependency with `Depends` for the path `/token`:
```Python hl_lines="2 74"
-{!./src/security/tutorial003.py!}
+{!../../../docs_src/security/tutorial003.py!}
```
`OAuth2PasswordRequestForm` is a class dependency that declares a form body with:
For the error, we use the exception `HTTPException`:
```Python hl_lines="1 75 76 77"
-{!./src/security/tutorial003.py!}
+{!../../../docs_src/security/tutorial003.py!}
```
### Check the password
So, the thief won't be able to try to use those same passwords in another system (as many users use the same password everywhere, this would be dangerous).
```Python hl_lines="78 79 80 81"
-{!./src/security/tutorial003.py!}
+{!../../../docs_src/security/tutorial003.py!}
```
#### About `**user_dict`
But for now, let's focus on the specific details we need.
```Python hl_lines="83"
-{!./src/security/tutorial003.py!}
+{!../../../docs_src/security/tutorial003.py!}
```
!!! tip
So, in our endpoint, we will only get a user if the user exists, was correctly authenticated, and is active:
```Python hl_lines="56 57 58 59 60 61 62 63 64 65 67 68 69 70 88"
-{!./src/security/tutorial003.py!}
+{!../../../docs_src/security/tutorial003.py!}
```
!!! info
+# SQL (Relational) Databases
+
**FastAPI** doesn't require you to use a SQL (relational) database.
But you can use any relational database that you want.
### Import the SQLAlchemy parts
```Python hl_lines="1 2 3"
-{!./src/sql_databases/sql_app/database.py!}
+{!../../../docs_src/sql_databases/sql_app/database.py!}
```
### Create a database URL for SQLAlchemy
```Python hl_lines="5 6"
-{!./src/sql_databases/sql_app/database.py!}
+{!../../../docs_src/sql_databases/sql_app/database.py!}
```
In this example, we are "connecting" to a SQLite database (opening a file with the SQLite database).
We will later use this `engine` in other places.
```Python hl_lines="8 9 10"
-{!./src/sql_databases/sql_app/database.py!}
+{!../../../docs_src/sql_databases/sql_app/database.py!}
```
#### Note
To create the `SessionLocal` class, use the function `sessionmaker`:
```Python hl_lines="11"
-{!./src/sql_databases/sql_app/database.py!}
+{!../../../docs_src/sql_databases/sql_app/database.py!}
```
### Create a `Base` class
Later we will inherit from this class to create each of the database models or classes (the ORM models):
```Python hl_lines="13"
-{!./src/sql_databases/sql_app/database.py!}
+{!../../../docs_src/sql_databases/sql_app/database.py!}
```
## Create the database models
These classes are the SQLAlchemy models.
```Python hl_lines="4 7 8 18 19"
-{!./src/sql_databases/sql_app/models.py!}
+{!../../../docs_src/sql_databases/sql_app/models.py!}
```
The `__tablename__` attribute tells SQLAlchemy the name of the table to use in the database for each of these models.
And we pass a SQLAlchemy class "type", as `Integer`, `String`, and `Boolean`, that defines the type in the database, as an argument.
```Python hl_lines="1 10 11 12 13 21 22 23 24"
-{!./src/sql_databases/sql_app/models.py!}
+{!../../../docs_src/sql_databases/sql_app/models.py!}
```
### Create the relationships
This will become, more or less, a "magic" attribute that will contain the values from other tables related to this one.
```Python hl_lines="2 15 26"
-{!./src/sql_databases/sql_app/models.py!}
+{!../../../docs_src/sql_databases/sql_app/models.py!}
```
When accessing the attribute `items` in a `User`, as in `my_user.items`, it will have a list of `Item` SQLAlchemy models (from the `items` table) that have a foreign key pointing to this record in the `users` table.
But for security, the `password` won't be in other Pydantic *models*, for example, it won't be sent from the API when reading a user.
```Python hl_lines="3 6 7 8 11 12 23 24 27 28"
-{!./src/sql_databases/sql_app/schemas.py!}
+{!../../../docs_src/sql_databases/sql_app/schemas.py!}
```
#### SQLAlchemy style and Pydantic style
Not only the IDs of those items, but all the data that we defined in the Pydantic *model* for reading items: `Item`.
```Python hl_lines="15 16 17 31 32 33 34"
-{!./src/sql_databases/sql_app/schemas.py!}
+{!../../../docs_src/sql_databases/sql_app/schemas.py!}
```
!!! tip
In the `Config` class, set the attribute `orm_mode = True`.
```Python hl_lines="15 19 20 31 36 37"
-{!./src/sql_databases/sql_app/schemas.py!}
+{!../../../docs_src/sql_databases/sql_app/schemas.py!}
```
!!! tip
* Read a single item.
```Python hl_lines="1 3 6 7 10 11 14 15 27 28"
-{!./src/sql_databases/sql_app/crud.py!}
+{!../../../docs_src/sql_databases/sql_app/crud.py!}
```
!!! tip
* `refresh` your instance (so that it contains any new data from the database, like the generated ID).
```Python hl_lines="18 19 20 21 22 23 24 31 32 33 34 35 36"
-{!./src/sql_databases/sql_app/crud.py!}
+{!../../../docs_src/sql_databases/sql_app/crud.py!}
```
!!! tip
In a very simplistic way create the database tables:
```Python hl_lines="9"
-{!./src/sql_databases/sql_app/main.py!}
+{!../../../docs_src/sql_databases/sql_app/main.py!}
```
#### Alembic Note
Our dependency will create a new SQLAlchemy `SessionLocal` that will be used in a single request, and then close it once the request is finished.
```Python hl_lines="15 16 17 18 19 20"
-{!./src/sql_databases/sql_app/main.py!}
+{!../../../docs_src/sql_databases/sql_app/main.py!}
```
!!! info
This will then give us better editor support inside the *path operation function*, because the editor will know that the `db` parameter is of type `Session`:
```Python hl_lines="24 32 38 47 53"
-{!./src/sql_databases/sql_app/main.py!}
+{!../../../docs_src/sql_databases/sql_app/main.py!}
```
!!! info "Technical Details"
Now, finally, here's the standard **FastAPI** *path operations* code.
```Python hl_lines="23 24 25 26 27 28 31 32 33 34 37 38 39 40 41 42 45 46 47 48 49 52 53 54 55"
-{!./src/sql_databases/sql_app/main.py!}
+{!../../../docs_src/sql_databases/sql_app/main.py!}
```
We are creating the database session before each request in the dependency with `yield`, and then closing it afterwards.
* `sql_app/database.py`:
```Python
-{!./src/sql_databases/sql_app/database.py!}
+{!../../../docs_src/sql_databases/sql_app/database.py!}
```
* `sql_app/models.py`:
```Python
-{!./src/sql_databases/sql_app/models.py!}
+{!../../../docs_src/sql_databases/sql_app/models.py!}
```
* `sql_app/schemas.py`:
```Python
-{!./src/sql_databases/sql_app/schemas.py!}
+{!../../../docs_src/sql_databases/sql_app/schemas.py!}
```
* `sql_app/crud.py`:
```Python
-{!./src/sql_databases/sql_app/crud.py!}
+{!../../../docs_src/sql_databases/sql_app/crud.py!}
```
* `sql_app/main.py`:
```Python
-{!./src/sql_databases/sql_app/main.py!}
+{!../../../docs_src/sql_databases/sql_app/main.py!}
```
## Check it
The middleware we'll add (just a function) will create a new SQLAlchemy `SessionLocal` for each request, add it to the request and then close it once the request is finished.
```Python hl_lines="14 15 16 17 18 19 20 21 22"
-{!./src/sql_databases/sql_app/alt_main.py!}
+{!../../../docs_src/sql_databases/sql_app/alt_main.py!}
```
!!! info
+# Static Files
+
You can serve static files automatically from a directory using `StaticFiles`.
## Install `aiofiles`
* "Mount" a `StaticFiles()` instance in a specific path.
```Python hl_lines="2 6"
-{!./src/static_files/tutorial001.py!}
+{!../../../docs_src/static_files/tutorial001.py!}
```
!!! note "Technical Details"
+# Testing
+
Thanks to <a href="https://www.starlette.io/testclient/" class="external-link" target="_blank">Starlette</a>, testing **FastAPI** applications is easy and enjoyable.
It is based on <a href="http://docs.python-requests.org" class="external-link" target="_blank">Requests</a>, so it's very familiar and intuitive.
Write simple `assert` statements with the standard Python expressions that you need to check (again, standard `pytest`).
```Python hl_lines="2 12 15 16 17 18"
-{!./src/app_testing/tutorial001.py!}
+{!../../../docs_src/app_testing/tutorial001.py!}
```
!!! tip
Let's say you have a file `main.py` with your **FastAPI** app:
```Python
-{!./src/app_testing/main.py!}
+{!../../../docs_src/app_testing/main.py!}
```
### Testing file
Then you could have a file `test_main.py` with your tests, and import your `app` from the `main` module (`main.py`):
```Python
-{!./src/app_testing/test_main.py!}
+{!../../../docs_src/app_testing/test_main.py!}
```
## Testing: extended example
Both *path operations* require an `X-Token` header.
```Python
-{!./src/app_testing/main_b.py!}
+{!../../../docs_src/app_testing/main_b.py!}
```
### Extended testing file
You could then have a `test_main_b.py`, the same as before, with the extended tests:
```Python
-{!./src/app_testing/test_main_b.py!}
+{!../../../docs_src/app_testing/test_main_b.py!}
```
Whenever you need the client to pass information in the request and you don't know how to, you can search (Google) how to do it in `requests`.
--- /dev/null
+site_name: FastAPI
+site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production
+site_url: https://fastapi.tiangolo.com/
+theme:
+ name: material
+ palette:
+ primary: teal
+ accent: amber
+ logo: img/icon-white.svg
+ favicon: img/favicon.png
+ language: en
+repo_name: tiangolo/fastapi
+repo_url: https://github.com/tiangolo/fastapi
+edit_uri: ''
+google_analytics:
+- UA-133183413-1
+- auto
+nav:
+- FastAPI: index.md
+- Languages:
+ - en: /
+ - es: /es/
+- features.md
+- python-types.md
+- Tutorial - User Guide:
+ - tutorial/index.md
+ - tutorial/first-steps.md
+ - tutorial/path-params.md
+ - tutorial/query-params.md
+ - tutorial/body.md
+ - tutorial/query-params-str-validations.md
+ - tutorial/path-params-numeric-validations.md
+ - tutorial/body-multiple-params.md
+ - tutorial/body-fields.md
+ - tutorial/body-nested-models.md
+ - tutorial/extra-data-types.md
+ - tutorial/cookie-params.md
+ - tutorial/header-params.md
+ - tutorial/response-model.md
+ - tutorial/extra-models.md
+ - tutorial/response-status-code.md
+ - tutorial/request-forms.md
+ - tutorial/request-files.md
+ - tutorial/request-forms-and-files.md
+ - tutorial/handling-errors.md
+ - tutorial/path-operation-configuration.md
+ - tutorial/encoder.md
+ - tutorial/body-updates.md
+ - Dependencies:
+ - tutorial/dependencies/index.md
+ - tutorial/dependencies/classes-as-dependencies.md
+ - tutorial/dependencies/sub-dependencies.md
+ - tutorial/dependencies/dependencies-in-path-operation-decorators.md
+ - tutorial/dependencies/dependencies-with-yield.md
+ - Security:
+ - tutorial/security/index.md
+ - tutorial/security/first-steps.md
+ - tutorial/security/get-current-user.md
+ - tutorial/security/simple-oauth2.md
+ - tutorial/security/oauth2-jwt.md
+ - tutorial/middleware.md
+ - tutorial/cors.md
+ - tutorial/sql-databases.md
+ - tutorial/bigger-applications.md
+ - tutorial/background-tasks.md
+ - tutorial/application-configuration.md
+ - tutorial/static-files.md
+ - tutorial/testing.md
+ - tutorial/debugging.md
+- Advanced User Guide:
+ - advanced/index.md
+ - advanced/path-operation-advanced-configuration.md
+ - advanced/additional-status-codes.md
+ - advanced/response-directly.md
+ - advanced/custom-response.md
+ - advanced/additional-responses.md
+ - advanced/response-cookies.md
+ - advanced/response-headers.md
+ - advanced/response-change-status-code.md
+ - advanced/advanced-dependencies.md
+ - Advanced Security:
+ - advanced/security/index.md
+ - advanced/security/oauth2-scopes.md
+ - advanced/security/http-basic-auth.md
+ - advanced/using-request-directly.md
+ - advanced/middleware.md
+ - advanced/sql-databases-peewee.md
+ - advanced/async-sql-databases.md
+ - advanced/nosql-databases.md
+ - advanced/sub-applications-proxy.md
+ - advanced/templates.md
+ - advanced/graphql.md
+ - advanced/websockets.md
+ - advanced/events.md
+ - advanced/custom-request-and-route.md
+ - advanced/testing-websockets.md
+ - advanced/testing-events.md
+ - advanced/testing-dependencies.md
+ - advanced/extending-openapi.md
+ - advanced/openapi-callbacks.md
+ - advanced/wsgi.md
+- async.md
+- deployment.md
+- project-generation.md
+- alternatives.md
+- history-design-future.md
+- external-links.md
+- benchmarks.md
+- help-fastapi.md
+- contributing.md
+- release-notes.md
+markdown_extensions:
+- toc:
+ permalink: true
+- markdown.extensions.codehilite:
+ guess_lang: false
+- markdown_include.include:
+ base_path: docs
+- admonition
+- codehilite
+- extra
+- pymdownx.superfences:
+ custom_fences:
+ - name: mermaid
+ class: mermaid
+ format: !!python/name:pymdownx.superfences.fence_div_format ''
+extra:
+ social:
+ - type: github
+ link: https://github.com/tiangolo/typer
+ - type: twitter
+ link: https://twitter.com/tiangolo
+ - type: linkedin
+ link: https://www.linkedin.com/in/tiangolo
+ - type: rss
+ link: https://dev.to/tiangolo
+ - type: medium
+ link: https://medium.com/@tiangolo
+ - type: globe
+ link: https://tiangolo.com
+extra_css:
+- css/termynal.css
+- css/custom.css
+extra_javascript:
+- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js
+- js/termynal.js
+- js/custom.js
--- /dev/null
+<p align="center">
+ <a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
+</p>
+<p align="center">
+ <em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
+</p>
+<p align="center">
+<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">
+</a>
+<a href="https://pypi.org/project/fastapi" target="_blank">
+ <img src="https://badge.fury.io/py/fastapi.svg" alt="Package version">
+</a>
+<a href="https://gitter.im/tiangolo/fastapi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge" target="_blank">
+ <img src="https://badges.gitter.im/tiangolo/fastapi.svg" alt="Join the chat at https://gitter.im/tiangolo/fastapi">
+</a>
+</p>
+
+---
+
+**Documentation**: <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
+
+**Source Code**: <a href="https://github.com/tiangolo/fastapi" target="_blank">https://github.com/tiangolo/fastapi</a>
+
+---
+
+FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints.
+
+The key features are:
+
+* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance).
+
+* **Fast to code**: Increase the speed to develop features by about 200% to 300% *.
+* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. *
+* **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. 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" 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>
+
+## Opinions
+
+"*[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products.*"
+
+<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/tiangolo/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
+
+---
+
+"*I’m over the moon excited about **FastAPI**. It’s so fun!*"
+
+<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> podcast host</strong> <a href="https://twitter.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
+
+---
+
+"*Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that.*"
+
+<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="http://www.hug.rest/" target="_blank">Hug</a> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
+
+---
+
+"*If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]*"
+
+"*We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]*"
+
+<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> founders - <a href="https://spacy.io" target="_blank">spaCy</a> creators</strong> <a href="https://twitter.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://twitter.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
+
+---
+
+"*We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]*"
+
+<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
+
+---
+
+## **Typer**, the FastAPI of CLIs
+
+<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
+
+If you are building a <abbr title="Command Line Interface">CLI</abbr> app to be used in the terminal instead of a web API, check out <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
+
+**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀
+
+## Requirements
+
+Python 3.6+
+
+FastAPI stands on the shoulders of giants:
+
+* <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
+
+<div class="termy">
+
+```console
+$ pip install fastapi
+
+---> 100%
+```
+
+</div>
+
+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>.
+
+<div class="termy">
+
+```console
+$ pip install uvicorn
+
+---> 100%
+```
+
+</div>
+
+## Example
+
+### Create it
+
+* Create a file `main.py` with:
+
+```Python
+from fastapi import FastAPI
+
+app = FastAPI()
+
+
+@app.get("/")
+def read_root():
+ return {"Hello": "World"}
+
+
+@app.get("/items/{item_id}")
+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>
+
+If your code uses `async` / `await`, use `async def`:
+
+```Python hl_lines="7 12"
+from fastapi import FastAPI
+
+app = FastAPI()
+
+
+@app.get("/")
+async def read_root():
+ return {"Hello": "World"}
+
+
+@app.get("/items/{item_id}")
+async def read_item(item_id: int, q: str = None):
+ return {"item_id": item_id, "q": q}
+```
+
+**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>
+
+### Run it
+
+Run the server with:
+
+<div class="termy">
+
+```console
+$ uvicorn main:app --reload
+
+<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+<span style="color: green;">INFO</span>: Started reloader process [28720]
+<span style="color: green;">INFO</span>: Started server process [28722]
+<span style="color: green;">INFO</span>: Waiting for application startup.
+<span style="color: green;">INFO</span>: Application startup complete.
+```
+
+</div>
+
+<details markdown="1">
+<summary>About the command <code>uvicorn main:app --reload</code>...</summary>
+
+The command `uvicorn main:app` refers to:
+
+* `main`: the file `main.py` (the Python "module").
+* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.
+* `--reload`: make the server restart after code changes. Only do this for development.
+
+</details>
+
+### Check it
+
+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:
+
+```JSON
+{"item_id": 5, "q": "somequery"}
+```
+
+You already created an API that:
+
+* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`.
+* Both _paths_ take `GET` <em>operations</em> (also known as HTTP _methods_).
+* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`.
+* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`.
+
+### Interactive API docs
+
+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" class="external-link" target="_blank">Swagger UI</a>):
+
+
+
+### Alternative API docs
+
+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" class="external-link" target="_blank">ReDoc</a>):
+
+
+
+## Example upgrade
+
+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 23 24 25"
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ price: float
+ is_offer: bool = None
+
+
+@app.get("/")
+def read_root():
+ return {"Hello": "World"}
+
+
+@app.get("/items/{item_id}")
+def read_item(item_id: int, q: str = None):
+ return {"item_id": item_id, "q": q}
+
+
+@app.put("/items/{item_id}")
+def update_item(item_id: int, item: Item):
+ return {"item_name": item.name, "item_id": item_id}
+```
+
+The server should reload automatically (because you added `--reload` to the `uvicorn` command above).
+
+### Interactive API docs upgrade
+
+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:
+
+
+
+* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API:
+
+
+
+* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen:
+
+
+
+### Alternative API docs upgrade
+
+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:
+
+
+
+### Recap
+
+In summary, you declare **once** the types of parameters, body, etc. as function parameters.
+
+You do that with standard modern Python types.
+
+You don't have to learn a new syntax, the methods or classes of a specific library, etc.
+
+Just standard **Python 3.6+**.
+
+For example, for an `int`:
+
+```Python
+item_id: int
+```
+
+or for a more complex `Item` model:
+
+```Python
+item: Item
+```
+
+...and with that single declaration you get:
+
+* Editor support, including:
+ * Completion.
+ * Type checks.
+* Validation of data:
+ * Automatic and clear errors when the data is invalid.
+ * Validation even for deeply nested JSON objects.
+* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of input data: coming from the network to Python data and types. Reading from:
+ * JSON.
+ * Path parameters.
+ * Query parameters.
+ * Cookies.
+ * Headers.
+ * Forms.
+ * Files.
+* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of output data: converting from Python data and types to network data (as JSON):
+ * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc).
+ * `datetime` objects.
+ * `UUID` objects.
+ * Database models.
+ * ...and many more.
+* Automatic interactive API documentation, including 2 alternative user interfaces:
+ * Swagger UI.
+ * ReDoc.
+
+---
+
+Coming back to the previous code example, **FastAPI** will:
+
+* Validate that there is an `item_id` in the path for `GET` and `PUT` requests.
+* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests.
+ * If it is not, the client will see a useful, clear error.
+* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests.
+ * As the `q` parameter is declared with `= None`, it is optional.
+ * Without the `None` it would be required (as is the body in the case with `PUT`).
+* For `PUT` requests to `/items/{item_id}`, Read the body as JSON:
+ * Check that it has a required attribute `name` that should be a `str`.
+ * Check that it has a required attribute `price` that has to be a `float`.
+ * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present.
+ * All this would also work for deeply nested JSON objects.
+* Convert from and to JSON automatically.
+* Document everything with OpenAPI, that can be used by:
+ * Interactive documentation systems.
+ * 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.
+
+Try changing the line with:
+
+```Python
+ return {"item_name": item.name, "item_id": item_id}
+```
+
+...from:
+
+```Python
+ ... "item_name": item.name ...
+```
+
+...to:
+
+```Python
+ ... "item_price": item.price ...
+```
+
+...and see how your editor will auto-complete the attributes and know their types:
+
+
+
+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:
+
+* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**.
+* How to set **validation constraints** as `maximum_length` or `regex`.
+* A very powerful and easy to use **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** system.
+* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth.
+* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic).
+* Many extra features (thanks to Starlette) as:
+ * **WebSockets**
+ * **GraphQL**
+ * extremely easy tests based on `requests` and `pytest`
+ * **CORS**
+ * **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" 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/" class="internal-link" target="_blank">Benchmarks</a>.
+
+## Optional Dependencies
+
+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`.
+* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Required if you want to use `FileResponse` or `StaticFiles`.
+* <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 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`.
+
+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.
+* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Required if you want to use `ORJSONResponse`.
+
+You can install all of these with `pip install fastapi[all]`.
+
+## License
+
+This project is licensed under the terms of the MIT license.
--- /dev/null
+site_name: FastAPI
+site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production
+site_url: https://fastapi.tiangolo.com/es/
+theme:
+ name: material
+ palette:
+ primary: teal
+ accent: amber
+ logo: https://fastapi.tiangolo.com/img/icon-white.svg
+ favicon: https://fastapi.tiangolo.com/img/favicon.png
+ language: es
+repo_name: tiangolo/fastapi
+repo_url: https://github.com/tiangolo/fastapi
+edit_uri: ''
+google_analytics:
+- UA-133183413-1
+- auto
+nav:
+- FastAPI: index.md
+- Languages:
+ - en: /
+ - es: /es/
+markdown_extensions:
+- toc:
+ permalink: true
+- markdown.extensions.codehilite:
+ guess_lang: false
+- markdown_include.include:
+ base_path: docs
+- admonition
+- codehilite
+- extra
+- pymdownx.superfences:
+ custom_fences:
+ - name: mermaid
+ class: mermaid
+ format: !!python/name:pymdownx.superfences.fence_div_format ''
+extra:
+ social:
+ - type: github
+ link: https://github.com/tiangolo/typer
+ - type: twitter
+ link: https://twitter.com/tiangolo
+ - type: linkedin
+ link: https://www.linkedin.com/in/tiangolo
+ - type: rss
+ link: https://dev.to/tiangolo
+ - type: medium
+ link: https://medium.com/@tiangolo
+ - type: globe
+ link: https://tiangolo.com
+extra_css:
+- https://fastapi.tiangolo.com/css/termynal.css
+- https://fastapi.tiangolo.com/css/custom.css
+extra_javascript:
+- https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js
+- https://fastapi.tiangolo.com/js/termynal.js
+- https://fastapi.tiangolo.com/js/custom.js
--- /dev/null
+!!! warning
+ The current page still doesn't have a translation for this language.
+
+ But you can help translating it: [Contributing](https://fastapi.tiangolo.com/contributing/){.internal-link target=_blank}.
+++ /dev/null
-site_name: FastAPI
-site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production
-site_url: https://fastapi.tiangolo.com/
-
-theme:
- name: 'material'
- palette:
- primary: 'teal'
- accent: 'amber'
- logo: 'img/icon-white.svg'
- favicon: 'img/favicon.png'
-
-repo_name: tiangolo/fastapi
-repo_url: https://github.com/tiangolo/fastapi
-edit_uri: ''
-google_analytics:
- - 'UA-133183413-1'
- - 'auto'
-
-nav:
- - FastAPI: 'index.md'
- - Features: 'features.md'
- - Python types intro: 'python-types.md'
- - Tutorial - User Guide:
- - Tutorial - User Guide - Intro: 'tutorial/index.md'
- - First Steps: 'tutorial/first-steps.md'
- - Path Parameters: 'tutorial/path-params.md'
- - Query Parameters: 'tutorial/query-params.md'
- - Request Body: 'tutorial/body.md'
- - Query Parameters and String Validations: 'tutorial/query-params-str-validations.md'
- - Path Parameters and Numeric Validations: 'tutorial/path-params-numeric-validations.md'
- - Body - Multiple Parameters: 'tutorial/body-multiple-params.md'
- - Body - Fields: 'tutorial/body-fields.md'
- - Body - Nested Models: 'tutorial/body-nested-models.md'
- - Extra data types: 'tutorial/extra-data-types.md'
- - Cookie Parameters: 'tutorial/cookie-params.md'
- - Header Parameters: 'tutorial/header-params.md'
- - Response Model: 'tutorial/response-model.md'
- - Extra Models: 'tutorial/extra-models.md'
- - Response Status Code: 'tutorial/response-status-code.md'
- - Form Data: 'tutorial/request-forms.md'
- - Request Files: 'tutorial/request-files.md'
- - Request Forms and Files: 'tutorial/request-forms-and-files.md'
- - Handling Errors: 'tutorial/handling-errors.md'
- - Path Operation Configuration: 'tutorial/path-operation-configuration.md'
- - JSON Compatible Encoder: 'tutorial/encoder.md'
- - Body - updates: 'tutorial/body-updates.md'
- - Dependencies:
- - First Steps: 'tutorial/dependencies/index.md'
- - Classes as Dependencies: 'tutorial/dependencies/classes-as-dependencies.md'
- - Sub-dependencies: 'tutorial/dependencies/sub-dependencies.md'
- - Dependencies in path operation decorators: 'tutorial/dependencies/dependencies-in-path-operation-decorators.md'
- - Dependencies with yield: 'tutorial/dependencies/dependencies-with-yield.md'
- - Security:
- - Security Intro: 'tutorial/security/index.md'
- - First Steps: 'tutorial/security/first-steps.md'
- - Get Current User: 'tutorial/security/get-current-user.md'
- - Simple OAuth2 with Password and Bearer: 'tutorial/security/simple-oauth2.md'
- - OAuth2 with Password (and hashing), Bearer with JWT tokens: 'tutorial/security/oauth2-jwt.md'
- - Middleware: 'tutorial/middleware.md'
- - CORS (Cross-Origin Resource Sharing): 'tutorial/cors.md'
- - SQL (Relational) Databases: 'tutorial/sql-databases.md'
- - Bigger Applications - Multiple Files: 'tutorial/bigger-applications.md'
- - Background Tasks: 'tutorial/background-tasks.md'
- - Application Configuration: 'tutorial/application-configuration.md'
- - Static Files: 'tutorial/static-files.md'
- - Testing: 'tutorial/testing.md'
- - Debugging: 'tutorial/debugging.md'
- - Advanced User Guide:
- - Advanced User Guide - Intro: 'advanced/index.md'
- - Path Operation Advanced Configuration: 'advanced/path-operation-advanced-configuration.md'
- - Additional Status Codes: 'advanced/additional-status-codes.md'
- - Return a Response Directly: 'advanced/response-directly.md'
- - Custom Response - HTML, Stream, File, others: 'advanced/custom-response.md'
- - Additional Responses in OpenAPI: 'advanced/additional-responses.md'
- - Response Cookies: 'advanced/response-cookies.md'
- - Response Headers: 'advanced/response-headers.md'
- - Response - Change Status Code: 'advanced/response-change-status-code.md'
- - Advanced Dependencies: 'advanced/advanced-dependencies.md'
- - Advanced Security:
- - Advanced Security - Intro: 'advanced/security/index.md'
- - OAuth2 scopes: 'advanced/security/oauth2-scopes.md'
- - HTTP Basic Auth: 'advanced/security/http-basic-auth.md'
- - Using the Request Directly: 'advanced/using-request-directly.md'
- - Advanced Middleware: 'advanced/middleware.md'
- - SQL (Relational) Databases with Peewee: 'advanced/sql-databases-peewee.md'
- - Async SQL (Relational) Databases: 'advanced/async-sql-databases.md'
- - NoSQL (Distributed / Big Data) Databases: 'advanced/nosql-databases.md'
- - Sub Applications - Behind a Proxy, Mounts: 'advanced/sub-applications-proxy.md'
- - Templates: 'advanced/templates.md'
- - GraphQL: 'advanced/graphql.md'
- - WebSockets: 'advanced/websockets.md'
- - 'Events: startup - shutdown': 'advanced/events.md'
- - Custom Request and APIRoute class: 'advanced/custom-request-and-route.md'
- - Testing WebSockets: 'advanced/testing-websockets.md'
- - 'Testing Events: startup - shutdown': 'advanced/testing-events.md'
- - Testing Dependencies with Overrides: 'advanced/testing-dependencies.md'
- - Extending OpenAPI: 'advanced/extending-openapi.md'
- - OpenAPI Callbacks: 'advanced/openapi-callbacks.md'
- - Including WSGI - Flask, Django, others: 'advanced/wsgi.md'
- - Concurrency and async / await: 'async.md'
- - Deployment: 'deployment.md'
- - Project Generation - Template: 'project-generation.md'
- - Alternatives, Inspiration and Comparisons: 'alternatives.md'
- - History, Design and Future: 'history-design-future.md'
- - External Links and Articles: 'external-links.md'
- - Benchmarks: 'benchmarks.md'
- - Help FastAPI - Get Help: 'help-fastapi.md'
- - Development - Contributing: 'contributing.md'
- - Release Notes: 'release-notes.md'
-
-markdown_extensions:
- - toc:
- permalink: true
- - markdown.extensions.codehilite:
- guess_lang: false
- - markdown_include.include:
- base_path: docs
- - admonition
- - codehilite
- - extra
- - pymdownx.superfences:
- custom_fences:
- - name: mermaid
- class: mermaid
- format: !!python/name:pymdownx.superfences.fence_div_format
-
-extra:
- social:
- - type: 'github'
- link: 'https://github.com/tiangolo/typer'
- - type: 'twitter'
- link: 'https://twitter.com/tiangolo'
- - type: 'linkedin'
- link: 'https://www.linkedin.com/in/tiangolo'
- - type: 'rss'
- link: 'https://dev.to/tiangolo'
- - type: 'medium'
- link: 'https://medium.com/@tiangolo'
- - type: 'globe'
- link: 'https://tiangolo.com'
-
-extra_css:
- - 'css/termynal.css'
- - 'css/custom.css'
-
-extra_javascript:
- - 'https://unpkg.com/mermaid@8.4.6/dist/mermaid.min.js'
- - 'js/termynal.js'
- - 'js/custom.js'
doc = [
"mkdocs",
"mkdocs-material",
- "markdown-include"
+ "markdown-include",
+ "typer",
+ "typer-cli",
+ "pyyaml"
]
dev = [
"pyjwt",
#!/usr/bin/env bash
-python -m mkdocs build
+set -e
+set -x
-cp ./docs/index.md ./README.md
+python ./scripts/docs.py build-all
--- /dev/null
+import os
+import shutil
+from http.server import HTTPServer, SimpleHTTPRequestHandler
+from pathlib import Path
+from typing import Dict, Optional, Tuple
+
+import mkdocs.commands.build
+import mkdocs.commands.serve
+import mkdocs.config
+import mkdocs.utils
+import typer
+import yaml
+
+app = typer.Typer()
+
+mkdocs_name = "mkdocs.yml"
+
+missing_translation_snippet = """
+{!../../../docs/missing-translation.md!}
+"""
+
+docs_path = Path("docs")
+
+
+def lang_callback(lang: Optional[str]):
+ if lang is None:
+ return
+ if not lang.isalpha() or len(lang) != 2:
+ typer.echo("Use a 2 letter language code, like: es")
+ raise typer.Abort()
+ lang = lang.lower()
+ return lang
+
+
+def complete_existing_lang(incomplete: str):
+ lang_path: Path
+ for lang_path in docs_path.iterdir():
+ if lang_path.is_dir() and lang_path.name.startswith(incomplete):
+ yield lang_path.name
+
+
+@app.command()
+def new_lang(lang: str = typer.Argument(..., callback=lang_callback)):
+ """
+ Generate a new docs translation directory for the language LANG.
+
+ LANG should be a 2-letter language code, like: en, es, de, pt, etc.
+ """
+ new_path: Path = Path("docs") / lang
+ if new_path.exists():
+ typer.echo(f"The language was already created: {lang}")
+ raise typer.Abort()
+ new_path.mkdir()
+ en_docs_path = Path("docs/en")
+ en_config_path: Path = en_docs_path / mkdocs_name
+ en_config: dict = mkdocs.utils.yaml_load(en_config_path.read_text())
+ fastapi_url_base = "https://fastapi.tiangolo.com/"
+ new_config = {}
+ new_config["site_name"] = en_config["site_name"]
+ new_config["site_description"] = en_config["site_description"]
+ new_config["site_url"] = en_config["site_url"] + f"{lang}/"
+ new_config["theme"] = en_config["theme"]
+ new_config["theme"]["logo"] = fastapi_url_base + en_config["theme"]["logo"]
+ new_config["theme"]["favicon"] = fastapi_url_base + en_config["theme"]["favicon"]
+ new_config["theme"]["language"] = lang
+ new_config["repo_name"] = en_config["repo_name"]
+ new_config["repo_url"] = en_config["repo_url"]
+ new_config["edit_uri"] = en_config["edit_uri"]
+ new_config["google_analytics"] = en_config["google_analytics"]
+ new_config["nav"] = en_config["nav"][:2]
+
+ new_config["markdown_extensions"] = en_config["markdown_extensions"]
+ new_config["extra"] = en_config["extra"]
+
+ extra_css = []
+ css: str
+ for css in en_config["extra_css"]:
+ if css.startswith("http"):
+ extra_css.append(css)
+ else:
+ extra_css.append(fastapi_url_base + css)
+ new_config["extra_css"] = extra_css
+
+ extra_js = []
+ js: str
+ for js in en_config["extra_javascript"]:
+ if js.startswith("http"):
+ extra_js.append(js)
+ else:
+ extra_js.append(fastapi_url_base + js)
+ new_config["extra_javascript"] = extra_js
+ new_config_path: Path = Path(new_path) / mkdocs_name
+ new_config_path.write_text(yaml.dump(new_config, sort_keys=False, width=200))
+ new_config_docs_path: Path = new_path / "docs"
+ new_config_docs_path.mkdir()
+ en_index_path: Path = en_docs_path / "docs" / "index.md"
+ new_index_path: Path = new_config_docs_path / "index.md"
+ en_index_content = en_index_path.read_text()
+ new_index_content = f"{missing_translation_snippet}\n\n{en_index_content}"
+ new_index_path.write_text(new_index_content)
+ typer.secho(f"Successfully initialized: {new_path}", color=typer.colors.GREEN)
+ update_languages(lang=None)
+
+
+@app.command()
+def build_lang(
+ lang: str = typer.Argument(
+ ..., callback=lang_callback, autocompletion=complete_existing_lang
+ )
+):
+ """
+ Build the docs for a language, filling missing pages with translation notifications.
+ """
+ lang_path: Path = Path("docs") / lang
+ if not lang_path.is_dir():
+ typer.echo(f"The language translation doesn't seem to exist yet: {lang}")
+ raise typer.Abort()
+ typer.echo(f"Building docs for: {lang}")
+ build_dir_path = Path("docs_build")
+ build_dir_path.mkdir(exist_ok=True)
+ build_lang_path = build_dir_path / lang
+ en_lang_path = Path("docs/en")
+ site_path = Path("site").absolute()
+ if lang == "en":
+ dist_path = site_path
+ else:
+ dist_path: Path = site_path / lang
+ shutil.rmtree(build_lang_path, ignore_errors=True)
+ shutil.copytree(lang_path, build_lang_path)
+ en_config_path: Path = en_lang_path / mkdocs_name
+ en_config: dict = mkdocs.utils.yaml_load(en_config_path.read_text())
+ nav = en_config["nav"]
+ lang_config_path: Path = lang_path / mkdocs_name
+ lang_config: dict = mkdocs.utils.yaml_load(lang_config_path.read_text())
+ lang_nav = lang_config["nav"]
+ # Exclude first 2 entries FastAPI and Languages, for custom handling
+ use_nav = nav[2:]
+ lang_use_nav = lang_nav[2:]
+ file_to_nav = get_file_to_nav_map(use_nav)
+ sections = get_sections(use_nav)
+ lang_file_to_nav = get_file_to_nav_map(lang_use_nav)
+ use_lang_file_to_nav = get_file_to_nav_map(lang_use_nav)
+ for file in file_to_nav:
+ file_path = Path(file)
+ lang_file_path: Path = build_lang_path / "docs" / file_path
+ en_file_path: Path = en_lang_path / "docs" / file_path
+ lang_file_path.parent.mkdir(parents=True, exist_ok=True)
+ if not lang_file_path.is_file():
+ en_text = en_file_path.read_text()
+ lang_text = get_text_with_translate_missing(en_text)
+ lang_file_path.write_text(lang_text)
+ file_key = file_to_nav[file]
+ use_lang_file_to_nav[file] = file_key
+ if file_key:
+ composite_key = ()
+ new_key = ()
+ for key_part in file_key:
+ composite_key += (key_part,)
+ key_first_file = sections[composite_key]
+ if key_first_file in lang_file_to_nav:
+ new_key = lang_file_to_nav[key_first_file]
+ else:
+ new_key += (key_part,)
+ use_lang_file_to_nav[file] = new_key
+ key_to_section = {(): []}
+ for file, file_key in use_lang_file_to_nav.items():
+ section = get_key_section(key_to_section=key_to_section, key=file_key)
+ section.append(file)
+ new_nav = key_to_section[()]
+ export_lang_nav = [lang_nav[0], nav[1]] + new_nav
+ lang_config["nav"] = export_lang_nav
+ build_lang_config_path: Path = build_lang_path / mkdocs_name
+ build_lang_config_path.write_text(
+ yaml.dump(lang_config, sort_keys=False, width=200)
+ )
+ current_dir = os.getcwd()
+ os.chdir(build_lang_path)
+ mkdocs.commands.build.build(mkdocs.config.load_config(site_dir=str(dist_path)))
+ os.chdir(current_dir)
+ typer.secho(f"Successfully built docs for: {lang}", color=typer.colors.GREEN)
+
+
+@app.command()
+def build_all():
+ """
+ Build mkdocs site for en, and then build each language inside, end result is located
+ at directory ./site/ with each language inside.
+ """
+ site_path = Path("site").absolute()
+ update_languages(lang=None)
+ en_build_path: Path = docs_path / "en"
+ current_dir = os.getcwd()
+ os.chdir(en_build_path)
+ typer.echo(f"Building docs for: en")
+ mkdocs.commands.build.build(mkdocs.config.load_config(site_dir=str(site_path)))
+ os.chdir(current_dir)
+ for lang in docs_path.iterdir():
+ if lang == en_build_path or not lang.is_dir():
+ continue
+ build_lang(lang.name)
+ typer.echo("Copying en index.md to README.md")
+ en_index = en_build_path / "docs" / "index.md"
+ shutil.copyfile(en_index, "README.md")
+
+
+@app.command()
+def update_languages(
+ lang: str = typer.Argument(
+ None, callback=lang_callback, autocompletion=complete_existing_lang
+ )
+):
+ """
+ Update the mkdocs.yml file Languages section including all the available languages.
+
+ The LANG argument is a 2-letter language code. If it's not provided, update all the
+ mkdocs.yml files (for all the languages).
+ """
+ if lang is None:
+ for lang_path in docs_path.iterdir():
+ if lang_path.is_dir():
+ typer.echo(f"Updating {lang_path.name}")
+ update_config(lang_path.name)
+ else:
+ typer.echo(f"Updating {lang}")
+ update_config(lang)
+
+
+@app.command()
+def serve():
+ """
+ A quick server to preview a built site with translations.
+
+ For development, prefer the command live (or just mkdocs serve).
+
+ This is here only to preview a site with translations already built.
+
+ Make sure you run the build-all command first.
+ """
+ typer.echo(
+ "Warning: this is a very simple server."
+ + "For development, use mkdocs serve instead."
+ )
+ typer.echo("This is here only to preview a site with translations already built.")
+ typer.echo("Make sure you run the build-all command first.")
+ os.chdir("site")
+ server_address = ("", 8008)
+ server = HTTPServer(server_address, SimpleHTTPRequestHandler)
+ typer.echo(f"Serving at: http://0.0.0.0:8008")
+ server.serve_forever()
+
+
+@app.command()
+def live(
+ lang: str = typer.Argument(
+ None, callback=lang_callback, autocompletion=complete_existing_lang
+ )
+):
+ """
+ Serve with livereload a docs site for a specific language.
+
+ This only shows the actual translated files, not the placeholders created with
+ build-all.
+
+ Takes an optional LANG argument with the name of the language to serve, by default
+ en.
+ """
+ if lang is None:
+ lang = "en"
+ lang_path: Path = docs_path / lang
+ os.chdir(lang_path)
+ mkdocs.commands.serve.serve(dev_addr="0.0.0.0:8008")
+
+
+def update_config(lang: str):
+ lang_path: Path = docs_path / lang
+ config_path = lang_path / mkdocs_name
+ config: dict = mkdocs.utils.yaml_load(config_path.read_text())
+ languages = [{"en": "/"}]
+ for lang in docs_path.iterdir():
+ if lang.name == "en" or not lang.is_dir():
+ continue
+ name = lang.name
+ languages.append({name: f"/{name}/"})
+ config["nav"][1] = {"Languages": languages}
+ config_path.write_text(yaml.dump(config, sort_keys=False, width=200))
+
+
+def get_key_section(
+ *, key_to_section: Dict[Tuple[str, ...], list], key: Tuple[str, ...]
+) -> list:
+ if key in key_to_section:
+ return key_to_section[key]
+ super_key = key[:-1]
+ title = key[-1]
+ super_section = get_key_section(key_to_section=key_to_section, key=super_key)
+ new_section = []
+ super_section.append({title: new_section})
+ key_to_section[key] = new_section
+ return new_section
+
+
+def get_text_with_translate_missing(text: str) -> str:
+ lines = text.splitlines()
+ lines.insert(1, missing_translation_snippet)
+ new_text = "\n".join(lines)
+ return new_text
+
+
+def get_file_to_nav_map(nav: list) -> Dict[str, Tuple[str, ...]]:
+ file_to_nav = {}
+ for item in nav:
+ if type(item) is str:
+ file_to_nav[item] = tuple()
+ elif type(item) is dict:
+ item_key = list(item.keys())[0]
+ sub_nav = item[item_key]
+ sub_file_to_nav = get_file_to_nav_map(sub_nav)
+ for k, v in sub_file_to_nav.items():
+ file_to_nav[k] = (item_key,) + v
+ return file_to_nav
+
+
+def get_sections(nav: list) -> Dict[Tuple[str, ...], str]:
+ sections = {}
+ for item in nav:
+ if type(item) is str:
+ continue
+ elif type(item) is dict:
+ item_key = list(item.keys())[0]
+ sub_nav = item[item_key]
+ sections[(item_key,)] = sub_nav[0]
+ sub_sections = get_sections(sub_nav)
+ for k, v in sub_sections.items():
+ new_key = (item_key,) + k
+ sections[new_key] = v
+ return sections
+
+
+if __name__ == "__main__":
+ app()
set -x
# Sort imports one per line, so autoflake can remove unused imports
-isort --recursive --force-single-line-imports --thirdparty fastapi --apply fastapi tests docs/src
+isort --recursive --force-single-line-imports --thirdparty fastapi --apply fastapi tests docs_src scripts
sh ./scripts/format.sh
#!/bin/sh -e
set -x
-autoflake --remove-all-unused-imports --recursive --remove-unused-variables --in-place docs/src/ fastapi tests --exclude=__init__.py
-black fastapi tests docs/src
-isort --multi-line=3 --trailing-comma --force-grid-wrap=0 --combine-as --line-width 88 --recursive --thirdparty fastapi --apply fastapi tests docs/src
+autoflake --remove-all-unused-imports --recursive --remove-unused-variables --in-place docs_src fastapi tests scripts --exclude=__init__.py
+black fastapi tests docs_src scripts
+isort --multi-line=3 --trailing-comma --force-grid-wrap=0 --combine-as --line-width 88 --recursive --thirdparty fastapi --apply fastapi tests docs_src scripts
fi
bash ./scripts/lint.sh
# Check README.md is up to date
-diff --brief docs/index.md README.md
-export PYTHONPATH=./docs/src
-pytest --cov=fastapi --cov=tests --cov=docs/src --cov-report=term-missing ${@}
+diff --brief docs/en/docs/index.md README.md
+export PYTHONPATH=./docs_src
+pytest --cov=fastapi --cov=tests --cov=docs/src --cov-report=term-missing tests ${@}
def test_path_operation_img():
- shutil.copy("./docs/img/favicon.png", "./image.png")
+ shutil.copy("./docs/en/docs/img/favicon.png", "./image.png")
response = client.get("/items/foo?img=1")
assert response.status_code == 200
assert response.headers["Content-Type"] == "image/png"
def test_path_operation_img():
- shutil.copy("./docs/img/favicon.png", "./image.png")
+ shutil.copy("./docs/en/docs/img/favicon.png", "./image.png")
response = client.get("/items/foo?img=1")
assert response.status_code == 200
assert response.headers["Content-Type"] == "image/png"
def test_main():
- shutil.copytree("./docs/src/templates/templates/", "./templates")
- shutil.copytree("./docs/src/templates/static/", "./static")
+ shutil.copytree("./docs_src/templates/templates/", "./templates")
+ shutil.copytree("./docs_src/templates/static/", "./static")
from templates.tutorial001 import app
client = TestClient(app)