mirror of https://github.com/tiangolo/fastapi.git
📝 Update docs, add first tutorials
This commit is contained in:
parent
400a4a99af
commit
093bb4cd19
Binary file not shown.
|
After Width: | Height: | Size: 77 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
**Documentation**: [https://fastapi.tiangolo.com](https://fastapi.tiangolo.com)
|
||||
|
||||
**Source**: [https://github.com/tiangolo/fastapi](https://github.com/tiangolo/fastapi)
|
||||
|
||||
---
|
||||
|
||||
FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+.
|
||||
|
|
@ -97,11 +99,12 @@ async def read_root():
|
|||
uvicorn main:app --debug
|
||||
```
|
||||
|
||||
**Note**: the command `uvicorn main:app` refers to:
|
||||
!!! note
|
||||
The command `uvicorn main:app` refers to:
|
||||
|
||||
* `main`: the file `main.py` (the Python "module").
|
||||
* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.
|
||||
* `--debug`: make the server restart after code changes. Only use for development.
|
||||
* `main`: the file `main.py` (the Python "module").
|
||||
* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.
|
||||
* `--debug`: make the server restart after code changes. Only use for development.
|
||||
|
||||
### Check it
|
||||
|
||||
|
|
@ -214,7 +217,7 @@ item: Item
|
|||
* Validation of data:
|
||||
* Automatic and clear errors when the data is invalid.
|
||||
* Validation even for deeply nested JSON objects.
|
||||
* Serialization of input data: from the network to Python, reading from:
|
||||
* Serialization of input data: conversion of data coming from the network to Python data and types. Reading from:
|
||||
* JSON.
|
||||
* Forms.
|
||||
* Files.
|
||||
|
|
@ -222,7 +225,7 @@ item: Item
|
|||
* Query parameters.
|
||||
* Cookies.
|
||||
* Headers.
|
||||
* Serialization of output data: from Python to network (as JSON):
|
||||
* Serialization of output data: converting from Python data and types to network data (as JSON):
|
||||
* Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc).
|
||||
* `datetime` objects.
|
||||
* `UUID` objects.
|
||||
|
|
@ -276,7 +279,7 @@ Try changing the line with:
|
|||

|
||||
|
||||
|
||||
For a more complete example including more features, [see the tutorial](tutorial).
|
||||
For a more complete example including more features, [see the tutorial]().
|
||||
|
||||
**Spoiler alert**: the tutorial, although very short, includes:
|
||||
|
||||
|
|
@ -293,7 +296,7 @@ For a more complete example including more features, [see the tutorial](tutorial
|
|||
|
||||
Used by Pydantic:
|
||||
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON parsing.
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - for faster JSON <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
|
||||
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
|
||||
|
||||
|
||||
|
|
@ -302,7 +305,7 @@ Used by Starlette:
|
|||
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - Required if you want to use the `TestClient`.
|
||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - Required if you want to use `FileResponse` or `StaticFiles`.
|
||||
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - Required if you want to use the default template configuration.
|
||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form parsing, with `request.form()`.
|
||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - Required if you want to support form <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>, with `request.form()`.
|
||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Required for `SessionMiddleware` support.
|
||||
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Required for `SchemaGenerator` support.
|
||||
* <a href="https://graphene-python.org/" target="_blank"><code>graphene</code></a> - Required for `GraphQLApp` support.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,138 @@
|
|||
The simplest FastAPI file could look like this:
|
||||
|
||||
```Python
|
||||
{!tutorial/src/first-steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
Copy that to a file `main.py`.
|
||||
|
||||
Run the live server:
|
||||
|
||||
```bash
|
||||
uvicorn main:app --debug
|
||||
```
|
||||
|
||||
!!! note
|
||||
The command `uvicorn main:app` refers to:
|
||||
|
||||
* `main`: the file `main.py` (the Python "module").
|
||||
* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.
|
||||
* `--debug`: make the server restart after code changes. Only use for development.
|
||||
|
||||
You will see an output like:
|
||||
|
||||
```hl_lines="4"
|
||||
INFO: Started reloader process [17961]
|
||||
INFO: Started server process [17962]
|
||||
INFO: Waiting for application startup.
|
||||
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
That last line shows the URL where your app is being served, in your local machine.
|
||||
|
||||
### Check it
|
||||
|
||||
Open your browser at <a href="http://127.0.0.1:8000" target="_blank">http://127.0.0.1:8000</a>.
|
||||
|
||||
You will see the JSON response as:
|
||||
|
||||
```JSON
|
||||
{"hello": "world"}
|
||||
```
|
||||
|
||||
### 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>.
|
||||
|
||||
You will see the automatic interactive API documentation (provided by <a href="https://github.com/swagger-api/swagger-ui" 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>.
|
||||
|
||||
You will see the alternative automatic documentation (provided by <a href="https://github.com/Rebilly/ReDoc" target="_blank">ReDoc</a>):
|
||||
|
||||

|
||||
|
||||
## Recap, step by step
|
||||
|
||||
### Step 1: import `FastAPI`
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!tutorial/src/first-steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
`FastAPI` is a Python class that provides all the functionality for your API.
|
||||
|
||||
### Step 2: create a `FastAPI` "instance"
|
||||
|
||||
```Python hl_lines="3"
|
||||
{!tutorial/src/first-steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
Here the `app` variable will be an "instance" of the class `FastAPI`.
|
||||
|
||||
This will be the main point of interaction to create all your API endpoints.
|
||||
|
||||
This `app` is the same one referred by `uvicorn` in thet command:
|
||||
|
||||
```bash
|
||||
uvicorn main:app --debug
|
||||
```
|
||||
|
||||
If you create your app like:
|
||||
|
||||
```Python hl_lines="3"
|
||||
{!tutorial/src/first-steps/tutorial002.py!}
|
||||
```
|
||||
|
||||
And put it in a file `main.py`, then you would call `uvicorn` like:
|
||||
|
||||
```bash
|
||||
uvicorn main:my_awesome_api --debug
|
||||
```
|
||||
|
||||
### Step 3: create an endpoint
|
||||
|
||||
```Python hl_lines="6"
|
||||
{!tutorial/src/first-steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
The `@app.get("/")` tells **FastAPI** that the function right below is an endpoint and that it should go to the path route `/`.
|
||||
|
||||
### Step 4: define the endpoint function
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!tutorial/src/first-steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
This is a Python function.
|
||||
|
||||
It will be called by FastAPI whenever it receives a request to the URL "`/`".
|
||||
|
||||
In this case, it is an `async` function.
|
||||
|
||||
---
|
||||
|
||||
You could also define it as a normal function instead of `async def`:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!tutorial/src/first-steps/tutorial003.py!}
|
||||
```
|
||||
|
||||
To know the difference, read the section about [Concurrency and `async` / `await`](/async/).
|
||||
|
||||
### Step 5: return the content
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!tutorial/src/first-steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
You can return a `dict`, `list`, singular values as `str`, `int`, etc.
|
||||
|
||||
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.
|
||||
|
|
@ -1 +0,0 @@
|
|||
Sorry! Coming soon... come back in a couple days.
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
This tutorial shows you how to use **FastAPI** with all its features, step by step.
|
||||
|
||||
Eeach section gradually builds on the previous ones, but it's structured to separate topics, so that you can go directly to any specific one to solve your specific API needs.
|
||||
|
||||
It is also built to work as a future reference. So you can come back and see exactly what you need.
|
||||
|
||||
And each section is very short, so you can go directly to what you need and get the information fast.
|
||||
|
||||
## Run the code
|
||||
|
||||
All the code blocks can be copied and used directly (they are actually tested Python files).
|
||||
|
||||
To run any of the examples, copy the code to a file `main.py`, and start `uvicorn` with:
|
||||
|
||||
```bash
|
||||
uvicorn main:app --debug
|
||||
```
|
||||
|
||||
It is **HIGHLY encouraged** that you write or copy the code, edit it and run it locally.
|
||||
|
||||
Using it in your editor is what really shows you the benefits of FastAPI, seeing how little code you have to write, all the type checks, autocompletion, etc.
|
||||
|
||||
---
|
||||
|
||||
## Install FastAPI
|
||||
|
||||
The first step is to install FastAPI.
|
||||
|
||||
For the tutorial, you might want to install it with all the optional dependencies and features:
|
||||
|
||||
```bash
|
||||
pip install fastapi[all]
|
||||
```
|
||||
|
||||
...that also includes `uvicorn`, that you can use as the server that runs your code.
|
||||
|
||||
!!! note
|
||||
You can also install it part by part.
|
||||
|
||||
This is what you would probably do once you want to deploy your application to production:
|
||||
|
||||
```bash
|
||||
pip install fastapi
|
||||
```
|
||||
|
||||
Also install `uvicorn` to work as the server:
|
||||
|
||||
```bash
|
||||
pip install uvicorn
|
||||
```
|
||||
|
||||
And the same for each of the optional dependencies that you want to use.
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
You can declare path "parameters" or "variables" with the same syntax used by Python format strings:
|
||||
|
||||
```Python hl_lines="6 7"
|
||||
{!./tutorial/src/path-params/tutorial001.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:
|
||||
|
||||
```JSON
|
||||
{"item_id":"foo"}
|
||||
```
|
||||
|
||||
## Path parameters with types
|
||||
|
||||
You can declare the type of a path parameter in the function, using standard Python type annotations:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/path-params/tutorial002.py!}
|
||||
```
|
||||
|
||||
In this case, `item_id` is declared to be an `int`.
|
||||
|
||||
!!! check
|
||||
This will give you editor support inside of your function, with error checks, completion, etc.
|
||||
|
||||
## Data "parsing"
|
||||
|
||||
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:
|
||||
|
||||
```JSON
|
||||
{"item_id":3}
|
||||
```
|
||||
|
||||
!!! check
|
||||
Notice that the value your function received (and returned) is `3`, as a Python `int`, not a string `"3"`.
|
||||
|
||||
So, with that type declaration, **FastAPI** gives you automatic request <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>.
|
||||
|
||||
## 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:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"loc": [
|
||||
"path",
|
||||
"item_id"
|
||||
],
|
||||
"msg": "value is not a valid integer",
|
||||
"type": "type_error.integer"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
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 `foat` 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>
|
||||
|
||||
|
||||
!!! check
|
||||
So, with the same Python type declaration, **FastAPI** gives you data validation.
|
||||
|
||||
Notice that the error also clearly states exactly the point where the validaton didn't pass.
|
||||
|
||||
This is incredibly helpful while developing and debugging code that interacts with your API.
|
||||
|
||||
## 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:
|
||||
|
||||
<img src="/img/tutorial/path-params/image01.png">
|
||||
|
||||
!!! check
|
||||
Again, just with that same Python type declaration, **FastAPI** gives you automatic, interactive documentation (integrating Swagger UI).
|
||||
|
||||
Notice that the path parameter is declared to be an integer.
|
||||
|
||||
## 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.
|
||||
|
||||
Because of this, **FastAPI** itself provides an alternative API documentation (using ReDoc):
|
||||
|
||||
<img src="/img/tutorial/path-params/image02.png">
|
||||
|
||||
The same way, there are many compatible tools. Including code generation tools for many languages.
|
||||
|
||||
## 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.
|
||||
|
||||
You can use the same type declarations with `str`, `float`, `bool` and many other complex data types.
|
||||
|
||||
These are explored in the next sections of the tutorial.
|
||||
|
||||
## Recap
|
||||
|
||||
With **FastAPI**, by using short, intuitive and standard Python type declarations, you get:
|
||||
|
||||
* Editor support: error checks, autocompletion, etc.
|
||||
* Data "<abbr title="converting the string that comes from an HTTP request into Python data">parsing</abbr>"
|
||||
* Data validation
|
||||
* API annotation and automatic documentation
|
||||
|
||||
And you only have to declare them once.
|
||||
|
||||
That's probably the main visible advantage of **FastAPI** compared to alternative frameworks (appart from the raw performance).
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
When you declare other function parameters that are not part of the path parameters, they are automatically interpreted as "query" parameters.
|
||||
|
||||
```Python hl_lines="9"
|
||||
{!./tutorial/src/query-params/tutorial001.py!}
|
||||
```
|
||||
|
||||
The query is the set of key-value pairs that go after the `?` in a URL, separated by `&` characters.
|
||||
|
||||
For example, in the url:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?skip=0&limit=10
|
||||
```
|
||||
|
||||
...the query parameters are:
|
||||
|
||||
* `skip`: with a value of `0`
|
||||
* `limit`: with a value of `10`
|
||||
|
||||
As they are part of the URL, they are "naturally" strings.
|
||||
|
||||
But when you declare them with Python types (in the example above, as `int`), they are converted to that type and validated against it.
|
||||
|
||||
All the same process that applied for path parameters also applies for query parameters:
|
||||
|
||||
* Editor support (obviously)
|
||||
* Data <abbr title="converting the string that comes from an HTTP request into Python data">"parsing"</abbr>
|
||||
* Data validation
|
||||
* Automatic documentation
|
||||
|
||||
## Defaults
|
||||
|
||||
As query parameters are not a fixed part of a path, they can be optional and can have default values.
|
||||
|
||||
In the example above they have default values of `skip=0` and `limit=10`.
|
||||
|
||||
So, going to the URL:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/
|
||||
```
|
||||
|
||||
would be the same as going to:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?skip=0&limit=10
|
||||
```
|
||||
|
||||
But if you go to, for example:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?skip=20
|
||||
```
|
||||
|
||||
The parameter values in your function will be:
|
||||
|
||||
* `skip=20`: because you set it in the URL
|
||||
* `limit=10`: because that was the default value
|
||||
|
||||
## Optional parameters
|
||||
|
||||
The same way, you can declare optional query parameters, by setting their default to `None`:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/query-params/tutorial002.py!}
|
||||
```
|
||||
|
||||
In this case, the function parameter `q` will be optional, and will be `None` by default.
|
||||
|
||||
!!! check
|
||||
Also notice that **FastAPI** is smart enough to notice that the path parameter `item_id` is a path parameter and `q` is not, so, it's a query parameter.
|
||||
|
||||
## Query parameter type conversion
|
||||
|
||||
You can also declare `bool` types, and they will be converted:
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!./tutorial/src/query-params/tutorial003.py!}
|
||||
```
|
||||
|
||||
In this case, if you go to:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?short=1
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?short=True
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?short=true
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?short=on
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?short=yes
|
||||
```
|
||||
|
||||
or any other case variation (uppercase, first letter in uppercase, etc), your function will see the parameter `short` with a `bool` value of `True`. Otherwise as `False`.
|
||||
|
||||
|
||||
## Multiple path and query parameters
|
||||
|
||||
You can declare multiple path parameters and query parameters at the same time, **FastAPI** knows which is which.
|
||||
|
||||
And you don't have to declare them in any specific order.
|
||||
|
||||
They will be detected by name:
|
||||
|
||||
```Python hl_lines="6 8"
|
||||
{!./tutorial/src/query-params/tutorial004.py!}
|
||||
```
|
||||
|
||||
## Required query parameters
|
||||
|
||||
When you declare a default value for non-path parameters (for now, we have only seen query parameters), then it is not required.
|
||||
|
||||
If you don't want to add a specific value but just make it optional, set the default as `None`.
|
||||
|
||||
But when you want to make a query parameter required, you can just do not declare any default value:
|
||||
|
||||
```Python hl_lines="6 8"
|
||||
{!./tutorial/src/query-params/tutorial005.py!}
|
||||
```
|
||||
|
||||
Here the query parameter `needy` is a required query parameter of type `str`.
|
||||
|
||||
If you open in your browser a URL like:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/users/2/items/foo-item
|
||||
```
|
||||
|
||||
...without adding the required parameter `needy`, you will see an error like:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"loc": [
|
||||
"query",
|
||||
"needy"
|
||||
],
|
||||
"msg": "field required",
|
||||
"type": "value_error.missing"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
As `needy` is a required parameter, you would need to set it in the URL:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/users/2/items/foo-item?needy=sooooneedy
|
||||
```
|
||||
|
||||
...this would work:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"item_id": "foo-item",
|
||||
"owner_id": 2,
|
||||
"needy": "sooooneedy"
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
from fastapi import FastAPI
|
||||
|
||||
my_awesome_api = FastAPI()
|
||||
|
||||
|
||||
@my_awesome_api.get("/")
|
||||
async def root():
|
||||
return {"message": "Hello World"}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def root():
|
||||
return {"message": "Hello World"}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/users/{user_id}/items/{item_id}")
|
||||
async def read_user_item(
|
||||
user_id: int, item_id: str, needy: str
|
||||
):
|
||||
item = {"item_id": item_id, "owner_id": user_id, "needy": needy}
|
||||
return item
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/users/{user_id}/items/{item_id}")
|
||||
async def read_user_item(
|
||||
user_id: int, item_id: str, needy: str, q: str = None, short: bool = False
|
||||
):
|
||||
item = {"item_id": item_id, "owner_id": user_id, "needy": needy}
|
||||
if q:
|
||||
item.update({"q": q})
|
||||
if not short:
|
||||
item.update(
|
||||
{"description": "This is an amazing item that has a long description"}
|
||||
)
|
||||
return item
|
||||
Loading…
Reference in New Issue