mirror of
https://github.com/fastapi/fastapi.git
synced 2026-10-22 18:06:17 -04:00
🎨 Tweak external links, Markdown format, typos (#881)
This commit is contained in:
1 parent
174e7b1730
commit
a41a729682
60 files changed
+341
-418
No files matched your search
@@ -1,6 +1,6 @@
|
||||
!!! warning
|
||||
This is a rather advanced topic.
|
||||
|
||||
|
||||
If you are starting with **FastAPI**, you might not need this.
|
||||
|
||||
You can declare additional responses, with additional status codes, media types, descriptions, etc.
|
||||
@@ -21,7 +21,6 @@ Each of those response `dict`s can have a key `model`, containing a Pydantic mod
|
||||
|
||||
For example, to declare another response with a status code `404` and a Pydantic model `Message`, you can write:
|
||||
|
||||
|
||||
```Python hl_lines="18 23"
|
||||
{!./src/additional_responses/tutorial001.py!}
|
||||
```
|
||||
@@ -199,7 +198,6 @@ It will all be combined and included in your OpenAPI, and shown in the API docs:
|
||||
|
||||
<img src="/img/tutorial/additional-responses/image01.png">
|
||||
|
||||
|
||||
## Combine predefined responses and custom ones
|
||||
|
||||
You might want to have some predefined responses that apply to many *path operations*, but you want to combine them with custom responses needed by each *path operation*.
|
||||
@@ -236,5 +234,5 @@ For example:
|
||||
|
||||
To see what exactly you can include in the responses, you can check these sections in the OpenAPI specification:
|
||||
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responsesObject" target="_blank">OpenAPI Responses Object</a>, it includes the `Response Object`.
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responseObject" target="_blank">OpenAPI Response Object</a>, you can include anything from this directly in each response inside your `responses` parameter. Including `description`, `headers`, `content` (inside of this is that you declare different media types and JSON Schemas), and `links`.
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responsesObject" class="external-link" target="_blank">OpenAPI Responses Object</a>, it includes the `Response Object`.
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responseObject" class="external-link" target="_blank">OpenAPI Response Object</a>, you can include anything from this directly in each response inside your `responses` parameter. Including `description`, `headers`, `content` (inside of this is that you declare different media types and JSON Schemas), and `links`.
|
||||
@@ -1,4 +1,4 @@
|
||||
You can also use <a href="https://github.com/encode/databases" target="_blank">`encode/databases`</a> with **FastAPI** to connect to databases using `async` and `await`.
|
||||
You can also use <a href="https://github.com/encode/databases" class="external-link" target="_blank">`encode/databases`</a> with **FastAPI** to connect to databases using `async` and `await`.
|
||||
|
||||
It is compatible with:
|
||||
|
||||
@@ -13,7 +13,7 @@ Later, for your production application, you might want to use a database server
|
||||
!!! tip
|
||||
You could adopt ideas from the previous section about <a href="/tutorial/sql-databases/" target="_blank">SQLAlchemy ORM</a>, like using utility functions to perform operations in the database, independent of your **FastAPI** code.
|
||||
|
||||
This section doesn't apply those ideas, to be equivalent to the counterpart in <a href="https://www.starlette.io/database/" target="_blank">Starlette</a>.
|
||||
This section doesn't apply those ideas, to be equivalent to the counterpart in <a href="https://www.starlette.io/database/" class="external-link" target="_blank">Starlette</a>.
|
||||
|
||||
## Import and set up `SQLAlchemy`
|
||||
|
||||
@@ -149,7 +149,7 @@ So, the final result returned would be something like:
|
||||
|
||||
## Check it
|
||||
|
||||
You can copy this code as is, and see the docs at <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
You can copy this code as is, and see the docs at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
There you can see all your API documented and interact with it:
|
||||
|
||||
@@ -157,4 +157,4 @@ There you can see all your API documented and interact with it:
|
||||
|
||||
## More info
|
||||
|
||||
You can read more about <a href="https://github.com/encode/databases" target="_blank">`encode/databases` at its GitHub page</a>.
|
||||
You can read more about <a href="https://github.com/encode/databases" class="external-link" target="_blank">`encode/databases` at its GitHub page</a>.
|
||||
@@ -22,7 +22,6 @@ First, import `BackgroundTasks` and define a parameter in your *path operation f
|
||||
!!! tip
|
||||
You declare a parameter of `BackgroundTasks` and use it in a very similar way as to when <a href="/tutorial/using-request-directly/" target="_blank">using the `Request` directly</a>.
|
||||
|
||||
|
||||
## Create a task function
|
||||
|
||||
Create a function to be run as the background task.
|
||||
@@ -31,7 +30,7 @@ It is just a standard function that can receive parameters.
|
||||
|
||||
It can be an `async def` or normal `def` function, **FastAPI** will know how to handle it correctly.
|
||||
|
||||
In this case, the task function will write to a file (simulating sending an email).
|
||||
In this case, the task function will write to a file (simulating sending an email).
|
||||
|
||||
And as the write operation doesn't use `async` and `await`, we define the function with normal `def`:
|
||||
|
||||
@@ -71,7 +70,7 @@ And then another background task generated at the *path operation function* will
|
||||
|
||||
## Technical Details
|
||||
|
||||
The class `BackgroundTasks` comes directly from <a href="https://www.starlette.io/background/" target="_blank">`starlette.background`</a>.
|
||||
The class `BackgroundTasks` comes directly from <a href="https://www.starlette.io/background/" class="external-link" target="_blank">`starlette.background`</a>.
|
||||
|
||||
It is imported/included directly into FastAPI so that you can import it from `fastapi` and avoid accidentally importing the alternative `BackgroundTask` (without the `s` at the end) from `starlette.background`.
|
||||
|
||||
@@ -79,11 +78,11 @@ By only using `BackgroundTasks` (and not `BackgroundTask`), it's then possible t
|
||||
|
||||
It's still possible to use `BackgroundTask` alone in FastAPI, but you have to create the object in your code and return a Starlette `Response` including it.
|
||||
|
||||
You can see more details in <a href="https://www.starlette.io/background/" target="_blank">Starlette's official docs for Background Tasks</a>.
|
||||
You can see more details in <a href="https://www.starlette.io/background/" class="external-link" target="_blank">Starlette's official docs for Background Tasks</a>.
|
||||
|
||||
## Caveat
|
||||
|
||||
If you need to perform heavy background computation and you don't necessarily need it to be run by the same process (for example, you don't need to share memory, variables, etc), you might benefit from using other bigger tools like <a href="http://www.celeryproject.org/" target="_blank">Celery</a>.
|
||||
If you need to perform heavy background computation and you don't necessarily need it to be run by the same process (for example, you don't need to share memory, variables, etc), you might benefit from using other bigger tools like <a href="http://www.celeryproject.org/" class="external-link" target="_blank">Celery</a>.
|
||||
|
||||
They tend to require more complex configurations, a message/job queue manager, like RabbitMQ or Redis, but they allow you to run background tasks in multiple processes, and especially, in multiple servers.
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ Let's say you have a file structure like this:
|
||||
* The file `app/routers/users.py` is beside the `app/routers/__init__.py`.
|
||||
* So, it's a submodule: `app.routers.users`.
|
||||
|
||||
|
||||
## `APIRouter`
|
||||
|
||||
Let's say the file dedicated to handling just users is the submodule at `/app/routers/users.py`.
|
||||
@@ -55,7 +54,6 @@ But it's still part of the same **FastAPI** application/web API (it's part of th
|
||||
|
||||
You can create the *path operations* for that module using `APIRouter`.
|
||||
|
||||
|
||||
### Import `APIRouter`
|
||||
|
||||
You import it and create an "instance" the same way you would with the class `FastAPI`:
|
||||
@@ -64,7 +62,6 @@ You import it and create an "instance" the same way you would with the class `Fa
|
||||
{!./src/bigger_applications/app/routers/users.py!}
|
||||
```
|
||||
|
||||
|
||||
### Path operations with `APIRouter`
|
||||
|
||||
And then you use it to declare your *path operations*.
|
||||
@@ -86,7 +83,6 @@ All the same parameters, responses, dependencies, tags, etc.
|
||||
|
||||
We are going to include this `APIrouter` in the main `FastAPI` app, but first, let's add another `APIRouter`.
|
||||
|
||||
|
||||
## Another module with `APIRouter`
|
||||
|
||||
Let's say you also have the endpoints dedicated to handling "Items" from your application in the module at `app/routers/items.py`.
|
||||
@@ -144,7 +140,6 @@ We import the other submodules that have `APIRouter`s:
|
||||
|
||||
As the file `app/routers/items.py` is part of the same Python package, we can import it using "dot notation".
|
||||
|
||||
|
||||
### How the importing works
|
||||
|
||||
The section:
|
||||
@@ -172,7 +167,7 @@ from app.routers import items, users
|
||||
|
||||
The second version is an "absolute import".
|
||||
|
||||
To learn more about Python Packages and Modules, read <a href="https://docs.python.org/3/tutorial/modules.html" target="_blank">the official Python documentation about Modules</a>.
|
||||
To learn more about Python Packages and Modules, read <a href="https://docs.python.org/3/tutorial/modules.html" class="external-link" target="_blank">the official Python documentation about Modules</a>.
|
||||
|
||||
### Avoid name collisions
|
||||
|
||||
@@ -301,7 +296,7 @@ Now, run `uvicorn`, using the module `app.main` and the variable `app`:
|
||||
uvicorn app.main:app --reload
|
||||
```
|
||||
|
||||
And open the docs at <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
And open the docs at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
You will see the automatic API docs, including the paths from all the submodules, using the correct paths (and prefixes) and the correct tags:
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ First, you have to import it:
|
||||
!!! warning
|
||||
Notice that `Field` is imported directly from `pydantic`, not from `fastapi` as are all the rest (`Query`, `Path`, `Body`, etc).
|
||||
|
||||
|
||||
## Declare model attributes
|
||||
|
||||
You can then use `Field` with model attributes:
|
||||
@@ -45,7 +44,7 @@ If you know JSON Schema and want to add extra information apart from what we hav
|
||||
!!! warning
|
||||
Have in mind that extra parameters passed won't add any validation, only annotation, for documentation purposes.
|
||||
|
||||
For example, you can use that functionality to pass a <a href="http://json-schema.org/latest/json-schema-validation.html#rfc.section.8.5" target="_blank">JSON Schema example</a> field to a body request JSON Schema:
|
||||
For example, you can use that functionality to pass a <a href="http://json-schema.org/latest/json-schema-validation.html#rfc.section.8.5" class="external-link" target="_blank">JSON Schema example</a> field to a body request JSON Schema:
|
||||
|
||||
```Python hl_lines="20 21 22 23 24 25"
|
||||
{!./src/body_fields/tutorial002.py!}
|
||||
|
||||
@@ -116,7 +116,7 @@ Again, doing just that declaration, with **FastAPI** you get:
|
||||
|
||||
Apart from normal singular types like `str`, `int`, `float`, etc. You can use more complex singular types that inherit from `str`.
|
||||
|
||||
To see all the options you have, checkout the docs for <a href="https://pydantic-docs.helpmanual.io/#exotic-types" target="_blank">Pydantic's exotic types</a>. You will see some examples in the next chapter.
|
||||
To see all the options you have, checkout the docs for <a href="https://pydantic-docs.helpmanual.io/#exotic-types" class="external-link" target="_blank">Pydantic's exotic types</a>. You will see some examples in the next chapter.
|
||||
|
||||
For example, as in the `Image` model we have a `url` field, we can declare it to be instead of a `str`, a Pydantic's `HttpUrl`:
|
||||
|
||||
@@ -231,7 +231,7 @@ In this case, you would accept any `dict` as long as it has `int` keys with `flo
|
||||
|
||||
## Recap
|
||||
|
||||
With **FastAPI** you have the maximum flexibility provided by Pydantic models, while keeping your code simple, short and elegant.
|
||||
With **FastAPI** you have the maximum flexibility provided by Pydantic models, while keeping your code simple, short and elegant.
|
||||
|
||||
But with all the benefits:
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Update replacing with `PUT`
|
||||
|
||||
To update an item you can use the [HTTP `PUT`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT) operation.
|
||||
To update an item you can use the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT" class="external-link" target="_blank">HTTP `PUT`</a> operation.
|
||||
|
||||
You can use the `jsonable_encoder` to convert the input data to data that can be stored as JSON (e.g. with a NoSQL database). For example, converting `datetime` to `str`.
|
||||
|
||||
@@ -28,7 +28,7 @@ And the data would be saved with that "new" `tax` of `10.5`.
|
||||
|
||||
## Partial updates with `PATCH`
|
||||
|
||||
You can also use the [HTTP `PATCH`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) operation to *partially* update data.
|
||||
You can also use the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> operation to *partially* update data.
|
||||
|
||||
This means that you can send only the data that you want to update, leaving the rest intact.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ A **request** body is data sent by the client to your API. A **response** body i
|
||||
|
||||
Your API almost always has to send a **response** body. But clients don't necessarily need to send **request** bodies all the time.
|
||||
|
||||
To declare a **request** body, you use <a href="https://pydantic-docs.helpmanual.io/" target="_blank">Pydantic</a> models with all their power and benefits.
|
||||
To declare a **request** body, you use <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> models with all their power and benefits.
|
||||
|
||||
!!! info
|
||||
You cannot send a request body using a `GET` operation (HTTP method).
|
||||
@@ -71,7 +71,7 @@ With just that Python type declaration, **FastAPI** will:
|
||||
* If the data is invalid, it will return a nice and clear error, indicating exactly where and what was the incorrect data.
|
||||
* Give you the received data in the parameter `item`.
|
||||
* As you declared it in the function to be of type `Item`, you will also have all the editor support (completion, etc) for all of the attributes and their types.
|
||||
* Generate <a href="http://json-schema.org" target="_blank">JSON Schema</a> definitions for your model, you can also use them anywhere else you like if it makes sense for your project.
|
||||
* Generate <a href="http://json-schema.org" class="external-link" target="_blank">JSON Schema</a> definitions for your model, you can also use them anywhere else you like if it makes sense for your project.
|
||||
* Those schemas will be part of the generated OpenAPI schema, and used by the automatic documentation <abbr title="User Interfaces">UIs</abbr>.
|
||||
|
||||
## Automatic docs
|
||||
@@ -100,13 +100,12 @@ And it was thoroughly tested at the design phase, before any implementation, to
|
||||
|
||||
There were even some changes to Pydantic itself to support this.
|
||||
|
||||
The previous screenshots were taken with <a href="https://code.visualstudio.com" target="_blank">Visual Studio Code</a>.
|
||||
The previous screenshots were taken with <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a>.
|
||||
|
||||
But you would get the same editor support with <a href="https://www.jetbrains.com/pycharm/" target="_blank">PyCharm</a> and most of the other Python editors:
|
||||
But you would get the same editor support with <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> and most of the other Python editors:
|
||||
|
||||
<img src="/img/tutorial/body/image05.png">
|
||||
|
||||
|
||||
## Use the model
|
||||
|
||||
Inside of the function, you can access all the attributes of the model object directly:
|
||||
@@ -139,4 +138,4 @@ The function parameters will be recognized as follows:
|
||||
|
||||
* If the parameter is also declared in the **path**, it will be used as a path parameter.
|
||||
* If the parameter is of a **singular type** (like `int`, `float`, `str`, `bool`, etc) it will be interpreted as a **query** parameter.
|
||||
* If the parameter is declared to be of the type of a **Pydantic model**, it will be interpreted as a request **body**.
|
||||
* If the parameter is declared to be of the type of a **Pydantic model**, it will be interpreted as a request **body**.
|
||||
@@ -1,4 +1,4 @@
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" target="_blank">CORS or "Cross-Origin Resource Sharing"</a> refers to the situations when a frontend running in a browser has JavaScript code that communicates with a backend, and the backend is in a different "origin" than the frontend.
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">CORS or "Cross-Origin Resource Sharing"</a> refers to the situations when a frontend running in a browser has JavaScript code that communicates with a backend, and the backend is in a different "origin" than the frontend.
|
||||
|
||||
## Origin
|
||||
|
||||
@@ -32,7 +32,7 @@ So, for everything to work correctly, it's better to specify explicitly the allo
|
||||
|
||||
## Use `CORSMiddleware`
|
||||
|
||||
You can configure it in your **FastAPI** application using Starlette's <a href="https://www.starlette.io/middleware/#corsmiddleware" target="_blank">`CORSMiddleware`</a>.
|
||||
You can configure it in your **FastAPI** application using Starlette's <a href="https://www.starlette.io/middleware/#corsmiddleware" class="external-link" target="_blank">`CORSMiddleware`</a>.
|
||||
|
||||
* Import it from Starlette.
|
||||
* Create a list of allowed origins (as strings).
|
||||
@@ -50,6 +50,6 @@ You can also specify if your backend allows:
|
||||
|
||||
## More info
|
||||
|
||||
For more details of what you can specify in `CORSMiddleware`, check <a href="https://www.starlette.io/middleware/#corsmiddleware" target="_blank">Starlette's `CORSMiddleware` docs</a>.
|
||||
For more details of what you can specify in `CORSMiddleware`, check <a href="https://www.starlette.io/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette's `CORSMiddleware` docs</a>.
|
||||
|
||||
For more info about <abbr title="Cross-Origin Resource Sharing">CORS</abbr>, check the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" target="_blank">Mozilla CORS documentation</a>.
|
||||
For more info about <abbr title="Cross-Origin Resource Sharing">CORS</abbr>, check the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">Mozilla CORS documentation</a>.
|
||||
@@ -13,7 +13,7 @@ For example, if you want to read or manipulate the request body before it is pro
|
||||
|
||||
Some use cases include:
|
||||
|
||||
* Converting non-JSON request bodies to JSON (e.g. [`msgpack`](https://msgpack.org/index.html)).
|
||||
* Converting non-JSON request bodies to JSON (e.g. <a href="https://msgpack.org/index.html" class="external-link" target="_blank">`msgpack`</a>).
|
||||
* Decompressing gzip-compressed request bodies.
|
||||
* Automatically logging all request bodies.
|
||||
|
||||
@@ -58,7 +58,7 @@ Here we use it to create a `GzipRequest` from the original request.
|
||||
|
||||
And those two things, `scope` and `receive`, are what is needed to create a new `Request` instance.
|
||||
|
||||
To learn more about the `Request` check <a href="https://www.starlette.io/requests/" target="_blank">Starlette's docs about Requests</a>.
|
||||
To learn more about the `Request` check <a href="https://www.starlette.io/requests/" class="external-link" target="_blank">Starlette's docs about Requests</a>.
|
||||
|
||||
The only thing the function returned by `GzipRequest.get_route_handler` does differently is convert the `Request` to a `GzipRequest`.
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ So, the line:
|
||||
will not be executed.
|
||||
|
||||
!!! info
|
||||
For more information, check <a href="https://docs.python.org/3/library/__main__.html" target="_blank">the official Python docs</a>.
|
||||
For more information, check <a href="https://docs.python.org/3/library/__main__.html" class="external-link" target="_blank">the official Python docs</a>.
|
||||
|
||||
## Run your code with your debugger
|
||||
|
||||
|
||||
@@ -14,13 +14,13 @@ To do this, use `yield` instead of `return`, and write the extra steps after.
|
||||
pip install async-exit-stack async-generator
|
||||
```
|
||||
|
||||
This installs <a href="https://github.com/sorcio/async_exit_stack" target="_blank">async-exit-stack</a> and <a href="https://github.com/python-trio/async_generator" target="_blank">async-generator</a>.
|
||||
This installs <a href="https://github.com/sorcio/async_exit_stack" class="external-link" target="_blank">async-exit-stack</a> and <a href="https://github.com/python-trio/async_generator" target="_blank">async-generator</a>.
|
||||
|
||||
!!! note "Technical Details"
|
||||
Any function that is valid to use with:
|
||||
|
||||
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" target="_blank">`@contextlib.contextmanager`</a> or
|
||||
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager" target="_blank">`@contextlib.asynccontextmanager`</a>
|
||||
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" class="external-link" target="_blank">`@contextlib.contextmanager`</a> or
|
||||
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager" class="external-link" target="_blank">`@contextlib.asynccontextmanager`</a>
|
||||
|
||||
would be valid to use as a **FastAPI** dependency.
|
||||
|
||||
@@ -98,7 +98,7 @@ You can have any combinations of dependencies that you want.
|
||||
**FastAPI** will make sure everything is run in the correct order.
|
||||
|
||||
!!! note "Technical Details"
|
||||
This works thanks to Python's <a href="https://docs.python.org/3/library/contextlib.html" target="_blank">Context Managers</a>.
|
||||
This works thanks to Python's <a href="https://docs.python.org/3/library/contextlib.html" class="external-link" target="_blank">Context Managers</a>.
|
||||
|
||||
**FastAPI** uses them internally to achieve this.
|
||||
|
||||
@@ -108,7 +108,7 @@ You can have any combinations of dependencies that you want.
|
||||
|
||||
"Context Managers" are any of those Python objects that you can use in a `with` statement.
|
||||
|
||||
For example, <a href="https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files" target="_blank">you can use `with` to read a file</a>:
|
||||
For example, <a href="https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files" class="external-link" target="_blank">you can use `with` to read a file</a>:
|
||||
|
||||
```Python
|
||||
with open("./somefile.txt") as f:
|
||||
@@ -129,7 +129,7 @@ When you create a dependency with `yield`, **FastAPI** will internally convert i
|
||||
|
||||
If you are just starting with **FastAPI** you might want to skip it for now.
|
||||
|
||||
In Python, you can create context managers by <a href="https://docs.python.org/3/reference/datamodel.html#context-managers" target="_blank">creating a class with two methods: `__enter__()` and `__exit__()`</a>.
|
||||
In Python, you can create context managers by <a href="https://docs.python.org/3/reference/datamodel.html#context-managers" class="external-link" target="_blank">creating a class with two methods: `__enter__()` and `__exit__()`</a>.
|
||||
|
||||
You can also use them with **FastAPI** dependencies with `yield` by using
|
||||
`with` or `async with` statements inside of the dependency function:
|
||||
@@ -141,8 +141,8 @@ You can also use them with **FastAPI** dependencies with `yield` by using
|
||||
!!! tip
|
||||
Another way to create a context manager is with:
|
||||
|
||||
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" target="_blank">`@contextlib.contextmanager`</a> or
|
||||
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager" target="_blank">`@contextlib.asynccontextmanager`</a>
|
||||
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" class="external-link" target="_blank">`@contextlib.contextmanager`</a> or
|
||||
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager" class="external-link" target="_blank">`@contextlib.asynccontextmanager`</a>
|
||||
|
||||
using them to decorate a function with a single `yield`.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Let's imagine that you have a database `fake_db` that only receives JSON compati
|
||||
|
||||
For example, it doesn't receive `datetime` objects, as those are not compatible with JSON.
|
||||
|
||||
So, a `datetime` object would have to be converted to a `str` containing the data in <a href="https://en.wikipedia.org/wiki/ISO_8601" target="_blank">ISO format</a>.
|
||||
So, a `datetime` object would have to be converted to a `str` containing the data in <a href="https://en.wikipedia.org/wiki/ISO_8601" class="external-link" target="_blank">ISO format</a>.
|
||||
|
||||
The same way, this database wouldn't receive a Pydantic model (an object with attributes), only a `dict`.
|
||||
|
||||
@@ -24,7 +24,7 @@ It receives an object, like a Pydantic model, and returns a JSON compatible vers
|
||||
|
||||
In this example, it would convert the Pydantic model to a `dict`, and the `datetime` to a `str`.
|
||||
|
||||
The result of calling it is something that can be encoded with the Python standard <a href="https://docs.python.org/3/library/json.html#json.dumps" target="_blank">`json.dumps()`</a>.
|
||||
The result of calling it is something that can be encoded with the Python standard <a href="https://docs.python.org/3/library/json.html#json.dumps" class="external-link" target="_blank">`json.dumps()`</a>.
|
||||
|
||||
It doesn't return a large `str` containing the data in JSON format (as a string). It returns a Python standard data structure (e.g. a `dict`) with values and sub-values that are all compatible with JSON.
|
||||
|
||||
|
||||
@@ -32,12 +32,12 @@ Here, the `shutdown` event handler function will write a text line `"Application
|
||||
|
||||
!!! tip
|
||||
Notice that in this case we are using a standard Python `open()` function that interacts with a file.
|
||||
|
||||
|
||||
So, it involves I/O (input/output), that requires "waiting" for things to be written to disk.
|
||||
|
||||
|
||||
But `open()` doesn't use `async` and `await`.
|
||||
|
||||
|
||||
So, we declare the event handler function with standard `def` instead of `async def`.
|
||||
|
||||
!!! info
|
||||
You can read more about these event handlers in <a href="https://www.starlette.io/events/" target="_blank">Starlette's Events' docs</a>.
|
||||
You can read more about these event handlers in <a href="https://www.starlette.io/events/" class="external-link" target="_blank">Starlette's Events' docs</a>.
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
If you already know that you need to modify the generated OpenAPI schema, continue reading.
|
||||
|
||||
|
||||
There are some cases where you might need to modify the generated OpenAPI schema.
|
||||
|
||||
In this section you will see how.
|
||||
@@ -37,7 +36,7 @@ And that function `get_openapi()` receives as parameters:
|
||||
|
||||
Using the information above, you can use the same utility function to generate the OpenAPI schema and override each part that you need.
|
||||
|
||||
For example, let's add <a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" target="_blank">ReDoc's OpenAPI extension to include a custom logo</a>.
|
||||
For example, let's add <a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" class="external-link" target="_blank">ReDoc's OpenAPI extension to include a custom logo</a>.
|
||||
|
||||
### Normal **FastAPI**
|
||||
|
||||
@@ -85,7 +84,7 @@ Now you can replace the `.openapi()` method with your new function.
|
||||
|
||||
### Check it
|
||||
|
||||
Once you go to <a href="http://127.0.0.1:8000/redoc" target="_blank">http://127.0.0.1:8000/redoc</a> you will see that you are using your custom logo (in this example, **FastAPI**'s logo):
|
||||
Once you go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> you will see that you are using your custom logo (in this example, **FastAPI**'s logo):
|
||||
|
||||
<img src="/img/tutorial/extending-openapi/image01.png">
|
||||
|
||||
@@ -132,12 +131,12 @@ You can probably right-click each link and select an option similar to `Save lin
|
||||
|
||||
**Swagger UI** uses the files:
|
||||
|
||||
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui-bundle.js">`swagger-ui-bundle.js`</a>
|
||||
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui.css" target="_blank">`swagger-ui.css`</a>
|
||||
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui-bundle.js" class="external-link" target="_blank">`swagger-ui-bundle.js`</a>
|
||||
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@3/swagger-ui.css" class="external-link" target="_blank">`swagger-ui.css`</a>
|
||||
|
||||
And **ReDoc** uses the file:
|
||||
|
||||
* <a href="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js" target="_blank">`redoc.standalone.js`</a>
|
||||
* <a href="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js" class="external-link" target="_blank">`redoc.standalone.js`</a>
|
||||
|
||||
After that, your file structure could look like:
|
||||
|
||||
@@ -171,7 +170,7 @@ pip install aiofiles
|
||||
|
||||
### Test the static files
|
||||
|
||||
Start your application and go to <a href="http://127.0.0.1:8000/static/redoc.standalone.js" target="_blank">http://127.0.0.1:8000/static/redoc.standalone.js</a>.
|
||||
Start your application and go to <a href="http://127.0.0.1:8000/static/redoc.standalone.js" class="external-link" target="_blank">http://127.0.0.1:8000/static/redoc.standalone.js</a>.
|
||||
|
||||
You should see a very long JavaScript file for **ReDoc**.
|
||||
|
||||
@@ -238,6 +237,6 @@ Now, to be able to test that everything works, create a path operation:
|
||||
|
||||
### Test it
|
||||
|
||||
Now, you should be able to disconnect your WiFi, go to your docs at <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>, and reload the page.
|
||||
Now, you should be able to disconnect your WiFi, go to your docs at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, and reload the page.
|
||||
|
||||
And even without Internet, you would be able to see the docs for your API and interact with it.
|
||||
@@ -19,10 +19,10 @@ And you will still have the same features as seen up to now:
|
||||
|
||||
Here are some of the additional data types you can use:
|
||||
|
||||
* `UUID`:
|
||||
* `UUID`:
|
||||
* A standard "Universally Unique Identifier", common as an ID in many databases and systems.
|
||||
* In requests and responses will be represented as a `str`.
|
||||
* `datetime.datetime`:
|
||||
* `datetime.datetime`:
|
||||
* A Python `datetime.datetime`.
|
||||
* In requests and responses will be represented as a `str` in ISO 8601 format, like: `2008-09-15T15:53:00+05:00`.
|
||||
* `datetime.date`:
|
||||
@@ -34,7 +34,7 @@ Here are some of the additional data types you can use:
|
||||
* `datetime.timedelta`:
|
||||
* A Python `datetime.timedelta`.
|
||||
* In requests and responses will be represented as a `float` of total seconds.
|
||||
* Pydantic also allows representing it as a "ISO 8601 time diff encoding", <a href="https://pydantic-docs.helpmanual.io/#json-serialisation" target="_blank">see the docs for more info</a>.
|
||||
* Pydantic also allows representing it as a "ISO 8601 time diff encoding", <a href="https://pydantic-docs.helpmanual.io/#json-serialisation" class="external-link" target="_blank">see the docs for more info</a>.
|
||||
* `frozenset`:
|
||||
* In requests and responses, treated the same as a `set`:
|
||||
* In requests, a list will be read, eliminating duplicates and converting it to a `set`.
|
||||
@@ -48,7 +48,6 @@ Here are some of the additional data types you can use:
|
||||
* Standard Python `Decimal`.
|
||||
* In requests and responses, handled the same as a `float`.
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
Here's an example path operation with parameters using some of the above types.
|
||||
|
||||
@@ -158,7 +158,7 @@ You can declare a response to be the `Union` of two types, that means, that the
|
||||
|
||||
It will be defined in OpenAPI with `anyOf`.
|
||||
|
||||
To do that, use the standard Python type hint <a href="https://docs.python.org/3/library/typing.html#typing.Union" target="_blank">`typing.Union`</a>:
|
||||
To do that, use the standard Python type hint <a href="https://docs.python.org/3/library/typing.html#typing.Union" class="external-link" target="_blank">`typing.Union`</a>:
|
||||
|
||||
```Python hl_lines="1 14 15 18 19 20 33"
|
||||
{!./src/extra_models/tutorial003.py!}
|
||||
|
||||
@@ -32,7 +32,7 @@ That last line shows the URL where your app is being served, in your local machi
|
||||
|
||||
### Check it
|
||||
|
||||
Open your browser at <a href="http://127.0.0.1:8000" target="_blank">http://127.0.0.1:8000</a>.
|
||||
Open your browser at <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
|
||||
|
||||
You will see the JSON response as:
|
||||
|
||||
@@ -42,18 +42,17 @@ You will see the JSON response as:
|
||||
|
||||
### Interactive API docs
|
||||
|
||||
Now go to <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" target="_blank">Swagger UI</a>):
|
||||
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>):
|
||||
|
||||

