-Details about the `async def` syntax for endpoint functions and some background about asynchronous code, concurrency, and parallelism.
+Details about the `async def` syntax for path operation functions and some background about asynchronous code, concurrency, and parallelism.
## In a hurry?
results = await some_library()
```
-Then, declare your endpoint functions with `async def` like:
+Then, declare your path operation functions with `async def` like:
```Python hl_lines="2"
@app.get('/')
---
-If you are using a third party library that communicates with something (a database, an API, the file system, etc) and doesn't have support for using `await`, (this is currently the case for most database libraries), then declare your endpoint functions as normally, with just `def`, like:
+If you are using a third party library that communicates with something (a database, an API, the file system, etc) and doesn't have support for using `await`, (this is currently the case for most database libraries), then declare your path operation functions as normally, with just `def`, like:
```Python hl_lines="2"
@app.get('/')
---
-**Note**: you can mix `def` and `async def` in your endpoints as much as you need and define each one using the best option for you. FastAPI will do the right thing with them.
+**Note**: you can mix `def` and `async def` in your path operation functions as much as you need and define each one using the best option for you. FastAPI will do the right thing with them.
Anyway, in any of the cases above, FastAPI will still work asynchronously and be extremely fast.
---
-So, if you are using a library that tells you that you can call it with `await`, you need to create the endpoint that uses it with `async def`, like in:
+So, if you are using a library that tells you that you can call it with `await`, you need to create the path operation functions that uses it with `async def`, like in:
```Python hl_lines="2 3"
@app.get('/burgers')
So, about the egg and the chicken, how do you call the first `async` function?
-If you are working with **FastAPI** you don't have to worry about that, because that "first" function will be your endpoint, and FastAPI will know how to do the right thing.
+If you are working with **FastAPI** you don't have to worry about that, because that "first" function will be your path operation function, and FastAPI will know how to do the right thing.
But if you want to use `async` / `await` without FastAPI, <a href="https://docs.python.org/3/library/asyncio-task.html#coroutine" target="_blank">check the official Python docs</a>
### Based on open standards
-* <a href="https://github.com/OAI/OpenAPI-Specification" target="_blank"><strong>OpenAPI</strong></a> for API creation, including declarations of endpoints, parameters, body requests, security, etc.
+* <a href="https://github.com/OAI/OpenAPI-Specification" target="_blank"><strong>OpenAPI</strong></a> for API creation, including declarations of <abbr title="also known as: endpoints, routes">path</abbr> <abbr title="also known as HTTP methods, as POST, GET, PUT, DELETE">operations</abbr>, parameters, body requests, security, etc.
* Automatic data model documentation with <a href="http://json-schema.org/" target="_blank"><strong>JSON Schema</strong></a> (as OpenAPI itself is based on JSON Schema).
* Designed around these standards, after a meticulous study. Instead of an afterthought layer on top.
* This also allows using automatic **client code generation** in many languages.
* Even dependencies can have dependencies, creating a hierarchy or **"graph" of dependencies**.
* All **automatically handled** by the framework.
-* All the dependencies can require data from requests and **augment the endpoint** constraints and automatic documentation.
-* **Automatic validation** even for endpoint parameters defined in dependencies.
+* All the dependencies can require data from requests and **augment the path operation** constraints and automatic documentation.
+* **Automatic validation** even for path operation parameters defined in dependencies.
* Support for complex user authentication systems, **database connections**, etc.
* **No compromise** with databases, frontends, etc. But easy integration with all of them.
Or in other way, no need for them, import and use the code you need.
-Any integration is designed to be so simple to use (with dependencies) that you can create a "plug-in" for your application in 2 lines of code using the same structure and syntax used for your endpoints.
+Any integration is designed to be so simple to use (with dependencies) that you can create a "plug-in" for your application in 2 lines of code using the same structure and syntax used for your path operations.
### Tested
* `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.
+ * `--debug`: make the server restart after code changes. Only do this for development.
### Check it
### Recap
-In summary, you declare **once** the types of parameters, body, etc. as function parameters. You don't have to learn a new syntax, use a specific library, class or object to declare fields, you just type standard Python types.
+In summary, you declare **once** the types of parameters, body, etc. as function parameters.
+
+You do that with standard modern Python types.
+
+You don't have to learn a new syntax, the methods or classes of a specific library, etc.
+
+Just standard **Python 3.6+**.
For example, for an `int`:
* Validation of data:
* Automatic and clear errors when the data is invalid.
* Validation even for deeply nested JSON objects.
-* Serialization of input data: conversion of data coming from the network to Python data and types. Reading from:
+* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of input data: coming from the network, to Python data and types. Reading from:
* JSON.
- * Forms.
- * Files.
* Path parameters.
* Query parameters.
* Cookies.
* Headers.
-* Serialization of output data: converting from Python data and types to network data (as JSON):
+ * Forms.
+ * Files.
+* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> of output data: converting from Python data and types to network data (as JSON):
* Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc).
* `datetime` objects.
* `UUID` objects.
Coming back to the previous code example, **FastAPI** will:
* Validate that there is an `item_id` in the path.
-* Validate that the `item_id` is of type `int`. If it is not, the client will see a useful error.
-* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`). As the `q` parameter is declared with `= None`, it is optional. Without the `None` it would be required (as is the body).
+* Validate that the `item_id` is of type `int`.
+ * If it is not, the client will see a useful, clear error.
+* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`).
+ * As the `q` parameter is declared with `= None`, it is optional.
+ * Without the `None` it would be required (as is the body).
* Read the body as JSON:
* Check that it has a required attribute `name` that should be a `str`.
* Check that is has a required attribute `price` that has to be a `float`.
* Check that it has an optional attribute `is_offer`, that should be a `bool`, if present.
- * All this would also work for deeply nested JSON objects
+ * All this would also work for deeply nested JSON objects.
* Convert from and to JSON automatically.
-* Document everything as OpenAPI, so the interactive documentation is created and updated automatically.
-* Provide the interactive documentation web interfaces.
+* Document everything as an OpenAPI schema, that can be used by:
+ * Interactive documentation sytems.
+ * Automatic client code generation systems, for many languages.
+* Provide 2 interactive documentation web interfaces directly.
---
For a more complete example including more features, [see the tutorial](tutorial/intro/).
-**Spoiler alert**: the tutorial, although very short, includes:
+**Spoiler alert**: the tutorial includes:
-* Declaration of **parameters** from different places as: headers, cookies, form data and files.
+* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**.
* How to set **validation constrains** as `maximum_length` or `regex`.
-* A very powerful and easy to use **Dependency Injection** system (also known as "components", "resources", "providers", "services").
+* A very powerful and easy to use **<abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** system.
* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth.
-* More advanced (but equally easy) techniques for declaring **deeply nested models** (JSON body, Form and Files) (thanks to Pydantic).
-* Many extra features (thanks to Starlette) as **WebSockets**, **GraphQL**, extremely easy tests based on `requests` and `pytest`, CORS, Cookie Sessions and more.
+* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic).
+* Many extra features (thanks to Starlette) as:
+ * **WebSockets**
+ * **GraphQL**
+ * extremely easy tests based on `requests` and `pytest`
+ * **CORS**
+ * **Cookie Sessions**
+ * ...and more.
## Multiple body parameters
-In the previous example, the endpoint would expect a JSON body with the attributes of an `Item`, like:
+In the previous example, the path operations would expect a JSON body with the attributes of an `Item`, like:
```JSON
{
## Recap
-You can add multiple body parameters to your function endpoint, even though a request can only have a single body.
+You can add multiple body parameters to your path operation function, even though a request can only have a single body.
-But **FastAPI** will handle it, give you the correct data in your function, and validate and document the correct schema in the endpoint.
+But **FastAPI** will handle it, give you the correct data in your function, and validate and document the correct schema in the path operation.
You can also declare singular values to be received as part of the body.
-The same way you can declare additional validation and metadata in endpoint function parameters with `Query`, `Path` and `Body`, you can declare validation and metadata inside of Pydantic models using `Schema`.
+The same way you can declare additional validation and metadata in path operation function parameters with `Query`, `Path` and `Body`, you can declare validation and metadata inside of Pydantic models using `Schema`.
## Import Schema
`Body` is also a subclass of `Schema` directly. And there are others you will see later that are subclasses of `Body`.
!!! tip
- Notice how each model's attribute with a type, default value and `Schema` has the same structure as an endpoint's function's parameter, with `Schema` instead of `Path`, `Query` and `Body`.
+ Notice how each model's attribute with a type, default value and `Schema` has the same structure as a path operation function's parameter, with `Schema` instead of `Path`, `Query` and `Body`.
## Schema extras
## Declare it as a parameter
-To add it to your endpoint, declare it the same way you declared path and query parameters:
+To add it to your path operation, declare it the same way you declared path and query parameters:
```Python hl_lines="16"
{!./tutorial/src/body/tutorial001.py!}
<img src="/img/tutorial/body/image01.png">
-And will be also used in the API docs inside each endpoint that needs them:
+And will be also used in the API docs inside each path operation that needs them:
<img src="/img/tutorial/body/image02.png">
`FastAPI` is a Python class that provides all the functionality for your API.
+!!! note "Technical Details"
+ `FastAPI` is a class that inherits directly from `Starlette`.
+
+ You can use all the Starlette functionality with `FastAPI` too.
+
### Step 2: create a `FastAPI` "instance"
```Python hl_lines="3"
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 will be the main point of interaction to create all your API.
This `app` is the same one referred by `uvicorn` in thet command:
uvicorn main:my_awesome_api --debug
```
-### Step 3: create an endpoint
+### Step 3: create a path operation
+
+#### Path
+
+"Path" here refers to the last part of the URL starting from the first `/`.
+
+So, in a URL like:
+
+```
+https://example.com/items/foo
+```
+
+...the path would be:
+
+```
+/items/foo
+```
+
+!!! info
+ A "path" is also commonly called an "endpoint" or a "route".
+
+Building an API, the "path" is the main way to separate "concerns" and functionalities.
+
+#### Operation
+
+"Operation" here refers to one of the HTTP "methods".
+
+One of:
+
+* `POST`
+* `GET`
+* `PUT`
+* `DELETE`
+
+...and the more exotic ones:
+
+* `OPTIONS`
+* `HEAD`
+* `PATCH`
+* `TRACE`
+
+In the HTTP protocol, you can communicate to each path using one (or more) of these "methods".
+
+---
+
+When building APIs, you normally use these specific HTTP methods to perform a specific operation.
+
+Normally you use:
+
+* `POST`: to create data.
+* `GET`: to read data.
+* `PUT`: to update data.
+* `DELETE`: to delete data.
+
+So, in OpenAPI, each of the HTTP methods is called an "operation".
+
+We are going to call them "operations" too.
+
+#### Define a path operation function
```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 `/`.
+The `@app.get("/")` tells **FastAPI** that the function right below is in charge of handling requests that go to:
-You can also use other HTTP methods:
+* the path `/`
+* using a <abbr title="an HTTP GET method"><code>get</code> operation</abbr>
+
+You can also use the other operations:
* `@app.post()`
* `@app.put()`
* `@app.delete()`
-And more exotic ones:
+And the more exotic ones:
* `@app.options()`
* `@app.head()`
* `@app.patch()`
* `@app.trace()`
-### Step 4: define the endpoint function
+!!! 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.
+
+ For example, when using GraphQL you normally perform all the operations using only `post`.
+
+### Step 4: define the path operation function
```Python hl_lines="7"
{!tutorial/src/first-steps/tutorial001.py!}
q: str = Query(None, max_length=50)
```
-This will validate the data, show a clear error when the data is not valid, and document the parameter in the OpenAPI schema endpoint.
+This will validate the data, show a clear error when the data is not valid, and document the parameter in the OpenAPI schema path operation.
## Add more validations
!!! warning
- You can declare multiple `File` and `Form` parameters in an endpoint, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `multipart/form-data` instead of `application/json`.
+ You can declare multiple `File` and `Form` parameters in a path operation, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `multipart/form-data` instead of `application/json`.
This is not a limitation of **FastAPI**, it's part of the HTTP protocol.
The files and form fields will be uploaded as form data and you will receive the files and form fields.
!!! warning
- You can declare multiple `File` and `Form` parameters in an endpoint, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `multipart/form-data` instead of `application/json`.
+ You can declare multiple `File` and `Form` parameters in a path operation, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `multipart/form-data` instead of `application/json`.
This is not a limitation of **FastAPI**, it's part of the HTTP protocol.
!!! warning
- You can declare multiple `Form` parameters in an endpoint, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `application/x-www-form-urlencoded` instead of `application/json`.
+ You can declare multiple `Form` parameters in a path operation, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `application/x-www-form-urlencoded` instead of `application/json`.
This is not a limitation of **FastAPI**, it's part of the HTTP protocol.
-You can declare the model used for the response with the parameter `response_model` in any of the endpoint creation methods:
+You can declare the model used for the response with the parameter `response_model` in any of the path operations:
* `@app.get()`
* `@app.post()`
```
!!! note
- Notice that `response_model` is a parameter of the "decorator" method (`get`, `post`, etc), not of your endpoint function like all the parameters and body.
+ Notice that `response_model` is a parameter of the "decorator" method (`get`, `post`, etc). Not of your path operation function, like all the parameters and body.
It receives a standard Pydantic model and will:
* Convert the output data to the type declarations of the model
* Validate the data
-* Add a JSON Schema for the response, in the OpenAPI endpoint
+* Add a JSON Schema for the response, in the OpenAPI path operation
* Will be used by the automatic documentation systems
But most importantly:
In this case, it might not be a problem, becase the user himself is sending the password.
-But if we use sthe same model for another endpoint, we could be sending the passwords of our users to every client.
+But if we use sthe same model for another path operation, we could be sending the passwords of our users to every client.
!!! danger
Never send the plain password of a user in a response.
{!./tutorial/src/response-model/tutorial003.py!}
```
-Here, even though our endpoint function is returning the same input user that contains the password:
+Here, even though our path operation function is returning the same input user that contains the password:
```Python hl_lines="23"
{!./tutorial/src/response-model/tutorial003.py!}
## Recap
-Use the endpoint decorator's parameter `response_model` to define response models and especially to ensure private data is filtered out.
+Use the path operation decorator's parameter `response_model` to define response models and especially to ensure private data is filtered out.