mirror of
https://github.com/fastapi/fastapi.git
synced 2026-10-22 18:06:17 -04:00
📝 Refactor docs, "Tutorial - User Guide" and "Advanced User Guide" (#887)
This commit is contained in:
1 parent
a41a729682
commit
22982287ff
78 files changed
+340
-292
No files matched your search
@@ -1,73 +0,0 @@
|
||||
!!! warning
|
||||
This is, more or less, an "advanced" chapter.
|
||||
|
||||
If you are just starting with **FastAPI** you might want to skip this chapter and come back to it later.
|
||||
|
||||
## Parameterized dependencies
|
||||
|
||||
All the dependencies we have seen are a fixed function or class.
|
||||
|
||||
But there could be cases where you want to be able to set parameters on the dependency, without having to declare many different functions or classes.
|
||||
|
||||
Let's imagine that we want to have a dependency that checks if the query parameter `q` contains some fixed content.
|
||||
|
||||
But we want to be able to parameterize that fixed content.
|
||||
|
||||
## A "callable" instance
|
||||
|
||||
In Python there's a way to make an instance of a class a "callable".
|
||||
|
||||
Not the class itself (which is already a callable), but an instance of that class.
|
||||
|
||||
To do that, we declare a method `__call__`:
|
||||
|
||||
```Python hl_lines="10"
|
||||
{!./src/dependencies/tutorial011.py!}
|
||||
```
|
||||
|
||||
In this case, this `__call__` is what **FastAPI** will use to check for additional parameters and sub-dependencies, and this is what will be called to pass a value to the parameter in your *path operation function* later.
|
||||
|
||||
## Parameterize the instance
|
||||
|
||||
And now, we can use `__init__` to declare the parameters of the instance that we can use to "parameterize" the dependency:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./src/dependencies/tutorial011.py!}
|
||||
```
|
||||
|
||||
In this case, **FastAPI** won't ever touch or care about `__init__`, we will use it directly in our code.
|
||||
|
||||
## Create an instance
|
||||
|
||||
We could create an instance of this class with:
|
||||
|
||||
```Python hl_lines="16"
|
||||
{!./src/dependencies/tutorial011.py!}
|
||||
```
|
||||
|
||||
And that way we are able to "parameterize" our dependency, that now has `"bar"` inside of it, as the attribute `checker.fixed_content`.
|
||||
|
||||
## Use the instance as a dependency
|
||||
|
||||
Then, we could use this `checker` in a `Depends(checker)`, instead of `Depends(FixedContentQueryChecker)`, because the dependency is the instance, `checker`, not the class itself.
|
||||
|
||||
And when solving the dependency, **FastAPI** will call this `checker` like:
|
||||
|
||||
```Python
|
||||
checker(q="somequery")
|
||||
```
|
||||
|
||||
...and pass whatever that returns as the value of the dependency in our path operation function as the parameter `fixed_content_included`:
|
||||
|
||||
```Python hl_lines="20"
|
||||
{!./src/dependencies/tutorial011.py!}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
All this might seem contrived. And it might not be very clear how is it useful yet.
|
||||
|
||||
These examples are intentionally simple, but show how it all works.
|
||||
|
||||
In the chapters about security, you will be using utility functions that are implemented in this same way.
|
||||
|
||||
If you understood all this, you already know how those utility tools for security work underneath.
|
||||
@@ -2,13 +2,13 @@ Before diving deeper into the **Dependency Injection** system, let's upgrade the
|
||||
|
||||
## A `dict` from the previous example
|
||||
|
||||
In the previous example, we are returning a `dict` from our dependency ("dependable"):
|
||||
In the previous example, we were returning a `dict` from our dependency ("dependable"):
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./src/dependencies/tutorial001.py!}
|
||||
```
|
||||
|
||||
But then we get a `dict` in the parameter `commons` of the path operation function.
|
||||
But then we get a `dict` in the parameter `commons` of the *path operation function*.
|
||||
|
||||
And we know that editors can't provide a lot of support (like completion) for `dict`s, because they can't know their keys and value types.
|
||||
|
||||
@@ -63,9 +63,9 @@ Then, in **FastAPI**, you could use a Python class as a dependency.
|
||||
|
||||
What FastAPI actually checks is that it is a "callable" (function, class or anything else) and the parameters defined.
|
||||
|
||||
If you pass a "callable" as a dependency in **FastAPI**, it will analyze the parameters for that "callable", and process them in the same way as the parameters for a path operation function. Including sub-dependencies.
|
||||
If you pass a "callable" as a dependency in **FastAPI**, it will analyze the parameters for that "callable", and process them in the same way as the parameters for a *path operation function*. Including sub-dependencies.
|
||||
|
||||
That also applies to callables with no parameters at all. The same as it would be for path operation functions with no parameters.
|
||||
That also applies to callables with no parameters at all. The same as it would be for *path operation functions* with no parameters.
|
||||
|
||||
Then, we can change the dependency "dependable" `common_parameters` from above to the class `CommonQueryParameters`:
|
||||
|
||||
@@ -173,7 +173,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams)
|
||||
commons: CommonQueryParams = Depends()
|
||||
```
|
||||
|
||||
So, you can declare the dependency as the type of the variable, and use `Depends()` as the "default" value, without any parameter, instead of having to write the full class *again* inside of `Depends(CommonQueryParams)`.
|
||||
So, you can declare the dependency as the type of the variable, and use `Depends()` as the "default" value (the value after the `=`) for that function's parameter, without any parameter, instead of having to write the full class *again* inside of `Depends(CommonQueryParams)`.
|
||||
|
||||
So, the same example would look like:
|
||||
|
||||
|
||||
@@ -57,4 +57,4 @@ So, you can re-use a normal dependency (that returns a value) you already use so
|
||||
|
||||
## Dependencies for a group of *path operations*
|
||||
|
||||
Later, when reading about how to <a href="https://fastapi.tiangolo.com/tutorial/bigger-applications/" target="_blank">structure bigger applications</a>, possibly with multiple files, you will learn how to declare a single `dependencies` parameter for a group of *path operations*.
|
||||
Later, when reading about how to structure bigger applications ([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md){.internal-link target=_blank}), possibly with multiple files, you will learn how to declare a single `dependencies` parameter for a group of *path operations*.
|
||||
@@ -10,11 +10,11 @@ To do this, use `yield` instead of `return`, and write the extra steps after.
|
||||
!!! info
|
||||
For this to work, you need to use **Python 3.7** or above, or in **Python 3.6**, install the "backports":
|
||||
|
||||
```bash
|
||||
```
|
||||
pip install async-exit-stack async-generator
|
||||
```
|
||||
|
||||
This installs <a href="https://github.com/sorcio/async_exit_stack" class="external-link" target="_blank">async-exit-stack</a> and <a href="https://github.com/python-trio/async_generator" target="_blank">async-generator</a>.
|
||||
This installs <a href="https://github.com/sorcio/async_exit_stack" class="external-link" target="_blank">async-exit-stack</a> and <a href="https://github.com/python-trio/async_generator" class="external-link" target="_blank">async-generator</a>.
|
||||
|
||||
!!! note "Technical Details"
|
||||
Any function that is valid to use with:
|
||||
@@ -116,7 +116,7 @@ with open("./somefile.txt") as f:
|
||||
print(contents)
|
||||
```
|
||||
|
||||
Underneath, the `open("./somefile.txt")` returns an object that is a called a "Context Manager".
|
||||
Underneath, the `open("./somefile.txt")` creates an object that is a called a "Context Manager".
|
||||
|
||||
When the `with` block finishes, it makes sure to close the file, even if there were exceptions.
|
||||
|
||||
@@ -129,9 +129,9 @@ When you create a dependency with `yield`, **FastAPI** will internally convert i
|
||||
|
||||
If you are just starting with **FastAPI** you might want to skip it for now.
|
||||
|
||||
In Python, you can create context managers by <a href="https://docs.python.org/3/reference/datamodel.html#context-managers" class="external-link" target="_blank">creating a class with two methods: `__enter__()` and `__exit__()`</a>.
|
||||
In Python, you can create Context Managers by <a href="https://docs.python.org/3/reference/datamodel.html#context-managers" class="external-link" target="_blank">creating a class with two methods: `__enter__()` and `__exit__()`</a>.
|
||||
|
||||
You can also use them with **FastAPI** dependencies with `yield` by using
|
||||
You can also use them inside of **FastAPI** dependencies with `yield` by using
|
||||
`with` or `async with` statements inside of the dependency function:
|
||||
|
||||
```Python hl_lines="1 2 3 4 5 6 7 8 9 13"
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
It is designed to be very simple to use, and to make it very easy for any developer to integrate other components with **FastAPI**.
|
||||
|
||||
## "Dependency Injection"?
|
||||
## What is "Dependency Injection"
|
||||
|
||||
**"Dependency Injection"** means, in programming, that there is a way for your code (in this case, your path operation functions) to declare things that it requires to work and use: "dependencies".
|
||||
**"Dependency Injection"** means, in programming, that there is a way for your code (in this case, your *path operation functions*) to declare things that it requires to work and use: "dependencies".
|
||||
|
||||
And then, that system (in this case **FastAPI**) will take care of doing whatever is needed to provide your code with those needed dependencies ("inject" the dependencies).
|
||||
|
||||
@@ -13,7 +13,7 @@ This is very useful when you need to:
|
||||
* Have shared logic (the same code logic again and again).
|
||||
* Share database connections.
|
||||
* Enforce security, authentication, role requirements, etc.
|
||||
* etc.
|
||||
* And many other things...
|
||||
|
||||
All these, while minimizing code repetition.
|
||||
|
||||
@@ -27,7 +27,7 @@ But this way we can focus on how the **Dependency Injection** system works.
|
||||
|
||||
Let's first focus on the dependency.
|
||||
|
||||
It is just a function that can take all the same parameters that a path operation function can take:
|
||||
It is just a function that can take all the same parameters that a *path operation function* can take:
|
||||
|
||||
```Python hl_lines="6 7"
|
||||
{!./src/dependencies/tutorial001.py!}
|
||||
@@ -37,9 +37,9 @@ That's it.
|
||||
|
||||
**2 lines**.
|
||||
|
||||
And it has the same shape and structure that all your path operation functions.
|
||||
And it has the same shape and structure that all your *path operation functions*.
|
||||
|
||||
You can think of it as a path operation function without the "decorator" (without the `@app.get("/some-path")`).
|
||||
You can think of it as a *path operation function* without the "decorator" (without the `@app.get("/some-path")`).
|
||||
|
||||
And it can return anything you want.
|
||||
|
||||
@@ -59,7 +59,7 @@ And then it just returns a `dict` containing those values.
|
||||
|
||||
### Declare the dependency, in the "dependant"
|
||||
|
||||
The same way you use `Body`, `Query`, etc. with your path operation function parameters, use `Depends` with a new parameter:
|
||||
The same way you use `Body`, `Query`, etc. with your *path operation function* parameters, use `Depends` with a new parameter:
|
||||
|
||||
```Python hl_lines="11 16"
|
||||
{!./src/dependencies/tutorial001.py!}
|
||||
@@ -71,7 +71,7 @@ You only give `Depends` a single parameter.
|
||||
|
||||
This parameter must be something like a function.
|
||||
|
||||
And that function takes parameters in the same way that path operation functions do.
|
||||
And that function takes parameters in the same way that *path operation functions* do.
|
||||
|
||||
!!! tip
|
||||
You'll see what other "things", apart from functions, can be used as dependencies in the next chapter.
|
||||
@@ -80,26 +80,25 @@ Whenever a new request arrives, **FastAPI** will take care of:
|
||||
|
||||
* Calling your dependency ("dependable") function with the correct parameters.
|
||||
* Get the result from your function.
|
||||
* Assign that result to the parameter in your path operation function.
|
||||
* Assign that result to the parameter in your *path operation function*.
|
||||
|
||||
!!! note
|
||||
!!! check
|
||||
Notice that you don't have to create a special class and pass it somewhere to **FastAPI** to "register" it or anything similar.
|
||||
|
||||
You just pass it to `Depends` and **FastAPI** knows how to do the rest.
|
||||
|
||||
## To `async` or not to `async`
|
||||
|
||||
As dependencies will also be called by **FastAPI** (the same as your path operation functions), the same rules apply while defining your functions.
|
||||
As dependencies will also be called by **FastAPI** (the same as your *path operation functions*), the same rules apply while defining your functions.
|
||||
|
||||
You can use `async def` or normal `def`.
|
||||
|
||||
And you can declare dependencies with `async def` inside of normal `def` path operation functions, or `def` dependencies inside of `async def` path operation functions, etc.
|
||||
And you can declare dependencies with `async def` inside of normal `def` *path operation functions*, or `def` dependencies inside of `async def` *path operation functions*, etc.
|
||||
|
||||
It doesn't matter. **FastAPI** will know what to do.
|
||||
|
||||
!!! note
|
||||
If you don't know, check the _"In a hurry?"_ section about <a href="https://fastapi.tiangolo.com/async/#in-a-hurry" target="_blank">`async` and `await` in the docs</a>.
|
||||
|
||||
If you don't know, check the [Async: *"In a hurry?"*](../../async.md){.internal-link target=_blank} section about `async` and `await` in the docs.
|
||||
|
||||
## Integrated with OpenAPI
|
||||
|
||||
@@ -118,7 +117,7 @@ Actually, all (or most) of the web frameworks work in this same way.
|
||||
|
||||
You never call those functions directly. They are called by your framework (in this case, **FastAPI**).
|
||||
|
||||
With the Dependency Injection system, you can also tell **FastAPI** that your path operation function also "depends" on something else that should be executed before your *path operation function*, and **FastAPI** will take care of executing it and "injecting" the results.
|
||||
With the Dependency Injection system, you can also tell **FastAPI** that your *path operation function* also "depends" on something else that should be executed before your *path operation function*, and **FastAPI** will take care of executing it and "injecting" the results.
|
||||
|
||||
Other common terms for this same idea of "dependency injection" are:
|
||||
|
||||
@@ -130,9 +129,9 @@ Other common terms for this same idea of "dependency injection" are:
|
||||
|
||||
## **FastAPI** plug-ins
|
||||
|
||||
Integrations and "plug-in"s can be built using the **Dependency Injection** system. But in fact, there is actually **no need to create "plug-ins"**, as by using dependencies it's possible to declare an infinite number of integrations and interactions that become available to your path operation functions.
|
||||
Integrations and "plug-in"s can be built using the **Dependency Injection** system. But in fact, there is actually **no need to create "plug-ins"**, as by using dependencies it's possible to declare an infinite number of integrations and interactions that become available to your *path operation functions*.
|
||||
|
||||
And dependencies can be created in a very simple and intuitive way that allow you to just import the Python packages you need, and integrate them with your API functions in a couple of lines of code, _literally_.
|
||||
And dependencies can be created in a very simple and intuitive way that allow you to just import the Python packages you need, and integrate them with your API functions in a couple of lines of code, *literally*.
|
||||
|
||||
You will see examples of this in the next chapters, about relational and NoSQL databases, security, etc.
|
||||
|
||||
@@ -159,6 +158,6 @@ In the end, a hierarchical tree of dependencies is built, and the **Dependency I
|
||||
|
||||
## Integrated with **OpenAPI**
|
||||
|
||||
All these dependencies, while declaring their requirements, add parameters, validations, etc. to your path operations.
|
||||
All these dependencies, while declaring their requirements, also add parameters, validations, etc. to your *path operations*.
|
||||
|
||||
**FastAPI** will take care of adding it all to the OpenAPI schema, so that it is shown in the interactive documentation systems.
|
||||
@@ -1,6 +1,6 @@
|
||||
You can create dependencies that have sub-dependencies.
|
||||
You can create dependencies that have **sub-dependencies**.
|
||||
|
||||
They can be as "deep" as you need them to be.
|
||||
They can be as **deep** as you need them to be.
|
||||
|
||||
**FastAPI** will take care of solving them.
|
||||
|
||||
@@ -40,7 +40,7 @@ Then we can use the dependency with:
|
||||
```
|
||||
|
||||
!!! info
|
||||
Notice that we are only declaring one dependency in the path operation function, the `query_or_cookie_extractor`.
|
||||
Notice that we are only declaring one dependency in the *path operation function*, the `query_or_cookie_extractor`.
|
||||
|
||||
But **FastAPI** will know that it has to solve `query_extractor` first, to pass the results of that to `query_or_cookie_extractor` while calling it.
|
||||
|
||||
@@ -61,7 +61,7 @@ async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False
|
||||
|
||||
Apart from all the fancy words used here, the **Dependency Injection** system is quite simple.
|
||||
|
||||
Just functions that look the same as the path operation functions.
|
||||
Just functions that look the same as the *path operation functions*.
|
||||
|
||||
But still, it is very powerful, and allows you to declare arbitrarily deeply nested dependency "graphs" (trees).
|
||||
|
||||
|
||||
Reference in new issue
Block a user