|
||||
|
||||
|
||||
### Alternative API docs
|
||||
|
||||
And now, go to <a href="http://127.0.0.1:8000/redoc" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
|
||||
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" target="_blank">ReDoc</a>):
|
||||
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>):
|
||||
|
||||

|
||||
|
||||
@@ -81,11 +80,11 @@ In that case, it would mean the JSON attributes, and data types they have, etc.
|
||||
|
||||
OpenAPI defines an API schema for your API. And that schema includes definitions (or "schemas") of the data sent and received by your API using **JSON Schema**, the standard for JSON data schemas.
|
||||
|
||||
#### Check it
|
||||
#### Check the `openapi.json`
|
||||
|
||||
If you are curious about how the raw OpenAPI schema looks like, it is just an automatically generated JSON with the descriptions of all your API.
|
||||
|
||||
You can see it directly at: <a href="http://127.0.0.1:8000/openapi.json" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
|
||||
You can see it directly at: <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
|
||||
|
||||
It will show a JSON starting with something like:
|
||||
|
||||
@@ -110,7 +109,7 @@ It will show a JSON starting with something like:
|
||||
...
|
||||
```
|
||||
|
||||
#### What for?
|
||||
#### What is OpenAPI for
|
||||
|
||||
This OpenAPI schema is what powers the 2 interactive documentation systems included.
|
||||
|
||||
@@ -256,7 +255,7 @@ And the more exotic ones:
|
||||
|
||||
!!! tip
|
||||
You are free to use each operation (HTTP method) as you wish.
|
||||
|
||||
|
||||
**FastAPI** doesn't enforce any specific meaning.
|
||||
|
||||
The information here is presented as a guideline, not a requirement.
|
||||
@@ -275,7 +274,7 @@ This is our "**path operation function**":
|
||||
{!./src/first_steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
This is a Python function.
|
||||
This is a Python function.
|
||||
|
||||
It will be called by **FastAPI** whenever it receives a request to the URL "`/`" using `GET`.
|
||||
|
||||
@@ -304,11 +303,10 @@ You can also return Pydantic models (you'll see more about that later).
|
||||
|
||||
There are many other objects and models that will be automatically converted to JSON (including ORMs, etc). Try using your favorite ones, it's highly probable that they are already supported.
|
||||
|
||||
|
||||
## Recap
|
||||
|
||||
* Import `FastAPI`.
|
||||
* Create an `app` instance.
|
||||
* Write a **path operation decorator** (like `@app.get("/")`).
|
||||
* Write a **path operation function** (like `def root(): ...` above).
|
||||
* Run the development server (like `uvicorn main:app --reload`).
|
||||
* Run the development server (like `uvicorn main:app --reload`).
|
||||
@@ -5,7 +5,7 @@ You can combine normal FastAPI path operations with GraphQL on the same applicat
|
||||
|
||||
## Import and use `graphene`
|
||||
|
||||
GraphQL is implemented with Graphene, you can check <a href="https://docs.graphene-python.org/en/latest/quickstart/" target="_blank">Graphene's docs</a> for more details.
|
||||
GraphQL is implemented with Graphene, you can check <a href="https://docs.graphene-python.org/en/latest/quickstart/" class="external-link" target="_blank">Graphene's docs</a> for more details.
|
||||
|
||||
Import `graphene` and define your GraphQL data:
|
||||
|
||||
@@ -26,13 +26,12 @@ Then import and add Starlette's `GraphQLApp`:
|
||||
|
||||
## Check it
|
||||
|
||||
Run it with Uvicorn and open your browser at <a href="http://127.0.0.1:8000" target="_blank">http://127.0.0.1:8000</a>.
|
||||
Run it with Uvicorn and open your browser at <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
|
||||
|
||||
You will see GraphiQL web user interface:
|
||||
|
||||
<img src="/img/tutorial/graphql/image01.png">
|
||||
|
||||
|
||||
## More details
|
||||
|
||||
For more details, including:
|
||||
@@ -41,4 +40,4 @@ For more details, including:
|
||||
* Adding background tasks
|
||||
* Using normal or async functions
|
||||
|
||||
check the official <a href="https://www.starlette.io/graphql/" target="_blank">Starlette GraphQL docs</a>.
|
||||
check the official <a href="https://www.starlette.io/graphql/" class="external-link" target="_blank">Starlette GraphQL docs</a>.
|
||||
@@ -82,7 +82,7 @@ But in case you needed it for an advanced scenario, you can add custom headers:
|
||||
|
||||
## Install custom exception handlers
|
||||
|
||||
You can add custom exception handlers with <a href="https://www.starlette.io/exceptions/" target="_blank">the same exception utilities from Starlette</a>.
|
||||
You can add custom exception handlers with <a href="https://www.starlette.io/exceptions/" class="external-link" target="_blank">the same exception utilities from Starlette</a>.
|
||||
|
||||
Let's say you have a custom exception `UnicornException` that you (or a library you use) might `raise`.
|
||||
|
||||
@@ -156,7 +156,7 @@ path -> item_id
|
||||
!!! warning
|
||||
These are technical details that you might skip if it's not important for you now.
|
||||
|
||||
`RequestValidationError` is a sub-class of Pydantic's <a href="https://pydantic-docs.helpmanual.io/#error-handling" target="_blank">`ValidationError`</a>.
|
||||
`RequestValidationError` is a sub-class of Pydantic's <a href="https://pydantic-docs.helpmanual.io/#error-handling" class="external-link" target="_blank">`ValidationError`</a>.
|
||||
|
||||
**FastAPI** uses it so that, if you use a Pydantic model in `response_model`, and your data has an error, you will see the error in your log.
|
||||
|
||||
|
||||
@@ -28,11 +28,10 @@ The middleware function receives:
|
||||
!!! tip
|
||||
This technique is used in the tutorial about <a href="https://fastapi.tiangolo.com/tutorial/sql-databases/" target="_blank">SQL (Relational) Databases</a>.
|
||||
|
||||
|
||||
!!! tip
|
||||
Have in mind that custom proprietary headers can be added <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" target="_blank">using the 'X-' prefix</a>.
|
||||
Have in mind that custom proprietary headers can be added <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">using the 'X-' prefix</a>.
|
||||
|
||||
But if you have custom headers that you want a client in a browser to be able to see, you need to add them to your <a href="https://fastapi.tiangolo.com/tutorial/cors/" target="_blank">CORS configurations</a>, using the parameter `expose_headers` documented in <a href="https://www.starlette.io/middleware/#corsmiddleware" target="_blank">Starlette's CORS docs</a>.
|
||||
But if you have custom headers that you want a client in a browser to be able to see, you need to add them to your <a href="https://fastapi.tiangolo.com/tutorial/cors/" target="_blank">CORS configurations</a>, using the parameter `expose_headers` documented in <a href="https://www.starlette.io/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette's CORS docs</a>.
|
||||
|
||||
### Before and after the `response`
|
||||
|
||||
@@ -48,7 +47,7 @@ For example, you could add a custom header `X-Process-Time` containing the time
|
||||
|
||||
## Starlette's Middleware
|
||||
|
||||
You can also add any other <a href="https://www.starlette.io/middleware/" target="_blank">Starlette Middleware</a>.
|
||||
You can also add any other <a href="https://www.starlette.io/middleware/" class="external-link" target="_blank">Starlette Middleware</a>.
|
||||
|
||||
These are classes instead of plain functions.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
**FastAPI** can also be integrated with any <abbr title="Distributed database (Big Data), also 'Not Only SQL'">NoSQL</abbr>.
|
||||
|
||||
Here we'll see an example using **<a href="https://www.couchbase.com/" target="_blank">Couchbase</a>**, a <abbr title="Document here refers to a JSON object (a dict), with keys and values, and those values can also be other JSON objects, arrays (lists), numbers, strings, booleans, etc.">document</abbr> based NoSQL database.
|
||||
Here we'll see an example using **<a href="https://www.couchbase.com/" class="external-link" target="_blank">Couchbase</a>**, a <abbr title="Document here refers to a JSON object (a dict), with keys and values, and those values can also be other JSON objects, arrays (lists), numbers, strings, booleans, etc.">document</abbr> based NoSQL database.
|
||||
|
||||
You can adapt it to any other NoSQL database like:
|
||||
|
||||
@@ -11,7 +11,7 @@ You can adapt it to any other NoSQL database like:
|
||||
* **ElasticSearch**, etc.
|
||||
|
||||
!!! tip
|
||||
There is an official project generator with **FastAPI** and **Couchbase**, all based on **Docker**, including a frontend and more tools: <a href="https://github.com/tiangolo/full-stack-fastapi-couchbase" target="_blank">https://github.com/tiangolo/full-stack-fastapi-couchbase</a>
|
||||
There is an official project generator with **FastAPI** and **Couchbase**, all based on **Docker**, including a frontend and more tools: <a href="https://github.com/tiangolo/full-stack-fastapi-couchbase" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-couchbase</a>
|
||||
|
||||
## Import Couchbase components
|
||||
|
||||
@@ -84,9 +84,8 @@ We don't create it as a subclass of Pydantic's `BaseModel` but as a subclass of
|
||||
|
||||
!!! note
|
||||
Notice that we have a `hashed_password` and a `type` field that will be stored in the database.
|
||||
|
||||
But it is not part of the general `User` model (the one we will return in the path operation).
|
||||
|
||||
But it is not part of the general `User` model (the one we will return in the path operation).
|
||||
|
||||
## Get the user
|
||||
|
||||
@@ -104,14 +103,14 @@ By creating a function that is only dedicated to getting your user from a `usern
|
||||
```
|
||||
|
||||
### f-strings
|
||||
|
||||
If you are not familiar with the `f"userprofile::{username}"`, it is a Python "<a href="https://docs.python.org/3/glossary.html#term-f-string" target="_blank">f-string</a>".
|
||||
|
||||
If you are not familiar with the `f"userprofile::{username}"`, it is a Python "<a href="https://docs.python.org/3/glossary.html#term-f-string" class="external-link" target="_blank">f-string</a>".
|
||||
|
||||
Any variable that is put inside of `{}` in an f-string will be expanded / injected in the string.
|
||||
|
||||
### `dict` unpacking
|
||||
|
||||
If you are not familiar with the `UserInDB(**result.value)`, <a href="https://docs.python.org/3/glossary.html#term-argument" target="_blank">it is using `dict` "unpacking"</a>.
|
||||
If you are not familiar with the `UserInDB(**result.value)`, <a href="https://docs.python.org/3/glossary.html#term-argument" class="external-link" target="_blank">it is using `dict` "unpacking"</a>.
|
||||
|
||||
It will take the `dict` at `result.value`, and take each of its keys and values and pass them as key-values to `UserInDB` as keyword arguments.
|
||||
|
||||
@@ -140,7 +139,7 @@ UserInDB(username="johndoe", hashed_password="some_hash")
|
||||
|
||||
### Create the path operation function
|
||||
|
||||
As our code is calling Couchbase and we are not using the <a href="https://docs.couchbase.com/python-sdk/2.5/async-programming.html#asyncio-python-3-5" target="_blank">experimental Python <code>await</code> support</a>, we should declare our function with normal `def` instead of `async def`.
|
||||
As our code is calling Couchbase and we are not using the <a href="https://docs.couchbase.com/python-sdk/2.5/async-programming.html#asyncio-python-3-5" class="external-link" target="_blank">experimental Python <code>await</code> support</a>, we should declare our function with normal `def` instead of `async def`.
|
||||
|
||||
Also, Couchbase recommends not using a single `Bucket` object in multiple "<abbr title="A sequence of code being executed by the program, while at the same time, or at intervals, there can be others being executed too.">thread</abbr>s", so, we can get just get the bucket directly and pass it to our utility functions:
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ This part is pretty normal, most of the code is probably already familiar to you
|
||||
```
|
||||
|
||||
!!! tip
|
||||
The `callback_url` query parameter uses a Pydantic <a href="https://pydantic-docs.helpmanual.io/usage/types/#urls" target="_blank">URL</a> type.
|
||||
The `callback_url` query parameter uses a Pydantic <a href="https://pydantic-docs.helpmanual.io/usage/types/#urls" class="external-link" target="_blank">URL</a> type.
|
||||
|
||||
The only new thing is the `callbacks=messages_callback_router.routes` as an argument to the *path operation decorator*. We'll see what that is next.
|
||||
|
||||
@@ -62,7 +62,7 @@ This example doesn't implement the callback itself (that could be just a line of
|
||||
!!! tip
|
||||
The actual callback is just an HTTP request.
|
||||
|
||||
When implementing the callback yourself, you could use something like <a href="https://www.encode.io/httpx/" target="_blank">HTTPX</a> or <a href="https://requests.readthedocs.io/" target="_blank">Requests</a>.
|
||||
When implementing the callback yourself, you could use something like <a href="https://www.encode.io/httpx/" target="_blank">HTTPX</a> or <a href="https://requests.readthedocs.io/" class="external-link" target="_blank">Requests</a>.
|
||||
|
||||
## Write the callback documentation code
|
||||
|
||||
@@ -110,11 +110,11 @@ It should look just like a normal FastAPI *path operation*:
|
||||
There are 2 main differences from a normal *path operation*:
|
||||
|
||||
* It doesn't need to have any actual code, because your app will never call this code. It's only used to document the *external API*. So, the function could just have `pass`.
|
||||
* The *path* can contain an <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#key-expression" target="_blank">OpenAPI 3 expression</a> (see more below) where it can use variables with parameters and parts of the original request sent to *your API*.
|
||||
* The *path* can contain an <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a> (see more below) where it can use variables with parameters and parts of the original request sent to *your API*.
|
||||
|
||||
### The callback path expression
|
||||
|
||||
The callback *path* can have an <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#key-expression" target="_blank">OpenAPI 3 expression</a> that can contain parts of the original request sent to *your API*.
|
||||
The callback *path* can have an <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a> that can contain parts of the original request sent to *your API*.
|
||||
|
||||
In this case, it's the `str`:
|
||||
|
||||
@@ -179,7 +179,7 @@ Now use the parameter `callbacks` in *your API's path operation decorator* to pa
|
||||
|
||||
### Check the docs
|
||||
|
||||
Now you can start your app with Uvicorn and go to <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
Now you can start your app with Uvicorn and go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
You will see your docs including a "Callback" section for your *path operation* that shows how the *external API* should look like:
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ But if you don't remember what each number code is for, you can use the shortcut
|
||||
|
||||
That status code will be used in the response and will be added to the OpenAPI schema.
|
||||
|
||||
|
||||
## Tags
|
||||
|
||||
You can add tags to your path operation, pass the parameter `tags` with a `list` of `str` (commonly just one `str`):
|
||||
@@ -42,7 +41,7 @@ You can add a `summary` and `description`:
|
||||
|
||||
As descriptions tend to be long and cover multiple lines, you can declare the path operation description in the function <abbr title="a multi-line string as the first expression inside a function (not assigned to any variable) used for documentation">docstring</abbr> and **FastAPI** will read it from there.
|
||||
|
||||
You can write <a href="https://en.wikipedia.org/wiki/Markdown" target="_blank">Markdown</a> in the docstring, it will be interpreted and displayed correctly (taking into account docstring indentation).
|
||||
You can write <a href="https://en.wikipedia.org/wiki/Markdown" class="target-blank" 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!}
|
||||
@@ -65,7 +64,7 @@ You can specify the response description with the parameter `response_descriptio
|
||||
|
||||
!!! info
|
||||
OpenAPI specifies that each path operation requires a response description.
|
||||
|
||||
|
||||
So, if you don't provide one, **FastAPI** will automatically generate one of "Successful response".
|
||||
|
||||
<img src="/img/tutorial/path-operation-configuration/image03.png">
|
||||
@@ -74,7 +73,6 @@ You can specify the response description with the parameter `response_descriptio
|
||||
|
||||
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!}
|
||||
```
|
||||
@@ -89,4 +87,4 @@ Check how deprecated and non-deprecated path operations look like:
|
||||
|
||||
## Recap
|
||||
|
||||
You can configure and add metadata for your path operations easily by passing parameters to the path operation decorators.
|
||||
You can configure and add metadata for your path operations easily by passing parameters to the path operation decorators.
|
||||
@@ -6,7 +6,7 @@ You can declare path "parameters" or "variables" with the same syntax used by Py
|
||||
|
||||
The value of the path parameter `item_id` will be passed to your function as the argument `item_id`.
|
||||
|
||||
So, if you run this example and go to <a href="http://127.0.0.1:8000/items/foo" target="_blank">http://127.0.0.1:8000/items/foo</a>, you will see a response of:
|
||||
So, if you run this example and go to <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>, you will see a response of:
|
||||
|
||||
```JSON
|
||||
{"item_id":"foo"}
|
||||
@@ -27,7 +27,7 @@ In this case, `item_id` is declared to be an `int`.
|
||||
|
||||
## Data <abbr title="also known as: serialization, parsing, marshalling">conversion</abbr>
|
||||
|
||||
If you run this example and open your browser at <a href="http://127.0.0.1:8000/items/3" target="_blank">http://127.0.0.1:8000/items/3</a>, you will see a response of:
|
||||
If you run this example and open your browser at <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a>, you will see a response of:
|
||||
|
||||
```JSON
|
||||
{"item_id":3}
|
||||
@@ -40,7 +40,7 @@ If you run this example and open your browser at <a href="http://127.0.0.1:8000/
|
||||
|
||||
## Data validation
|
||||
|
||||
But if you go to the browser at <a href="http://127.0.0.1:8000/items/foo" target="_blank">http://127.0.0.1:8000/items/foo</a>, you will see a nice HTTP error of:
|
||||
But if you go to the browser at <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>, you will see a nice HTTP error of:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -59,7 +59,7 @@ But if you go to the browser at <a href="http://127.0.0.1:8000/items/foo" target
|
||||
|
||||
because the path parameter `item_id` had a value of `"foo"`, which is not an `int`.
|
||||
|
||||
The same error would appear if you provided a `float` instead of an int, as in: <a href="http://127.0.0.1:8000/items/4.2" target="_blank">http://127.0.0.1:8000/items/4.2</a>
|
||||
The same error would appear if you provided a `float` instead of an int, as in: <a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a>
|
||||
|
||||
!!! check
|
||||
So, with the same Python type declaration, **FastAPI** gives you data validation.
|
||||
@@ -70,7 +70,7 @@ The same error would appear if you provided a `float` instead of an int, as in:
|
||||
|
||||
## Documentation
|
||||
|
||||
And when you open your browser at <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>, you will see an automatic, interactive, API documentation like:
|
||||
And when you open your browser at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, you will see an automatic, interactive, API documentation like:
|
||||
|
||||
<img src="/img/tutorial/path-params/image01.png">
|
||||
|
||||
@@ -81,7 +81,7 @@ And when you open your browser at <a href="http://127.0.0.1:8000/docs" target="_
|
||||
|
||||
## Standards-based benefits, alternative documentation
|
||||
|
||||
And because the generated schema is from the <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md" target="_blank">OpenAPI</a> standard, there are many compatible tools.
|
||||
And because the generated schema is from the <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md" class="external-link" target="_blank">OpenAPI</a> standard, there are many compatible tools.
|
||||
|
||||
Because of this, **FastAPI** itself provides an alternative API documentation (using ReDoc):
|
||||
|
||||
@@ -91,7 +91,7 @@ The same way, there are many compatible tools. Including code generation tools f
|
||||
|
||||
## Pydantic
|
||||
|
||||
All the data validation is performed under the hood by <a href="https://pydantic-docs.helpmanual.io/" target="_blank">Pydantic</a>, so you get all the benefits from it. And you know you are in good hands.
|
||||
All the data validation is performed under the hood by <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a>, so you get all the benefits from it. And you know you are in good hands.
|
||||
|
||||
You can use the same type declarations with `str`, `float`, `bool` and many other complex data types.
|
||||
|
||||
@@ -130,7 +130,7 @@ And create class attributes with fixed values, those fixed values will be the av
|
||||
```
|
||||
|
||||
!!! info
|
||||
<a href="https://docs.python.org/3/library/enum.html" target="_blank">Enumerations (or enums) are available in Python</a> since version 3.4.
|
||||
<a href="https://docs.python.org/3/library/enum.html" class="external-link" target="_blank">Enumerations (or enums) are available in Python</a> since version 3.4.
|
||||
|
||||
!!! tip
|
||||
If you are wondering, "AlexNet", "ResNet", and "LeNet" are just names of Machine Learning <abbr title="Technically, Deep Learning model architectures">models</abbr>.
|
||||
|
||||
@@ -118,7 +118,7 @@ So, when you need to declare a value as required while using `Query`, you can us
|
||||
```
|
||||
|
||||
!!! info
|
||||
If you hadn't seen that `...` before: it is a a special single value, it is <a href="https://docs.python.org/3/library/constants.html#Ellipsis" target="_blank">part of Python and is called "Ellipsis"</a>.
|
||||
If you hadn't seen that `...` before: it is a a special single value, it is <a href="https://docs.python.org/3/library/constants.html#Ellipsis" class="external-link" target="_blank">part of Python and is called "Ellipsis"</a>.
|
||||
|
||||
This will let **FastAPI** know that this parameter is required.
|
||||
|
||||
@@ -276,4 +276,4 @@ Validations specific for strings:
|
||||
|
||||
In these examples you saw how to declare validations for `str` values.
|
||||
|
||||
See the next chapters to see how to declare validations for other types, like numbers.
|
||||
See the next chapters to see how to declare validations for other types, like numbers.
|
||||
@@ -1,7 +1,7 @@
|
||||
You can define files to be uploaded by the client using `File`.
|
||||
|
||||
!!! info
|
||||
To receive uploaded files, first install [`python-multipart`](https://andrew-d.github.io/python-multipart/).
|
||||
To receive uploaded files, first install <a href="https://andrew-d.github.io/python-multipart/" class="external-link" target="_blank">`python-multipart`</a>.
|
||||
|
||||
E.g. `pip install python-multipart`.
|
||||
|
||||
@@ -39,7 +39,6 @@ Have in mind that this means that the whole contents will be stored in memory. T
|
||||
|
||||
But there are several cases in where you might benefit from using `UploadFile`.
|
||||
|
||||
|
||||
## `File` parameters with `UploadFile`
|
||||
|
||||
Define a `File` parameter with a type of `UploadFile`:
|
||||
@@ -54,9 +53,8 @@ Using `UploadFile` has several advantages over `bytes`:
|
||||
* A file stored in memory up to a maximum size limit, and after passing this limit it will be stored in disk.
|
||||
* This means that it will work well for large files like images, videos, large binaries, etc. without consuming all the memory.
|
||||
* You can get metadata from the uploaded file.
|
||||
* It has a <a href="https://docs.python.org/3/glossary.html#term-file-like-object" target="_blank">file-like</a> `async` interface.
|
||||
* It exposes an actual Python <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" target="_blank">`SpooledTemporaryFile`</a> object that you can pass directly to other libraries that expect a file-like object.
|
||||
|
||||
* It has a <a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> `async` interface.
|
||||
* It exposes an actual Python <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a> object that you can pass directly to other libraries that expect a file-like object.
|
||||
|
||||
### `UploadFile`
|
||||
|
||||
@@ -66,7 +64,6 @@ Using `UploadFile` has several advantages over `bytes`:
|
||||
* `content_type`: A `str` with the content type (MIME type / media type) (e.g. `image/jpeg`).
|
||||
* `file`: A <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" target="_blank">`SpooledTemporaryFile`</a> (a <a href="https://docs.python.org/3/glossary.html#term-file-like-object" target="_blank">file-like</a> object). This is the actual Python file that you can pass directly to other functions or libraries that expect a "file-like" object.
|
||||
|
||||
|
||||
`UploadFile` has the following `async` methods. They all call the corresponding file methods underneath (using the internal `SpooledTemporaryFile`).
|
||||
|
||||
* `write(data)`: Writes `data` (`str` or `bytes`) to the file.
|
||||
@@ -93,11 +90,10 @@ contents = myfile.file.read()
|
||||
!!! note "`async` Technical Details"
|
||||
When you use the `async` methods, **FastAPI** runs the file methods in a threadpool and awaits for them.
|
||||
|
||||
|
||||
!!! note "Starlette Technical Details"
|
||||
**FastAPI**'s `UploadFile` inherits directly from **Starlette**'s `UploadFile`, but adds some necessary parts to make it compatible with **Pydantic** and the other parts of FastAPI.
|
||||
|
||||
## "Form Data"?
|
||||
## What is "Form Data"
|
||||
|
||||
The way HTML forms (`<form></form>`) sends the data to the server normally uses a "special" encoding for that data, it's different from JSON.
|
||||
|
||||
@@ -108,8 +104,7 @@ The way HTML forms (`<form></form>`) sends the data to the server normally uses
|
||||
|
||||
But when the form includes files, it is encoded as `multipart/form-data`. If you use `File`, **FastAPI** will know it has to get the files from the correct part of the body.
|
||||
|
||||
If you want to read more about these encodings and form fields, head to the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> web docs for <code>POST</code></a>.
|
||||
|
||||
If you want to read more about these encodings and form fields, head to the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> web docs for <code>POST</code></a>.
|
||||
|
||||
!!! warning
|
||||
You can declare multiple `File` and `Form` parameters in a path operation, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `multipart/form-data` instead of `application/json`.
|
||||
@@ -131,7 +126,7 @@ To use that, declare a `List` of `bytes` or `UploadFile`:
|
||||
You will receive, as declared, a `list` of `bytes` or `UploadFile`s.
|
||||
|
||||
!!! note
|
||||
Notice that, as of 2019-04-14, Swagger UI doesn't support multiple file uploads in the same form field. For more information, check <a href="https://github.com/swagger-api/swagger-ui/issues/4276" target="_blank">#4276</a> and <a href="https://github.com/swagger-api/swagger-ui/issues/3641" target="_blank">#3641</a>.
|
||||
Notice that, as of 2019-04-14, Swagger UI doesn't support multiple file uploads in the same form field. For more information, check <a href="https://github.com/swagger-api/swagger-ui/issues/4276" target="_blank">#4276</a> and <a href="https://github.com/swagger-api/swagger-ui/issues/3641" class="external-link" target="_blank">#3641</a>.
|
||||
|
||||
Nevertheless, **FastAPI** is already compatible with it, using the standard OpenAPI.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
You can define files and form fields at the same time using `File` and `Form`.
|
||||
|
||||
!!! info
|
||||
To receive uploaded files and/or form data, first install [`python-multipart`](https://andrew-d.github.io/python-multipart/).
|
||||
To receive uploaded files and/or form data, first install <a href="https://andrew-d.github.io/python-multipart/" class="external-link" target="_blank">`python-multipart`</a>.
|
||||
|
||||
E.g. `pip install python-multipart`.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
When you need to receive form fields instead of JSON, you can use `Form`.
|
||||
|
||||
!!! info
|
||||
To use forms, first install [`python-multipart`](https://andrew-d.github.io/python-multipart/).
|
||||
To use forms, first install <a href="https://andrew-d.github.io/python-multipart/" class="external-link" target="_blank">`python-multipart`</a>.
|
||||
|
||||
E.g. `pip install python-multipart`.
|
||||
|
||||
@@ -33,7 +33,7 @@ With `Form` you can declare the same metadata and validation as with `Body` (and
|
||||
!!! info
|
||||
To declare form bodies, you need to use `Form` explicitly, because without it the parameters would be interpreted as query parameters or body (JSON) parameters.
|
||||
|
||||
## "Form Fields"?
|
||||
## About "Form Fields"
|
||||
|
||||
The way HTML forms (`<form></form>`) sends the data to the server normally uses a "special" encoding for that data, it's different from JSON.
|
||||
|
||||
@@ -44,8 +44,7 @@ The way HTML forms (`<form></form>`) sends the data to the server normally uses
|
||||
|
||||
But when the form includes files, it is encoded as `multipart/form-data`. You'll read about handling files in the next chapter.
|
||||
|
||||
If you want to read more about these encodings and form fields, head to the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> web docs for <code>POST</code></a>.
|
||||
|
||||
If you want to read more about these encodings and form fields, head to the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> web docs for <code>POST</code></a>.
|
||||
|
||||
!!! warning
|
||||
You can declare multiple `Form` parameters in a path operation, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `application/x-www-form-urlencoded` instead of `application/json`.
|
||||
|
||||
@@ -29,7 +29,7 @@ Then set Cookies in it, and then return it:
|
||||
```
|
||||
|
||||
!!! tip
|
||||
Have in mind that if you return a response directly instead of using the `Response` parameter, FastAPI will return it directly.
|
||||
Have in mind that if you return a response directly instead of using the `Response` parameter, FastAPI will return it directly.
|
||||
|
||||
So, you will have to make sure your data is of the correct type. E.g. it is compatible with JSON, if you are returning a `JSONResponse`.
|
||||
|
||||
@@ -37,4 +37,4 @@ Then set Cookies in it, and then return it:
|
||||
|
||||
### More info
|
||||
|
||||
To see all the available parameters and options, check the <a href="https://www.starlette.io/responses/#set-cookie" target="_blank">documentation in Starlette</a>.
|
||||
To see all the available parameters and options, check the <a href="https://www.starlette.io/responses/#set-cookie" class="external-link" target="_blank">documentation in Starlette</a>.
|
||||
@@ -10,7 +10,7 @@ It might be useful, for example, to return custom headers or cookies.
|
||||
|
||||
## Starlette `Response`
|
||||
|
||||
In fact, you can return any <a href="https://www.starlette.io/responses/" target="_blank">Starlette `Response`</a> or any sub-class of it.
|
||||
In fact, you can return any <a href="https://www.starlette.io/responses/" class="external-link" target="_blank">Starlette `Response`</a> or any sub-class of it.
|
||||
|
||||
!!! tip
|
||||
`JSONResponse` itself is a sub-class of `Response`.
|
||||
@@ -42,9 +42,9 @@ The example above shows all the parts you need, but it's not very useful yet, as
|
||||
|
||||
Now, let's see how you could use that to return a custom response.
|
||||
|
||||
Let's say you want to return a response that is not available in the default <a href="https://www.starlette.io/responses/" target="_blank">Starlette `Response`s</a>.
|
||||
Let's say you want to return a response that is not available in the default <a href="https://www.starlette.io/responses/" class="external-link" target="_blank">Starlette `Response`s</a>.
|
||||
|
||||
Let's say that you want to return <a href="https://en.wikipedia.org/wiki/XML" target="_blank">XML</a>.
|
||||
Let's say that you want to return <a href="https://en.wikipedia.org/wiki/XML" class="external-link" target="_blank">XML</a>.
|
||||
|
||||
You could put your XML content in a string, put it in a Starlette Response, and return it:
|
||||
|
||||
|
||||
@@ -28,6 +28,6 @@ Create a response as described in <a href="https://fastapi.tiangolo.com/tutorial
|
||||
|
||||
## Custom Headers
|
||||
|
||||
Have in mind that custom proprietary headers can be added <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" target="_blank">using the 'X-' prefix</a>.
|
||||
Have in mind that custom proprietary headers can be added <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">using the 'X-' prefix</a>.
|
||||
|
||||
But if you have custom headers that you want a client in a browser to be able to see, you need to add them to your <a href="https://fastapi.tiangolo.com/tutorial/cors/" target="_blank">CORS configurations</a>, using the parameter `expose_headers` documented in <a href="https://www.starlette.io/middleware/#corsmiddleware" target="_blank">Starlette's CORS docs</a>.
|
||||
But if you have custom headers that you want a client in a browser to be able to see, you need to add them to your <a href="https://fastapi.tiangolo.com/tutorial/cors/" target="_blank">CORS configurations</a>, using the parameter `expose_headers` documented in <a href="https://www.starlette.io/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette's CORS docs</a>.
|
||||
@@ -120,7 +120,7 @@ So, if you send a request to that *path operation* for the item with ID `foo`, t
|
||||
```
|
||||
|
||||
!!! info
|
||||
FastAPI uses Pydantic model's `.dict()` with <a href="https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeldict" target="_blank">its `exclude_unset` parameter</a> to achieve this.
|
||||
FastAPI uses Pydantic model's `.dict()` with <a href="https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeldict" class="external-link" target="_blank">its `exclude_unset` parameter</a> to achieve this.
|
||||
|
||||
#### Data with values for fields with defaults
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ In short:
|
||||
* `500` and above are for server errors. You almost never use them directly. When something goes wrong at some part in your application code, or server, it will automatically return one of these status codes.
|
||||
|
||||
!!! tip
|
||||
To know more about each status code and which code is for what, check the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> documentation about HTTP status codes</a>.
|
||||
To know more about each status code and which code is for what, check the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> documentation about HTTP status codes</a>.
|
||||
|
||||
## Shortcut to remember the names
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ Copy the example in a file `main.py`:
|
||||
## Run it
|
||||
|
||||
!!! info
|
||||
First install [`python-multipart`](https://andrew-d.github.io/python-multipart/).
|
||||
First install <a href="https://andrew-d.github.io/python-multipart/" class="external-link" target="_blank">`python-multipart`</a>.
|
||||
|
||||
E.g. `pip install python-multipart`.
|
||||
|
||||
@@ -39,7 +39,7 @@ uvicorn main:app --reload
|
||||
|
||||
## Check it
|
||||
|
||||
Go to the interactive docs at: <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
Go to the interactive docs at: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
You will see something like this:
|
||||
|
||||
@@ -50,7 +50,6 @@ You will see something like this:
|
||||
|
||||
And your path operation has a little lock in the top-right corner that you can click.
|
||||
|
||||
|
||||
And if you click it, you have a little authorization form to type a `username` and `password` (and other optional fields):
|
||||
|
||||
<img src="/img/tutorial/security/image02.png">
|
||||
@@ -66,7 +65,6 @@ It can be used by third party applications and systems.
|
||||
|
||||
And it can also be used by yourself, to debug, check and test the same application.
|
||||
|
||||
|
||||
## The `password` flow
|
||||
|
||||
Now let's go back a bit and understand what is all that.
|
||||
@@ -99,10 +97,9 @@ So, let's review it from that simplified point of view:
|
||||
|
||||
In this example we are going to use **OAuth2**, with the **Password** flow, using a **Bearer** token.
|
||||
|
||||
|
||||
!!! info
|
||||
A "bearer" token is not the only option.
|
||||
|
||||
|
||||
But it's the best one for our use case.
|
||||
|
||||
And it might be the best for most use cases, unless you are an OAuth2 expert and know exactly why there's another option that suits better your needs.
|
||||
|
||||
@@ -18,7 +18,6 @@ Then, when you type that username and password, the browser sends them in the he
|
||||
* It returns an object of type `HTTPBasicCredentials`:
|
||||
* It contains the `username` and `password` sent.
|
||||
|
||||
|
||||
```Python hl_lines="2 6 10"
|
||||
{!./src/security/tutorial006.py!}
|
||||
```
|
||||
@@ -33,7 +32,7 @@ Here's a more complete example.
|
||||
|
||||
Use a dependency to check if the username and password are correct.
|
||||
|
||||
For this, use the Python standard module <a href="https://docs.python.org/3/library/secrets.html" target="_blank">`secrets`</a> to check the 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 13 14 15"
|
||||
{!./src/security/tutorial007.py!}
|
||||
|
||||
@@ -22,7 +22,7 @@ That way, you can create a token with an expiration of, let's say, 1 week, and t
|
||||
|
||||
And after a week, the token will be expired. And if the user (or a third party) tried to modify the token to change the expiration, you would be able to discover it, because the signatures would not match.
|
||||
|
||||
If you want to play with JWT tokens and see how they work, check <a href="https://jwt.io/" target="_blank">https://jwt.io</a>.
|
||||
If you want to play with JWT tokens and see how they work, check <a href="https://jwt.io/" class="external-link" target="_blank">https://jwt.io</a>.
|
||||
|
||||
## Install `PyJWT`
|
||||
|
||||
@@ -40,7 +40,7 @@ Whenever you pass exactly the same content (exactly the same password) you get e
|
||||
|
||||
But you cannot convert from the gibberish back to the password.
|
||||
|
||||
### What for?
|
||||
### Why use password hashing
|
||||
|
||||
If your database is stolen, the thief won't have your users' plaintext passwords, only the hashes.
|
||||
|
||||
@@ -141,7 +141,6 @@ Create a real JWT access token and return it.
|
||||
{!./src/security/tutorial004.py!}
|
||||
```
|
||||
|
||||
|
||||
### Technical details about the JWT "subject" `sub`
|
||||
|
||||
The JWT specification says that there's a key `sub`, with the subject of the token.
|
||||
@@ -166,7 +165,7 @@ The important thing to have in mind is that the `sub` key should have a unique i
|
||||
|
||||
## Check it
|
||||
|
||||
Run the server and go to the docs: <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
Run the server and go to the docs: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
You'll see the user interface like:
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ They are normally used to declare specific security permissions, for example:
|
||||
|
||||
For OAuth2 they are just strings.
|
||||
|
||||
|
||||
## Code to get the `username` and `password`
|
||||
|
||||
Now let's use the utilities provided by **FastAPI** to handle this.
|
||||
@@ -69,11 +68,11 @@ First, import `OAuth2PasswordRequestForm`, and use it as a dependency with `Depe
|
||||
|
||||
!!! info
|
||||
The `OAuth2PasswordRequestForm` is not a special class for **FastAPI** as is `OAuth2PasswordBearer`.
|
||||
|
||||
|
||||
`OAuth2PasswordBearer` makes **FastAPI** know that it is a security scheme. So it is added that way to OpenAPI.
|
||||
|
||||
|
||||
But `OAuth2PasswordRequestForm` is just a class dependency that you could have written yourself, or you could have declared `Form` parameters directly.
|
||||
|
||||
|
||||
But as it's a common use case, it is provided by **FastAPI** directly, just to make it easier.
|
||||
|
||||
### Use the form data
|
||||
@@ -111,7 +110,7 @@ Whenever you pass exactly the same content (exactly the same password) you get e
|
||||
|
||||
But you cannot convert from the gibberish back to the password.
|
||||
|
||||
##### What for?
|
||||
##### Why use password hashing
|
||||
|
||||
If your database is stolen, the thief won't have your users' plaintext passwords, only the hashes.
|
||||
|
||||
@@ -124,7 +123,7 @@ So, the thief won't be able to try to use that password in another system (as ma
|
||||
#### About `**user_dict`
|
||||
|
||||
`UserInDB(**user_dict)` means:
|
||||
|
||||
|
||||
*Pass the keys and values of the `user_dict` directly as key-value arguments, equivalent to:*
|
||||
|
||||
```Python
|
||||
@@ -201,7 +200,7 @@ So, in our endpoint, we will only get a user if the user exists, was correctly a
|
||||
|
||||
## See it in action
|
||||
|
||||
Open the interactive docs: <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
Open the interactive docs: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
### Authenticate
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
If you are starting a project from scratch, you are probably better off with <a href="https://fastapi.tiangolo.com/tutorial/sql-databases/" target="_blank">SQLAlchemy ORM</a>, or any other async ORM.
|
||||
|
||||
If you already have a code base that uses <a href="http://docs.peewee-orm.com/en/latest/" target="_blank">Peewee ORM</a>, you can check here how to use it with **FastAPI**.
|
||||
If you already have a code base that uses <a href="http://docs.peewee-orm.com/en/latest/" class="external-link" target="_blank">Peewee ORM</a>, you can check here how to use it with **FastAPI**.
|
||||
|
||||
!!! warning "Python 3.7+ required"
|
||||
You will need Python 3.7 or above to safely use Peewee with FastAPI.
|
||||
@@ -23,7 +23,7 @@ But if you need to change some of the defaults, support more than one predefined
|
||||
Nevertheless, it's possible to do it, and here you'll see exactly what code you have to add to be able to use Peewee with FastAPI.
|
||||
|
||||
!!! note "Technical Details"
|
||||
You can read more about Peewee's stand about async in Python <a href="http://docs.peewee-orm.com/en/latest/peewee/database.html#async-with-gevent" target="_blank">in the docs</a>, <a href="https://github.com/coleifer/peewee/issues/263#issuecomment-517347032" target="_blank">an issue</a>, <a href="https://github.com/coleifer/peewee/pull/2072#issuecomment-563215132" target="_blank">a PR</a>.
|
||||
You can read more about Peewee's stand about async in Python <a href="http://docs.peewee-orm.com/en/latest/peewee/database.html#async-with-gevent" target="_blank">in the docs</a>, <a href="https://github.com/coleifer/peewee/issues/263#issuecomment-517347032" target="_blank">an issue</a>, <a href="https://github.com/coleifer/peewee/pull/2072#issuecomment-563215132" class="external-link" target="_blank">a PR</a>.
|
||||
|
||||
## The same app
|
||||
|
||||
@@ -88,7 +88,7 @@ connect_args={"check_same_thread": False}
|
||||
|
||||
### Make Peewee async-compatible `PeeweeConnectionState`
|
||||
|
||||
The main issue with Peewee and FastAPI is that Peewee relies heavily on <a href="https://docs.python.org/3/library/threading.html#thread-local-data" target="_blank">Python's `threading.local`</a>, and it doesn't have a direct way to override it or let you handle connections/sessions directly (as is done in the SQLAlchemy tutorial).
|
||||
The main issue with Peewee and FastAPI is that Peewee relies heavily on <a href="https://docs.python.org/3/library/threading.html#thread-local-data" class="external-link" target="_blank">Python's `threading.local`</a>, and it doesn't have a direct way to override it or let you handle connections/sessions directly (as is done in the SQLAlchemy tutorial).
|
||||
|
||||
And `threading.local` is not compatible with the new async features of modern Python.
|
||||
|
||||
@@ -103,7 +103,7 @@ And `threading.local` is not compatible with the new async features of modern Py
|
||||
|
||||
But Python 3.7 and above provide a more advanced alternative to `threading.local`, that can also be used in the places where `threading.local` would be used, but is compatible with the new async features.
|
||||
|
||||
We are going to use that. It's called <a href="https://docs.python.org/3/library/contextvars.html" target="_blank">`contextvars`</a>.
|
||||
We are going to use that. It's called <a href="https://docs.python.org/3/library/contextvars.html" class="external-link" target="_blank">`contextvars`</a>.
|
||||
|
||||
We are going to override the internal parts of Peewee that use `threading.local` and replace them with `contextvars`, with the corresponding updates.
|
||||
|
||||
@@ -206,7 +206,7 @@ It provides a special custom object of class `ModelSelect`.
|
||||
|
||||
It's possible to create a `list` of its items with `list(some_user.items)`.
|
||||
|
||||
But the object itself is not a `list`. And it's also not an actual Python <a href="https://docs.python.org/3/glossary.html#term-generator" target="_blank">generator</a>. Because of this, Pydantic doesn't know by default how to convert it to a `list` of Pydantic *models* / schemas.
|
||||
But the object itself is not a `list`. And it's also not an actual Python <a href="https://docs.python.org/3/glossary.html#term-generator" class="external-link" target="_blank">generator</a>. Because of this, Pydantic doesn't know by default how to convert it to a `list` of Pydantic *models* / schemas.
|
||||
|
||||
But recent versions of Pydantic allow providing a custom class that inherits from `pydantic.utils.GetterDict`, to provide the functionality used when using the `orm_mode = True` to retrieve the values for ORM model attributes.
|
||||
|
||||
@@ -307,7 +307,7 @@ For the **next request**, as we will reset that context variable again in the mi
|
||||
#### Peewee Proxy
|
||||
|
||||
|
||||
If you are using a [Peewee Proxy](http://docs.peewee-orm.com/en/latest/peewee/database.html#dynamically-defining-a-database){.external-link target=_blank}, the actual database is at `db.obj`.
|
||||
If you are using a <a href="http://docs.peewee-orm.com/en/latest/peewee/database.html#dynamically-defining-a-database" class="external-link" target="_blank">Peewee Proxy</a>, the actual database is at `db.obj`.
|
||||
|
||||
So, you would reset it with:
|
||||
|
||||
@@ -381,9 +381,9 @@ Then run your app with Uvicorn:
|
||||
uvicorn sql_app.main:app --reload
|
||||
```
|
||||
|
||||
Open your browser at <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a> and create a couple of users.
|
||||
Open your browser at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> and create a couple of users.
|
||||
|
||||
Then open 10 tabs at <a href="http://127.0.0.1:8000/docs#/default/read_slow_users_slowusers__get" target="_blank">http://127.0.0.1:8000/docs#/default/read_slow_users_slowusers__get</a> at the same time.
|
||||
Then open 10 tabs at <a href="http://127.0.0.1:8000/docs#/default/read_slow_users_slowusers__get" class="external-link" target="_blank">http://127.0.0.1:8000/docs#/default/read_slow_users_slowusers__get</a> at the same time.
|
||||
|
||||
Go to the *path operation* "Get `/slowusers/`" in all of the tabs. Use the "Try it out" button and execute the request in each tab, one right after the other.
|
||||
|
||||
@@ -475,7 +475,7 @@ Repeat the same process with the 10 tabs. This time all of them will wait and yo
|
||||
|
||||
### The problem
|
||||
|
||||
Peewee uses [`threading.local`](https://docs.python.org/3/library/threading.html#thread-local-data){.external-link target=_blank} by default to store it's database "state" data (connection, transactions, etc).
|
||||
Peewee uses <a href="https://docs.python.org/3/library/threading.html#thread-local-data" class="external-link" target="_blank">`threading.local`</a> by default to store it's database "state" data (connection, transactions, etc).
|
||||
|
||||
`threading.local` creates a value exclusive to the current thread, but an async framework would run all the "tasks" (e.g. requests) in the same thread, and possibly not in order.
|
||||
|
||||
@@ -485,7 +485,7 @@ This means that, with Peewee's current implementation, multiple tasks could be u
|
||||
|
||||
### Context variables
|
||||
|
||||
Python 3.7 has [`contextvars`](https://docs.python.org/3/library/contextvars.html){.external-link target=_blank} that can create a local variable very similar to `threading.local`, but also supporting these async features.
|
||||
Python 3.7 has <a href="https://docs.python.org/3/library/contextvars.html" class="external-link" target="_blank">`contextvars`</a> that can create a local variable very similar to `threading.local`, but also supporting these async features.
|
||||
|
||||
There are several things to have in mind.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
But you can use any relational database that you want.
|
||||
|
||||
Here we'll see an example using <a href="https://www.sqlalchemy.org/" target="_blank">SQLAlchemy</a>.
|
||||
Here we'll see an example using <a href="https://www.sqlalchemy.org/" class="external-link" target="_blank">SQLAlchemy</a>.
|
||||
|
||||
You can easily adapt it to any database supported by SQLAlchemy, like:
|
||||
|
||||
@@ -17,8 +17,7 @@ In this example, we'll use **SQLite**, because it uses a single file and Python
|
||||
Later, for your production application, you might want to use a database server like **PostgreSQL**.
|
||||
|
||||
!!! tip
|
||||
There is an official project generator with **FastAPI** and **PostgreSQL**, all based on **Docker**, including a frontend and more tools: <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" target="_blank">https://github.com/tiangolo/full-stack-fastapi-postgresql</a>
|
||||
|
||||
There is an official project generator with **FastAPI** and **PostgreSQL**, all based on **Docker**, including a frontend and more tools: <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-postgresql</a>
|
||||
|
||||
!!! note
|
||||
Notice that most of the code is the standard `SQLAlchemy` code you would use with any framework.
|
||||
@@ -288,7 +287,7 @@ Not only the IDs of those items, but all the data that we defined in the Pydanti
|
||||
|
||||
Now, in the Pydantic *models* for reading, `Item` and `User`, add an internal `Config` class.
|
||||
|
||||
This <a href="https://pydantic-docs.helpmanual.io/#config" target="_blank">`Config`</a> class is used to provide configurations to Pydantic.
|
||||
This <a href="https://pydantic-docs.helpmanual.io/#config" class="external-link" target="_blank">`Config`</a> class is used to provide configurations to Pydantic.
|
||||
|
||||
In the `Config` class, set the attribute `orm_mode = True`.
|
||||
|
||||
@@ -324,7 +323,7 @@ And with this, the Pydantic *model* is compatible with ORMs, and you can just de
|
||||
You will be able to return a database model and it will read the data from it.
|
||||
|
||||
#### Technical Details about ORM mode
|
||||
|
||||
|
||||
SQLAlchemy and many others are by default "lazy loading".
|
||||
|
||||
That means, for example, that they don't fetch the data for relationships from the database unless you try to access the attribute that would contain that data.
|
||||
@@ -430,7 +429,7 @@ In a very simplistic way create the database tables:
|
||||
|
||||
#### Alembic Note
|
||||
|
||||
Normally you would probably initialize your database (create tables, etc) with <a href="https://alembic.sqlalchemy.org/en/latest/" target="_blank">Alembic</a>.
|
||||
Normally you would probably initialize your database (create tables, etc) with <a href="https://alembic.sqlalchemy.org/en/latest/" class="external-link" target="_blank">Alembic</a>.
|
||||
|
||||
And you would also use Alembic for "migrations" (that's its main job).
|
||||
|
||||
@@ -445,7 +444,7 @@ A "migration" is the set of steps needed whenever you change the structure of yo
|
||||
pip install async-exit-stack async-generator
|
||||
```
|
||||
|
||||
This installs <a href="https://github.com/sorcio/async_exit_stack" target="_blank">async-exit-stack</a> and <a href="https://github.com/python-trio/async_generator" target="_blank">async-generator</a>.
|
||||
This installs <a href="https://github.com/sorcio/async_exit_stack" target="_blank">async-exit-stack</a> and <a href="https://github.com/python-trio/async_generator" class="external-link" target="_blank">async-generator</a>.
|
||||
|
||||
You can also use the alternative method with a "middleware" explained at the end.
|
||||
|
||||
@@ -539,13 +538,13 @@ def read_user(user_id: int, db: Session = Depends(get_db)):
|
||||
|
||||
## Migrations
|
||||
|
||||
Because we are using SQLAlchemy directly and we don't require any kind of plug-in for it to work with **FastAPI**, we could integrate database <abbr title="Automatically updating the database to have any new column we define in our models.">migrations</abbr> with <a href="https://alembic.sqlalchemy.org" target="_blank">Alembic</a> directly.
|
||||
Because we are using SQLAlchemy directly and we don't require any kind of plug-in for it to work with **FastAPI**, we could integrate database <abbr title="Automatically updating the database to have any new column we define in our models.">migrations</abbr> with <a href="https://alembic.sqlalchemy.org" class="external-link" target="_blank">Alembic</a> directly.
|
||||
|
||||
And as the code related to SQLAlchemy and the SQLAlchemy models lives in separate independent files, you would even be able to perform the migrations with Alembic without having to install FastAPI, Pydantic, or anything else.
|
||||
|
||||
The same way, you would be able to use the same SQLAlchemy models and utilities in other parts of your code that are not related to **FastAPI**.
|
||||
|
||||
For example, in a background task worker with <a href="http://www.celeryproject.org/" target="_blank">Celery</a>, <a href="https://python-rq.org/" target="_blank">RQ</a>, or <a href="https://arq-docs.helpmanual.io/" target="_blank">ARQ</a>.
|
||||
For example, in a background task worker with <a href="http://www.celeryproject.org/" class="external-link" target="_blank">Celery</a>, <a href="https://python-rq.org/" class="external-link" target="_blank">RQ</a>, or <a href="https://arq-docs.helpmanual.io/" class="external-link" target="_blank">ARQ</a>.
|
||||
|
||||
## Review all the files
|
||||
|
||||
@@ -599,7 +598,7 @@ Then you can run it with Uvicorn:
|
||||
uvicorn sql_app.main:app --reload
|
||||
```
|
||||
|
||||
And then, you can open your browser at <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
And then, you can open your browser at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
And you will be able to interact with your **FastAPI** application, reading data from a real database:
|
||||
|
||||
@@ -607,13 +606,13 @@ And you will be able to interact with your **FastAPI** application, reading data
|
||||
|
||||
## Interact with the database directly
|
||||
|
||||
If you want to explore the SQLite database (file) directly, independently of FastAPI, to debug its contents, add tables, columns, records, modify data, etc. you can use <a href="https://sqlitebrowser.org/" target="_blank">DB Browser for SQLite</a>.
|
||||
If you want to explore the SQLite database (file) directly, independently of FastAPI, to debug its contents, add tables, columns, records, modify data, etc. you can use <a href="https://sqlitebrowser.org/" class="external-link" target="_blank">DB Browser for SQLite</a>.
|
||||
|
||||
It will look like this:
|
||||
|
||||
<img src="/img/tutorial/sql-databases/image02.png">
|
||||
|
||||
You can also use an online SQLite browser like <a href="https://inloop.github.io/sqlite-viewer/" target="_blank">SQLite Viewer</a> or <a href="https://extendsclass.com/sqlite-browser.html" target="_blank">ExtendsClass</a>.
|
||||
You can also use an online SQLite browser like <a href="https://inloop.github.io/sqlite-viewer/" target="_blank">SQLite Viewer</a> or <a href="https://extendsclass.com/sqlite-browser.html" class="external-link" target="_blank">ExtendsClass</a>.
|
||||
|
||||
## Alternative DB session with middleware
|
||||
|
||||
@@ -638,7 +637,7 @@ The middleware we'll add (just a function) will create a new SQLAlchemy `Session
|
||||
|
||||
### About `request.state`
|
||||
|
||||
<a href="https://www.starlette.io/requests/#other-state" target="_blank">`request.state` is a property of each Starlette `Request` object</a>. It is there to store arbitrary objects attached to the request itself, like the database session in this case.
|
||||
<a href="https://www.starlette.io/requests/#other-state" class="external-link" target="_blank">`request.state` is a property of each Starlette `Request` object</a>. It is there to store arbitrary objects attached to the request itself, like the database session in this case.
|
||||
|
||||
For us in this case, it helps us ensure a single database session is used through all the request, and then closed afterwards (in the middleware).
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
You can serve static files automatically from a directory using <a href="https://www.starlette.io/staticfiles/" target="_blank">Starlette's Static Files</a>.
|
||||
You can serve static files automatically from a directory using <a href="https://www.starlette.io/staticfiles/" class="external-link" target="_blank">Starlette's Static Files</a>.
|
||||
|
||||
## Install `aiofiles`
|
||||
|
||||
@@ -31,4 +31,4 @@ All these parameters can be different than "`static`", adjust them with the need
|
||||
|
||||
## More info
|
||||
|
||||
For more details and options check <a href="https://www.starlette.io/staticfiles/" target="_blank">Starlette's docs about Static Files</a>.
|
||||
For more details and options check <a href="https://www.starlette.io/staticfiles/" class="external-link" target="_blank">Starlette's docs about Static Files</a>.
|
||||
@@ -33,7 +33,6 @@ For these cases, you can declare an `openapi_prefix` parameter in your `FastAPI`
|
||||
|
||||
See the section below, about "mounting", for an example.
|
||||
|
||||
|
||||
## Mounting a **FastAPI** application
|
||||
|
||||
"Mounting" means adding a complete "independent" application in a specific path, that then takes care of handling all the sub-paths.
|
||||
@@ -78,18 +77,16 @@ Now, run `uvicorn`, if your file is at `main.py`, it would be:
|
||||
uvicorn main:app --reload
|
||||
```
|
||||
|
||||
And open the docs at <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
And open the docs at <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
You will see the automatic API docs for the main app, including only its own paths:
|
||||
|
||||
<img src="/img/tutorial/sub-applications/image01.png">
|
||||
|
||||
|
||||
And then, open the docs for the sub-application, at <a href="http://127.0.0.1:8000/subapi/docs" target="_blank">http://127.0.0.1:8000/subapi/docs</a>.
|
||||
And then, open the docs for the sub-application, at <a href="http://127.0.0.1:8000/subapi/docs" class="external-link" target="_blank">http://127.0.0.1:8000/subapi/docs</a>.
|
||||
|
||||
You will see the automatic API docs for the sub-application, including only its own sub-paths, with their correct prefix:
|
||||
|
||||
<img src="/img/tutorial/sub-applications/image02.png">
|
||||
|
||||
|
||||
If you try interacting with any of the two user interfaces, they will work, because the browser will be able to talk to the correct path (or sub-path).
|
||||
If you try interacting with any of the two user interfaces, they will work, because the browser will be able to talk to the correct path (or sub-path).
|
||||
@@ -64,4 +64,4 @@ And because you are using `StaticFiles`, that CSS file would be served automatic
|
||||
|
||||
## More details
|
||||
|
||||
For more details, including how to test templates, check <a href="https://www.starlette.io/templates/" target="_blank">Starlette's docs on templates</a>.
|
||||
For more details, including how to test templates, check <a href="https://www.starlette.io/templates/" class="external-link" target="_blank">Starlette's docs on templates</a>.
|
||||
@@ -1,8 +1,8 @@
|
||||
Thanks to <a href="https://www.starlette.io/testclient/" target="_blank">Starlette's TestClient</a>, testing **FastAPI** applications is easy and enjoyable.
|
||||
Thanks to <a href="https://www.starlette.io/testclient/" class="external-link" target="_blank">Starlette's TestClient</a>, testing **FastAPI** applications is easy and enjoyable.
|
||||
|
||||
It is based on <a href="http://docs.python-requests.org" target="_blank">Requests</a>, so it's very familiar and intuitive.
|
||||
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.
|
||||
|
||||
With it, you can use <a href="https://docs.pytest.org/" target="_blank">pytest</a> directly with **FastAPI**.
|
||||
With it, you can use <a href="https://docs.pytest.org/" class="external-link" target="_blank">pytest</a> directly with **FastAPI**.
|
||||
|
||||
## Using `TestClient`
|
||||
|
||||
@@ -21,7 +21,7 @@ Write simple `assert` statements with the standard Python expressions that you n
|
||||
```
|
||||
|
||||
!!! tip
|
||||
Notice that the testing functions are normal `def`, not `async def`.
|
||||
Notice that the testing functions are normal `def`, not `async def`.
|
||||
|
||||
And the calls to the client are also normal calls, not using `await`.
|
||||
|
||||
@@ -87,7 +87,7 @@ E.g.:
|
||||
* To pass *headers*, use a `dict` in the `headers` parameter.
|
||||
* For *cookies*, a `dict` in the `cookies` parameter.
|
||||
|
||||
For more information about how to pass data to the backend (using `requests` or the `TestClient`) check the <a href="http://docs.python-requests.org" target="_blank">Requests documentation</a>.
|
||||
For more information about how to pass data to the backend (using `requests` or the `TestClient`) check the <a href="http://docs.python-requests.org" class="external-link" target="_blank">Requests documentation</a>.
|
||||
|
||||
!!! info
|
||||
Note that the `TestClient` receives data that can be converted to JSON, not Pydantic models.
|
||||
|
||||
@@ -13,7 +13,7 @@ But there are situations where you might need to access the `Request` object dir
|
||||
|
||||
## Details about the `Request` object
|
||||
|
||||
As **FastAPI** is actually **Starlette** underneath, with a layer of several tools on top, you can use Starlette's <a href="https://www.starlette.io/requests/" target="_blank">`Request`</a> object directly when you need to.
|
||||
As **FastAPI** is actually **Starlette** underneath, with a layer of several tools on top, you can use Starlette's <a href="https://www.starlette.io/requests/" class="external-link" target="_blank">`Request`</a> object directly when you need to.
|
||||
|
||||
It would also mean that if you get data from the `Request` object directly (for example, read the body) it won't be validated, converted or annotated (with OpenAPI, for the automatic documentation) by FastAPI.
|
||||
|
||||
@@ -52,4 +52,4 @@ Then declare a *path operation function* parameter with the type being the `Requ
|
||||
|
||||
## `Request` documentation
|
||||
|
||||
You can read more details about the <a href="https://www.starlette.io/requests/" target="_blank">`Request` object in the official Starlette documentation site</a>.
|
||||
You can read more details about the <a href="https://www.starlette.io/requests/" class="external-link" target="_blank">`Request` object in the official Starlette documentation site</a>.
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
You can use <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" target="_blank">WebSockets</a> with **FastAPI**.
|
||||
You can use <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" class="external-link" target="_blank">WebSockets</a> with **FastAPI**.
|
||||
|
||||
## WebSockets client
|
||||
|
||||
@@ -68,18 +68,17 @@ They work the same way as for other FastAPI endpoints/*path operations*:
|
||||
!!! info
|
||||
In a WebSocket it doesn't really make sense to raise an `HTTPException`. So it's better to close the WebSocket connection directly.
|
||||
|
||||
You can use a closing code from the <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" target="_blank">valid codes defined in the specification</a>.
|
||||
You can use a closing code from the <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" class="external-link" target="_blank">valid codes defined in the specification</a>.
|
||||
|
||||
In the future, there will be a `WebSocketException` that you will be able to `raise` from anywhere, and add exception handlers for it. It depends on the <a href="https://github.com/encode/starlette/pull/527" target="_blank">PR #527</a> in Starlette.
|
||||
In the future, there will be a `WebSocketException` that you will be able to `raise` from anywhere, and add exception handlers for it. It depends on the <a href="https://github.com/encode/starlette/pull/527" class="external-link" target="_blank">PR #527</a> in Starlette.
|
||||
|
||||
## More info
|
||||
|
||||
To learn more about the options, check Starlette's documentation for:
|
||||
|
||||
* <a href="https://www.starlette.io/applications/" target="_blank">Applications (`websocket_route`)</a>.
|
||||
* <a href="https://www.starlette.io/websockets/" target="_blank">The `WebSocket` class</a>.
|
||||
* <a href="https://www.starlette.io/endpoints/#websocketendpoint" target="_blank">Class-based WebSocket handling</a>.
|
||||
|
||||
* <a href="https://www.starlette.io/applications/" class="external-link" target="_blank">Applications (`websocket_route`)</a>.
|
||||
* <a href="https://www.starlette.io/websockets/" class="external-link" target="_blank">The `WebSocket` class</a>.
|
||||
* <a href="https://www.starlette.io/endpoints/#websocketendpoint" class="external-link" target="_blank">Class-based WebSocket handling</a>.
|
||||
|
||||
## Test it
|
||||
|
||||
@@ -89,7 +88,7 @@ If your file is named `main.py`, run your application with:
|
||||
uvicorn main:app --reload
|
||||
```
|
||||
|
||||
Open your browser at <a href="http://127.0.0.1:8000" target="_blank">http://127.0.0.1:8000</a>.
|
||||
Open your browser at <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
|
||||
|
||||
You will see a simple page like:
|
||||
|
||||
|
||||
Reference in new issue
Block a user