* :sparkles: Re-export main features used from Starlette to simplify developer's code
* :recycle: Refactor Starlette exports
* :recycle: Refactor tutorial examples to use re-exported utils from Starlette
* :memo: Add examples for all middlewares
* :memo: Add new docs for middlewares
* :memo: Add examples for custom responses
* :memo: Extend docs for custom responses
* :memo: Update docs and add notes explaining re-exports from Starlette everywhere
* :bento: Update screenshot for HTTP status
* :wrench: Update MkDocs config with new content
* :recycle: Refactor tests to use re-exported utils from Starlette
* :sparkles: Re-export WebSocketDisconnect from Starlette for tests
* :white_check_mark: Add extra tests for extra re-exported middleware
* :white_check_mark: Add tests for re-exported responses from Starlette
* :sparkles: Add docs about mounting WSGI apps
* :heavy_plus_sign: Add Flask as a dependency to test WSGIMiddleware
* :white_check_mark: Test WSGIMiddleware example
-By default, **FastAPI** will return the responses using Starlette's `JSONResponse`, putting the content you return from your *path operation* inside of that `JSONResponse`.
+By default, **FastAPI** will return the responses using a `JSONResponse`, putting the content you return from your *path operation* inside of that `JSONResponse`.
It will use the default status code or the one you set in your *path operation*.
To achieve that, import `JSONResponse`, and return your content there directly, setting the `status_code` that you want:
-```Python hl_lines="2 20"
+```Python hl_lines="2 19"
{!./src/additional_status_codes/tutorial001.py!}
```
Make sure it has the data you want it to have, and that the values are valid JSON (if you are using `JSONResponse`).
+!!! note "Technical Details"
+ You could also use `from starlette.responses import JSONResponse`.
+
+ **FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette. The same with `status`.
+
## OpenAPI and API docs
-If you return additional status codes and responses directly, they won't be included in the OpenAPI schema (the API docs), because FastAPI doesn't have a way to know before hand what you are going to return.
+If you return additional status codes and responses directly, they won't be included in the OpenAPI schema (the API docs), because FastAPI doesn't have a way to know beforehand what you are going to return.
But you can document that in your code, using: [Additional Responses](additional-responses.md){.internal-link target=_blank}.
-!!! 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.
### Create a custom `GzipRequest` class
+!!! tip
+ This is a toy example to demonstrate how it works, if you need Gzip support, you can use the provided [`GzipMiddleware`](./middleware.md#gzipmiddleware){.internal-link target=_blank}.
+
First, we create a `GzipRequest` class, which will overwrite the `Request.body()` method to decompress the body in the presence of an appropriate header.
If there's no `gzip` in the header, it will not try to decompress the body.
That way, the same route class can handle gzip compressed or uncompressed requests.
-```Python hl_lines="10 11 12 13 14 15 16 17"
+```Python hl_lines="8 9 10 11 12 13 14 15"
{!./src/custom_request_and_route/tutorial001.py!}
```
Here we use it to create a `GzipRequest` from the original request.
-```Python hl_lines="20 21 22 23 24 25 26 27 28"
+```Python hl_lines="18 19 20 21 22 23 24 25 26"
{!./src/custom_request_and_route/tutorial001.py!}
```
All we need to do is handle the request inside a `try`/`except` block:
-```Python hl_lines="15 17"
+```Python hl_lines="13 15"
{!./src/custom_request_and_route/tutorial002.py!}
```
If an exception occurs, the`Request` instance will still be in scope, so we can read and make use of the request body when handling the error:
-```Python hl_lines="18 19 20"
+```Python hl_lines="16 17 18"
{!./src/custom_request_and_route/tutorial002.py!}
```
You can also set the `route_class` parameter of an `APIRouter`:
-```Python hl_lines="28"
+```Python hl_lines="26"
{!./src/custom_request_and_route/tutorial003.py!}
```
In this example, the *path operations* under the `router` will use the custom `TimedRoute` class, and will have an extra `X-Response-Time` header in the response with the time it took to generate the response:
-```Python hl_lines="15 16 17 18 19 20 21 22"
+```Python hl_lines="13 14 15 16 17 18 19 20"
{!./src/custom_request_and_route/tutorial003.py!}
```
-!!! warning
- This is a rather advanced topic.
-
- If you are starting with **FastAPI**, you might not need this.
-
-By default, **FastAPI** will return the responses using Starlette's `JSONResponse`.
+By default, **FastAPI** will return the responses using `JSONResponse`.
You can override it by returning a `Response` directly as seen in [Return a Response directly](response-directly.md){.internal-link target=_blank}.
-But if you return a `Response` directly, the data won't be automatically converted, and the documentation won't be automatically generated (for example, including the specific "media type", in the HTTP header `Content-Type`).
+But if you return a `Response` directly, the data won't be automatically converted, and the documentation won't be automatically generated (for example, including the specific "media type", in the HTTP header `Content-Type` as part of the generated OpenAPI).
But you can also declare the `Response` that you want to be used, in the *path operation decorator*.
## Use `UJSONResponse`
-For example, if you are squeezing performance, you can install and use `ujson` and set the response to be Starlette's `UJSONResponse`.
+For example, if you are squeezing performance, you can install and use `ujson` and set the response to be `UJSONResponse`.
Import the `Response` class (sub-class) you want to use and declare it in the *path operation decorator*.
{!./src/custom_response/tutorial001.py!}
```
-!!! note
- Notice that you import it directly from `starlette.responses`, not from `fastapi`.
-
!!! info
The parameter `response_class` will also be used to define the "media type" of the response.
{!./src/custom_response/tutorial002.py!}
```
-!!! note
- Notice that you import it directly from `starlette.responses`, not from `fastapi`.
-
!!! info
The parameter `response_class` will also be used to define the "media type" of the response.
And it will be documented as such in OpenAPI.
-### Return a Starlette `Response`
+### Return a `Response`
As seen in [Return a Response directly](response-directly.md){.internal-link target=_blank}, you can also override the response directly in your *path operation*, by returning it.
{!./src/custom_response/tutorial004.py!}
```
-In this example, the function `generate_html_response()` already generates a Starlette `Response` instead of the HTML in a `str`.
+In this example, the function `generate_html_response()` already generates and returns a `Response` instead of returning the HTML in a `str`.
By returning the result of calling `generate_html_response()`, you are already returning a `Response` that will override the default **FastAPI** behavior.
-But as you passed the `HTMLResponse` in the `response_class`, **FastAPI** will know how to document it in OpenAPI and the interactive docs as HTML with `text/html`:
+But as you passed the `HTMLResponse` in the `response_class` too, **FastAPI** will know how to document it in OpenAPI and the interactive docs as HTML with `text/html`:
<img src="/img/tutorial/custom-response/image01.png">
+## Available responses
+
+Here are some of the available responses.
+
+Have in mind that you can use `Response` to return anything else, or even create a custom sub-class.
+
+!!! note "Technical Details"
+ You could also use `from starlette.responses import HTMLResponse`.
+
+ **FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette.
+
+### `Response`
+
+The main `Response` class, all the other responses inherit from it.
+
+You can return it directly.
+
+It accepts the following parameters:
+
+* `content` - A `str` or `bytes`.
+* `status_code` - An `int` HTTP status code.
+* `headers` - A `dict` of strings.
+* `media_type` - A `str` giving the media type. E.g. `"text/html"`.
+
+FastAPI (actually Starlette) will automatically include a Content-Length header. It will also include a Content-Type header, based on the media_type and appending a charset for text types.
+
+```Python hl_lines="1 18"
+{!./src/response_directly/tutorial002.py!}
+```
+
+### `HTMLResponse`
+
+Takes some text or bytes and returns an HTML response, as you read above.
+
+### `PlainTextResponse`
+
+Takes some text or bytes and returns an plain text response.
+
+```Python hl_lines="2 7 9"
+{!./src/custom_response/tutorial005.py!}
+```
+
+### `JSONResponse`
+
+Takes some data and returns an `application/json` encoded response.
+
+This is the default response used in **FastAPI**, as you read above.
+
+### `UJSONResponse`
+
+An alternative JSON response using `ujson` for faster serialization as you read above.
+
+!!! warning
+ `ujson` is less careful than Python's built-in implementation in how it handles some edge-cases.
+
+### `RedirectResponse`
+
+Returns an HTTP redirect. Uses a 307 status code (Temporary Redirect) by default.
+
+```Python hl_lines="2 9"
+{!./src/custom_response/tutorial006.py!}
+```
+
+### `StreamingResponse`
+
+Takes an async generator or a normal generator/iterator and streams the response body.
+
+```Python hl_lines="2 14"
+{!./src/custom_response/tutorial007.py!}
+```
+
+#### Using `StreamingResponse` with file-like objects
+
+If you have a file-like object (e.g. the object returned by `open()`), you can return it in a `StreamingResponse`.
+
+This includes many libraries to interact with cloud storage, video processing, and others.
+
+```Python hl_lines="2 10 11"
+{!./src/custom_response/tutorial008.py!}
+```
+
+!!! tip
+ Notice that here as we are using standard `open()` that doesn't support `async` and `await`, we declare the path operation with normal `def`.
+
+### `FileResponse`
+
+Asynchronously streams a file as the response.
+
+Takes a different set of arguments to instantiate than the other response types:
+
+* `path` - The filepath to the file to stream.
+* `headers` - Any custom headers to include, as a dictionary.
+* `media_type` - A string giving the media type. If unset, the filename or path will be used to infer a media type.
+* `filename` - If set, this will be included in the response `Content-Disposition`.
+
+File responses will include appropriate `Content-Length`, `Last-Modified` and `ETag` headers.
+
+```Python hl_lines="2 10"
+{!./src/custom_response/tutorial009.py!}
+```
+
## Additional documentation
You can also declare the media type and many other details in OpenAPI using `responses`: [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}.
### Serve the static files
-* Import `StaticFiles` from Starlette.
+* Import `StaticFiles`.
* "Mount" a `StaticFiles()` instance in a specific path.
```Python hl_lines="7 11"
--- /dev/null
+In the main tutorial you read how to add [Custom Middleware](../tutorial/middleware.md){.internal-link target=_blank} to your application.
+
+And then you also read how to handle [CORS with the `CORSMiddleware`](../tutorial/cors.md){.internal-link target=_blank}.
+
+In this section we'll see how to use other middlewares.
+
+## Adding ASGI middlewares
+
+As **FastAPI** is based on Starlette and implements the <abbr title="Asynchronous Server Gateway Interface">ASGI</abbr> specification, you can use any ASGI middleware.
+
+A middleware doesn't have to be made for FastAPI or Starlette to work, as long as it follows the ASGI spec.
+
+In general, ASGI middlewares are classes that expect to receive an ASGI app as the first argument.
+
+So, in the documentation for third-party ASGI middlewares they will probably tell you to do something like:
+
+```Python
+from unicorn import UnicornMiddleware
+
+app = SomeASGIApp()
+
+new_app = UnicornMiddleware(app, some_config="rainbow")
+```
+
+But FastAPI (actually Starlette) provides a simpler way to do it that makes sure that the internal middlewares to handle server errors and custom exception handlers work properly.
+
+For that, you use `app.add_middleware()` (as in the example for CORS).
+
+```Python
+from fastapi import FastAPI
+from unicorn import UnicornMiddleware
+
+app = FastAPI()
+
+app.add_middleware(UnicornMiddleware, some_config="rainbow")
+```
+
+`app.add_middleware()` receives a middleware class as the first argument and any additional arguments to be passed to the middleware.
+
+## Integrated middlewares
+
+**FastAPI** includes several middlewares for common use cases, we'll see next how to use them.
+
+!!! note "Technical Details"
+ For the next examples, you could also use `from starlette.middleware.something import SomethingMiddleware`.
+
+ **FastAPI** provides several middlewares in `fastapi.middleware` just as a convenience for you, the developer. But most of the available middlewares come directly from Starlette.
+
+## `HTTPSRedirectMiddleware`
+
+Enforces that all incoming requests must either be `https` or `wss`.
+
+Any incoming requests to `http` or `ws` will be redirected to the secure scheme instead.
+
+```Python hl_lines="2 6"
+{!./src/advanced_middleware/tutorial001.py!}
+```
+
+## `TrustedHostMiddleware`
+
+Enforces that all incoming requests have a correctly set `Host` header, in order to guard against HTTP Host Header attacks.
+
+```Python hl_lines="2 6 7 8"
+{!./src/advanced_middleware/tutorial002.py!}
+```
+
+The following arguments are supported:
+
+* `allowed_hosts` - A list of domain names that should be allowed as hostnames. Wildcard domains such as `*.example.com` are supported for matching subdomains to allow any hostname either use `allowed_hosts=["*"]` or omit the middleware.
+
+If an incoming request does not validate correctly then a `400` response will be sent.
+
+## `GZipMiddleware`
+
+Handles GZip responses for any request that includes `"gzip"` in the `Accept-Encoding` header.
+
+The middleware will handle both standard and streaming responses.
+
+```Python hl_lines="2 6 7 8"
+{!./src/advanced_middleware/tutorial002.py!}
+```
+
+The following arguments are supported:
+
+* `minimum_size` - Do not GZip responses that are smaller than this minimum size in bytes. Defaults to `500`.
+
+## Other middlewares
+
+There are many other ASGI middlewares.
+
+For example:
+
+* <a href="https://docs.sentry.io/platforms/python/asgi/" class="external-link" target="_blank">Sentry</a>
+* <a href="https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py" class="external-link" target="_blank">Uvicorn's `ProxyHeadersMiddleware`</a>
+* <a href="https://github.com/florimondmanca/msgpack-asgi" class="external-link" target="_blank">MessagePack</a>
+
+To see other available middlewares check <a href="https://www.starlette.io/middleware/" class="external-link" target="_blank">Starlette's Middleware docs</a> and the <a href="https://github.com/florimondmanca/awesome-asgi" class="external-link" target="_blank">ASGI Awesome List</a>.
And then you can set the `status_code` in that *temporal* response object.
-```Python hl_lines="2 11 14"
+```Python hl_lines="1 9 12"
{!./src/response_change_status_code/tutorial001.py!}
```
You can declare a parameter of type `Response` in your *path operation function*.
-And then you can set headers in that *temporal* response object.
+And then you can set cookies in that *temporal* response object.
-```Python hl_lines="2 8 9"
+```Python hl_lines="1 8 9"
{!./src/response_cookies/tutorial002.py!}
```
### More info
+!!! note "Technical Details"
+ You could also use `from starlette.responses import Response` or `from starlette.responses import JSONResponse`.
+
+ **FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette.
+
+ And as the `Response` can be used frequently to set headers and cookies, **FastAPI** also provides it at `fastapi.Response`.
+
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>.
By default, **FastAPI** would automatically convert that return value to JSON using the `jsonable_encoder` explained in [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}.
-Then, behind the scenes, it would put that JSON-compatible data (e.g. a `dict`) inside of a Starlette `JSONResponse` that would be used to send the response to the client.
+Then, behind the scenes, it would put that JSON-compatible data (e.g. a `dict`) inside of a `JSONResponse` that would be used to send the response to the client.
But you can return a `JSONResponse` directly from your *path operations*.
It might be useful, for example, to return custom headers or cookies.
-## Starlette `Response`
+## Return a `Response`
-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.
+In fact, you can return any `Response` or any sub-class of it.
!!! tip
`JSONResponse` itself is a sub-class of `Response`.
-And when you return a Starlette `Response`, **FastAPI** will pass it directly.
+And when you return a `Response`, **FastAPI** will pass it directly.
It won't do any data conversion with Pydantic models, it won't convert the contents to any type, etc.
{!./src/response_directly/tutorial001.py!}
```
-!!! note
- Notice that you import it directly from `starlette.responses`, not from `fastapi`.
+!!! note "Technical Details"
+ You could also use `from starlette.responses import JSONResponse`.
+
+ **FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette.
## Returning a custom `Response`
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/" 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" class="external-link" target="_blank">XML</a>.
+Let's say that you want to return an <a href="https://en.wikipedia.org/wiki/XML" class="external-link" target="_blank">XML</a> response.
-You could put your XML content in a string, put it in a Starlette Response, and return it:
+You could put your XML content in a string, put it in a `Response`, and return it:
-```Python hl_lines="2 20"
+```Python hl_lines="1 18"
{!./src/response_directly/tutorial002.py!}
```
And then you can set headers in that *temporal* response object.
-```Python hl_lines="2 8 9"
+```Python hl_lines="1 7 8"
{!./src/response_headers/tutorial002.py!}
```
{!./src/response_headers/tutorial001.py!}
```
+!!! note "Technical Details"
+ You could also use `from starlette.responses import Response` or `from starlette.responses import JSONResponse`.
+
+ **FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette.
+
+ And as the `Response` can be used frequently to set headers and cookies, **FastAPI** also provides it at `fastapi.Response`.
+
## Custom Headers
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>.
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"
+```Python hl_lines="1 11 12 13"
{!./src/security/tutorial007.py!}
```
After detecting that the credentials are incorrect, return an `HTTPException` with a status code 401 (the same returned when no credentials are provided) and add the header `WWW-Authenticate` to make the browser show the login prompt again:
-```Python hl_lines="16 17 18 19 20"
+```Python hl_lines="15 16 17 18 19"
{!./src/security/tutorial007.py!}
```
First, let's quickly see the parts that change from the examples in the main **Tutorial - User Guide** for [OAuth2 with Password (and hashing), Bearer with JWT tokens](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. Now using OAuth2 scopes:
-```Python hl_lines="2 5 9 13 48 66 107 109 110 111 112 113 114 115 116 117 123 124 125 126 130 131 132 133 134 135 136 141 155"
+```Python hl_lines="2 5 9 13 47 65 106 108 109 110 111 112 113 114 115 116 122 123 124 125 129 130 131 132 133 134 135 140 154"
{!./src/security/tutorial005.py!}
```
The `scopes` parameter receives a `dict` with each scope as a key and the description as the value:
-```Python hl_lines="64 65 66 67"
+```Python hl_lines="63 64 65 66"
{!./src/security/tutorial005.py!}
```
But in your application, for security, you should make sure you only add the scopes that the user is actually able to have, or the ones you have predefined.
-```Python hl_lines="156"
+```Python hl_lines="155"
{!./src/security/tutorial005.py!}
```
We are doing it here to demonstrate how **FastAPI** handles scopes declared at different levels.
-```Python hl_lines="5 141 168"
+```Python hl_lines="5 140 167"
{!./src/security/tutorial005.py!}
```
This `SecurityScopes` class is similar to `Request` (`Request` was used to get the request object directly).
-```Python hl_lines="9 107"
+```Python hl_lines="9 106"
{!./src/security/tutorial005.py!}
```
In this exception, we include the scopes required (if any) as a string separated by spaces (using `scope_str`). We put that string containing the scopes in in the `WWW-Authenticate` header (this is part of the spec).
-```Python hl_lines="107 109 110 111 112 113 114 115 116 117"
+```Python hl_lines="106 108 109 110 111 112 113 114 115 116"
{!./src/security/tutorial005.py!}
```
We also verify that we have a user with that username, and if not, we raise that same exception we created before.
-```Python hl_lines="48 118 119 120 121 122 123 124 125 126 127 128 129"
+```Python hl_lines="47 117 118 119 120 121 122 123 124 125 126 127 128"
{!./src/security/tutorial005.py!}
```
For this, we use `security_scopes.scopes`, that contains a `list` with all these scopes as `str`.
-```Python hl_lines="130 131 132 133 134 135 136"
+```Python hl_lines="129 130 131 132 133 134 135"
{!./src/security/tutorial005.py!}
```
A common election is Jinja2, the same one used by Flask and other tools.
-Starlette has utilities to configure it easily that you can use directly in your **FastAPI** application.
+There are utilities to configure it easily that you can use directly in your **FastAPI** application (provided by Starlette).
## Install dependencies
## Using `Jinja2Templates`
-* Import `Jinja2Templates` form Starlette.
+* Import `Jinja2Templates`.
* Create a `templates` object that you can re-use later.
* Declare a `Request` parameter in the *path operation* that will return a template.
* Use the `templates` you created to render and return a `TemplateResponse`, passing the `request` as one of the key-value pairs in the Jinja2 "context".
-```Python hl_lines="4 11 15 16"
+```Python hl_lines="3 10 14 15"
{!./src/templates/tutorial001.py!}
```
!!! note
Notice that you have to pass the `request` as part of the key-value pairs in the context for Jinja2. So, you also have to declare it in your *path operation*.
+!!! note "Technical Details"
+ You could also use `from starlette.templating import Jinja2Templates`.
+
+ **FastAPI** provides the same `starlette.templating` as `fastapi.templating` just as a convenience for you, the developer. But most of the available responses come directly from Starlette. The same with `Request` and `StaticFiles`.
+
## Writing templates
Then you can write a template at `templates/item.html` with:
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.
+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 documented (with OpenAPI, for the automatic API user interface) by FastAPI.
Although any other parameter declared normally (for example, the body with a Pydantic model) would still be validated, converted, annotated, etc.
For that you need to access the request directly.
-### Import the `Request`
-
-First, import the `Request` class from Starlette:
-
-```Python hl_lines="2"
+```Python hl_lines="1 7 8"
{!./src/using_request_directly/tutorial001.py!}
```
-### Declare the `Request` parameter
-
-Then declare a *path operation function* parameter with the type being the `Request` class:
-
-```Python hl_lines="8"
-{!./src/using_request_directly/tutorial001.py!}
-```
+By declaring a *path operation function* parameter with the type being the `Request` **FastAPI** will know to pass the `Request` in that parameter.
!!! tip
- Note that in this case, we are declaring a path parameter besides the request parameter.
+ Note that in this case, we are declaring a path parameter beside the request parameter.
So, the path parameter will be extracted, validated, converted to the specified type and annotated with OpenAPI.
## `Request` documentation
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>.
+
+!!! note "Technical Details"
+ You could also use `from starlette.requests import Request`.
+
+ **FastAPI** provides it directly just as a convenience for you, the developer. But it comes directly from Starlette.
But it's the simplest way to focus on the server-side of WebSockets and have a working example:
-```Python hl_lines="2 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 42 43 44"
+```Python hl_lines="2 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 41 42 43"
{!./src/websockets/tutorial001.py!}
```
In your **FastAPI** application, create a `websocket`:
-```Python hl_lines="3 47 48"
+```Python hl_lines="1 46 47"
{!./src/websockets/tutorial001.py!}
```
-!!! tip
- In this example we are importing `WebSocket` from `starlette.websockets` to use it in the type declaration in the WebSocket route function.
+!!! note "Technical Details"
+ You could also use `from starlette.websockets import WebSocket`.
+
+ **FastAPI** provides the same `WebSocket` directly just as a convenience for you, the developer. But it comes directly from Starlette.
## Await for messages and send messages
In your WebSocket route you can `await` for messages and send messages.
-```Python hl_lines="49 50 51 52 53"
+```Python hl_lines="48 49 50 51 52"
{!./src/websockets/tutorial001.py!}
```
They work the same way as for other FastAPI endpoints/*path operations*:
-```Python hl_lines="55 56 57 58 59 60 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78"
+```Python hl_lines="53 54 55 56 57 58 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76"
{!./src/websockets/tutorial002.py!}
```
To learn more about the options, check Starlette's documentation for:
-* <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>.
--- /dev/null
+You can mount WSGI applications as you saw with [Sub Applications - Behind a Proxy, Mounts](./sub-applications-proxy.md){.internal-link target=_blank}.
+
+For that, you can use the `WSGIMiddleware` and use it to wrap your WSGI application, for example, Flask, Django, etc.
+
+## Using `WSGIMiddleware`
+
+You need to import `WSGIMiddleware`.
+
+Then wrap the WSGI (e.g. Flask) app with the middleware.
+
+And then mount that under a path.
+
+```Python hl_lines="1 3 22"
+{!./src/wsgi/tutorial001.py!}
+```
+
+## Check it
+
+Now, every request under the path `/v1/` will be handled by the Flask application.
+
+And the rest will be handled by **FastAPI**.
+
+If you run it with Uvicorn and go to <a href="http://localhost:8000/v1/" class="external-link" target="_blank">http://localhost:8000/v1/</a> you will see the response from Flask:
+
+```txt
+Hello, World from Flask!
+```
+
+And if you go to <a href="http://localhost:8000/v2" class="external-link" target="_blank">http://localhost:8000/v2</a> you will see the response from FastAPI:
+
+```JSON
+{
+ "message": "Hello World"
+}
+```
from fastapi import FastAPI
+from fastapi.responses import JSONResponse
from pydantic import BaseModel
-from starlette.responses import JSONResponse
class Item(BaseModel):
from fastapi import FastAPI
+from fastapi.responses import FileResponse
from pydantic import BaseModel
-from starlette.responses import FileResponse
class Item(BaseModel):
from fastapi import FastAPI
+from fastapi.responses import JSONResponse
from pydantic import BaseModel
-from starlette.responses import JSONResponse
class Item(BaseModel):
from fastapi import FastAPI
+from fastapi.responses import FileResponse
from pydantic import BaseModel
-from starlette.responses import FileResponse
class Item(BaseModel):
-from fastapi import Body, FastAPI
-from starlette.responses import JSONResponse
-from starlette.status import HTTP_201_CREATED
+from fastapi import Body, FastAPI, status
+from fastapi.responses import JSONResponse
app = FastAPI()
else:
item = {"name": name, "size": size}
items[item_id] = item
- return JSONResponse(status_code=HTTP_201_CREATED, content=item)
+ return JSONResponse(status_code=status.HTTP_201_CREATED, content=item)
--- /dev/null
+from fastapi import FastAPI
+from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
+
+app = FastAPI()
+
+app.add_middleware(HTTPSRedirectMiddleware)
+
+
+@app.get("/")
+async def main():
+ return {"message": "Hello World"}
--- /dev/null
+from fastapi import FastAPI
+from fastapi.middleware.trustedhost import TrustedHostMiddleware
+
+app = FastAPI()
+
+app.add_middleware(
+ TrustedHostMiddleware, allowed_hosts=["example.com", "*.example.com"]
+)
+
+
+@app.get("/")
+async def main():
+ return {"message": "Hello World"}
--- /dev/null
+from fastapi import FastAPI
+from fastapi.middleware.gzip import GZipMiddleware
+
+app = FastAPI()
+
+app.add_middleware(GZipMiddleware, minimum_size=1000)
+
+
+@app.get("/")
+async def main():
+ return "somebigcontent"
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from .main import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from .main_b import app
from fastapi import FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI
-from starlette.testclient import TestClient
-from starlette.websockets import WebSocket
+from fastapi.testclient import TestClient
+from fastapi.websockets import WebSocket
app = FastAPI()
from fastapi import FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI
-from starlette.middleware.cors import CORSMiddleware
+from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
allow_methods=["*"],
allow_headers=["*"],
)
+
+
+@app.get("/")
+async def main():
+ return {"message": "Hello World"}
import gzip
from typing import Callable, List
-from fastapi import Body, FastAPI
+from fastapi import Body, FastAPI, Request, Response
from fastapi.routing import APIRoute
-from starlette.requests import Request
-from starlette.responses import Response
class GzipRequest(Request):
from typing import Callable, List
-from fastapi import Body, FastAPI, HTTPException
+from fastapi import Body, FastAPI, HTTPException, Request, Response
from fastapi.exceptions import RequestValidationError
from fastapi.routing import APIRoute
-from starlette.requests import Request
-from starlette.responses import Response
class ValidationErrorLoggingRoute(APIRoute):
import time
from typing import Callable
-from fastapi import APIRouter, FastAPI
+from fastapi import APIRouter, FastAPI, Request, Response
from fastapi.routing import APIRoute
-from starlette.requests import Request
-from starlette.responses import Response
class TimedRoute(APIRoute):
from fastapi import FastAPI
-from starlette.responses import UJSONResponse
+from fastapi.responses import UJSONResponse
app = FastAPI()
from fastapi import FastAPI
-from starlette.responses import HTMLResponse
+from fastapi.responses import HTMLResponse
app = FastAPI()
from fastapi import FastAPI
-from starlette.responses import HTMLResponse
+from fastapi.responses import HTMLResponse
app = FastAPI()
from fastapi import FastAPI
-from starlette.responses import HTMLResponse
+from fastapi.responses import HTMLResponse
app = FastAPI()
--- /dev/null
+from fastapi import FastAPI
+from fastapi.responses import PlainTextResponse
+
+app = FastAPI()
+
+
+@app.get("/", response_class=PlainTextResponse)
+async def main():
+ return "Hello World"
--- /dev/null
+from fastapi import FastAPI
+from fastapi.responses import RedirectResponse
+
+app = FastAPI()
+
+
+@app.get("/typer")
+async def read_typer():
+ return RedirectResponse("https://typer.tiangolo.com")
--- /dev/null
+from fastapi import FastAPI
+from fastapi.responses import StreamingResponse
+
+app = FastAPI()
+
+
+async def fake_video_streamer():
+ for i in range(10):
+ yield b"some fake video bytes"
+
+
+@app.get("/")
+async def main():
+ return StreamingResponse(fake_video_streamer())
--- /dev/null
+from fastapi import FastAPI
+from fastapi.responses import StreamingResponse
+
+some_file_path = "large-video-file.mp4"
+app = FastAPI()
+
+
+@app.get("/")
+def main():
+ file_like = open(some_file_path, mode="rb")
+ return StreamingResponse(file_like, media_type="video/mp4")
--- /dev/null
+from fastapi import FastAPI
+from fastapi.responses import FileResponse
+
+some_file_path = "large-video-file.mp4"
+app = FastAPI()
+
+
+@app.get("/")
+async def main():
+ return FileResponse(some_file_path)
from fastapi import Depends, FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
get_swagger_ui_html,
get_swagger_ui_oauth2_redirect_html,
)
-from starlette.staticfiles import StaticFiles
+from fastapi.staticfiles import StaticFiles
app = FastAPI(docs_url=None, redoc_url=None)
-from fastapi import FastAPI
-from starlette.requests import Request
-from starlette.responses import JSONResponse
+from fastapi import FastAPI, Request
+from fastapi.responses import JSONResponse
class UnicornException(Exception):
from fastapi import FastAPI, HTTPException
from fastapi.exceptions import RequestValidationError
+from fastapi.responses import PlainTextResponse
from starlette.exceptions import HTTPException as StarletteHTTPException
-from starlette.responses import PlainTextResponse
app = FastAPI()
-from fastapi import FastAPI
+from fastapi import FastAPI, Request, status
from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import RequestValidationError
+from fastapi.responses import JSONResponse
from pydantic import BaseModel
-from starlette import status
-from starlette.requests import Request
-from starlette.responses import JSONResponse
app = FastAPI()
import time
-from fastapi import FastAPI
-from starlette.requests import Request
+from fastapi import FastAPI, Request
app = FastAPI()
from fastapi import APIRouter, FastAPI
+from fastapi.responses import JSONResponse
from pydantic import BaseModel, HttpUrl
-from starlette.responses import JSONResponse
app = FastAPI()
from typing import Set
-from fastapi import FastAPI
+from fastapi import FastAPI, status
from pydantic import BaseModel
-from starlette.status import HTTP_201_CREATED
app = FastAPI()
tags: Set[str] = []
-@app.post("/items/", response_model=Item, status_code=HTTP_201_CREATED)
+@app.post("/items/", response_model=Item, status_code=status.HTTP_201_CREATED)
async def create_item(*, item: Item):
return item
from typing import List
from fastapi import FastAPI, File, UploadFile
-from starlette.responses import HTMLResponse
+from fastapi.responses import HTMLResponse
app = FastAPI()
-from fastapi import FastAPI
-from starlette.responses import Response
-from starlette.status import HTTP_201_CREATED
+from fastapi import FastAPI, Response, status
app = FastAPI()
def get_or_create_task(task_id: str, response: Response):
if task_id not in tasks:
tasks[task_id] = "This didn't exist before"
- response.status_code = HTTP_201_CREATED
+ response.status_code = status.HTTP_201_CREATED
return tasks[task_id]
from fastapi import FastAPI
-from starlette.responses import JSONResponse
+from fastapi.responses import JSONResponse
app = FastAPI()
-from fastapi import FastAPI
-from starlette.responses import Response
+from fastapi import FastAPI, Response
app = FastAPI()
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
+from fastapi.responses import JSONResponse
from pydantic import BaseModel
-from starlette.responses import JSONResponse
class Item(BaseModel):
-from fastapi import FastAPI
-from starlette.responses import Response
+from fastapi import FastAPI, Response
app = FastAPI()
from fastapi import FastAPI
-from starlette.responses import JSONResponse
+from fastapi.responses import JSONResponse
app = FastAPI()
-from fastapi import FastAPI
-from starlette.responses import Response
+from fastapi import FastAPI, Response
app = FastAPI()
-from fastapi import FastAPI
-from starlette.status import HTTP_201_CREATED
+from fastapi import FastAPI, status
app = FastAPI()
-@app.post("/items/", status_code=HTTP_201_CREATED)
+@app.post("/items/", status_code=status.HTTP_201_CREATED)
async def create_item(name: str):
return {"name": name}
-from fastapi import Depends, FastAPI, HTTPException
+from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel
-from starlette.status import HTTP_401_UNAUTHORIZED
fake_users_db = {
"johndoe": {
user = fake_decode_token(token)
if not user:
raise HTTPException(
- status_code=HTTP_401_UNAUTHORIZED,
+ status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)
from datetime import datetime, timedelta
import jwt
-from fastapi import Depends, FastAPI, HTTPException
+from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jwt import PyJWTError
from passlib.context import CryptContext
from pydantic import BaseModel
-from starlette.status import HTTP_401_UNAUTHORIZED
# to get a string like this run:
# openssl rand -hex 32
async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
- status_code=HTTP_401_UNAUTHORIZED,
+ status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
raise HTTPException(
- status_code=HTTP_401_UNAUTHORIZED,
+ status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
from typing import List
import jwt
-from fastapi import Depends, FastAPI, HTTPException, Security
+from fastapi import Depends, FastAPI, HTTPException, Security, status
from fastapi.security import (
OAuth2PasswordBearer,
OAuth2PasswordRequestForm,
from jwt import PyJWTError
from passlib.context import CryptContext
from pydantic import BaseModel, ValidationError
-from starlette.status import HTTP_401_UNAUTHORIZED
# to get a string like this run:
# openssl rand -hex 32
else:
authenticate_value = f"Bearer"
credentials_exception = HTTPException(
- status_code=HTTP_401_UNAUTHORIZED,
+ status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": authenticate_value},
)
for scope in security_scopes.scopes:
if scope not in token_data.scopes:
raise HTTPException(
- status_code=HTTP_401_UNAUTHORIZED,
+ status_code=status.HTTP_401_UNAUTHORIZED,
detail="Not enough permissions",
headers={"WWW-Authenticate": authenticate_value},
)
import secrets
-from fastapi import Depends, FastAPI, HTTPException
+from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
-from starlette.status import HTTP_401_UNAUTHORIZED
app = FastAPI()
correct_password = secrets.compare_digest(credentials.password, "swordfish")
if not (correct_username and correct_password):
raise HTTPException(
- status_code=HTTP_401_UNAUTHORIZED,
+ status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password",
headers={"WWW-Authenticate": "Basic"},
)
from typing import List
-from fastapi import Depends, FastAPI, HTTPException
+from fastapi import Depends, FastAPI, HTTPException, Request, Response
from sqlalchemy.orm import Session
-from starlette.requests import Request
-from starlette.responses import Response
from . import crud, models, schemas
from .database import SessionLocal, engine
from fastapi import FastAPI
-from starlette.staticfiles import StaticFiles
+from fastapi.staticfiles import StaticFiles
app = FastAPI()
-from fastapi import FastAPI
-from starlette.requests import Request
-from starlette.staticfiles import StaticFiles
-from starlette.templating import Jinja2Templates
+from fastapi import FastAPI, Request
+from fastapi.staticfiles import StaticFiles
+from fastapi.templating import Jinja2Templates
app = FastAPI()
-from fastapi import FastAPI
-from starlette.requests import Request
+from fastapi import FastAPI, Request
app = FastAPI()
-from fastapi import FastAPI
-from starlette.responses import HTMLResponse
-from starlette.websockets import WebSocket
+from fastapi import FastAPI, WebSocket
+from fastapi.responses import HTMLResponse
app = FastAPI()
-from fastapi import Cookie, Depends, FastAPI, Header
-from starlette.responses import HTMLResponse
-from starlette.status import WS_1008_POLICY_VIOLATION
-from starlette.websockets import WebSocket
+from fastapi import Cookie, Depends, FastAPI, Header, WebSocket, status
+from fastapi.responses import HTMLResponse
app = FastAPI()
websocket: WebSocket, session: str = Cookie(None), x_client: str = Header(None)
):
if session is None and x_client is None:
- await websocket.close(code=WS_1008_POLICY_VIOLATION)
+ await websocket.close(code=status.WS_1008_POLICY_VIOLATION)
return session or x_client
--- /dev/null
+from flask import Flask, escape, request
+from fastapi import FastAPI
+from fastapi.middleware.wsgi import WSGIMiddleware
+
+flask_app = Flask(__name__)
+
+
+@flask_app.route("/")
+def flask_main():
+ name = request.args.get("name", "World")
+ return f"Hello, {escape(name)} from Flask!"
+
+
+app = FastAPI()
+
+
+@app.get("/v2")
+def read_main():
+ return {"message": "Hello World"}
+
+
+app.mount("/v1", WSGIMiddleware(flask_app))
## Use `CORSMiddleware`
-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>.
+You can configure it in your **FastAPI** application using the `CORSMiddleware`.
-* Import it from Starlette.
+* Import `CORSMiddleware`.
* Create a list of allowed origins (as strings).
* Add it as a "middleware" to your **FastAPI** application.
* Specific HTTP methods (`POST`, `PUT`) or all of them with the wildcard `"*"`.
* Specific HTTP headers or all of them with the wildcard `"*"`.
-```Python hl_lines="2 6 7 8 9 10 11 13 14 15 16 17 18 19"
+```Python hl_lines="2 6 7 8 9 10 11 13 14 15 16 17 18 19"
{!./src/cors/tutorial001.py!}
```
-## More info
+The default parameters used by the `CORSMiddleware` implementation are restrictive by default, so you'll need to explicitly enable particular origins, methods, or headers, in order for browsers to be permitted to use them in a Cross-Domain context.
+
+The following arguments are supported:
+
+* `allow_origins` - A list of origins that should be permitted to make cross-origin requests. E.g. `['https://example.org', 'https://www.example.org']`. You can use `['*']` to allow any origin.
+* `allow_origin_regex` - A regex string to match against origins that should be permitted to make cross-origin requests. eg. `'https://.*\.example\.org'`.
+* `allow_methods` - A list of HTTP methods that should be allowed for cross-origin requests. Defaults to `['GET']`. You can use `['*']` to allow all standard methods.
+* `allow_headers` - A list of HTTP request headers that should be supported for cross-origin requests. Defaults to `[]`. You can use `['*']` to allow all headers. The `Accept`, `Accept-Language`, `Content-Language` and `Content-Type` headers are always allowed for CORS requests.
+* `allow_credentials` - Indicate that cookies should be supported for cross-origin requests. Defaults to `False`.
+* `expose_headers` - Indicate any response headers that should be made accessible to the browser. Defaults to `[]`.
+* `max_age` - Sets a maximum time in seconds for browsers to cache CORS responses. Defaults to `60`.
+
+The middleware responds to two particular types of HTTP request...
+
+### CORS preflight requests
+
+These are any `OPTIONS` request with `Origin` and `Access-Control-Request-Method` headers.
-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>.
+In this case the middleware will intercept the incoming request and respond with appropriate CORS headers, and either a `200` or `400` response for informational purposes.
+
+### Simple requests
+
+Any request with an `Origin` header. In this case the middleware will pass the request through as normal, but will include appropriate CORS headers on the response.
+
+## More info
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>.
+
+!!! note "Technical Details"
+ You could also use `from starlette.middleware.cors import CORSMiddleware`.
+
+ **FastAPI** provides several middlewares in `fastapi.middleware` just as a convenience for you, the developer. But most of the available middlewares come directly from Starlette.
You could add a custom exception handler with `@app.exception_handler()`:
-```Python hl_lines="6 7 8 14 15 16 17 18 24"
+```Python hl_lines="5 6 7 13 14 15 16 17 18 24"
{!./src/handling_errors/tutorial003.py!}
```
{"message": "Oops! yolo did something. There goes a rainbow..."}
```
+!!! note "Technical Details"
+ You could also use `from starlette.requests import Request` and `from starlette.responses import JSONResponse`.
+
+ **FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette. The same with `Request`.
+
## Override the default exception handlers
**FastAPI** has some default exception handlers.
For example, you could want to return a plain text response instead of JSON for these errors:
-```Python hl_lines="1 3 9 10 11 22"
+```Python hl_lines="3 4 9 10 11 22"
{!./src/handling_errors/tutorial004.py!}
```
+!!! note "Technical Details"
+ You could also use `from starlette.responses import PlainTextResponse`.
+
+ **FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette.
+
### Use the `RequestValidationError` body
The `RequestValidationError` contains the `body` it received with invalid data.
You could use it while developing your app to log the body and debug it, return it to the user, etc.
-```Python hl_lines="16"
+```Python hl_lines="14"
{!./src/handling_errors/tutorial005.py!}
```
But when you register an exception handler, you should register it for Starlette's `HTTPException`.
-This way, if any part of Starlette's internal code, or a Starlette extension or plug-in, raises an `HTTPException`, your handler will be able to catch and handle it.
+This way, if any part of Starlette's internal code, or a Starlette extension or plug-in, raises a Starlette `HTTPException`, your handler will be able to catch and handle it.
In this example, to be able to have both `HTTPException`s in the same code, Starlette's exceptions is renamed to `StarletteHTTPException`:
* It can do something to that **response** or run any needed code.
* Then it returns the **response**.
+!!! note "Technical Details"
+ If you have dependencies with `yield`, the exit code will run *after* the middleware.
+
+ If there were any background tasks (documented later), they will run *after* all the middleware.
+
## Create a middleware
To create a middleware you use the decorator `@app.middleware("http")` on top of a function.
* Then it returns the `response` generated by the corresponding *path operation*.
* You can then modify further the `response` before returning it.
-```Python hl_lines="9 10 12 15"
+```Python hl_lines="8 9 11 14"
{!./src/middleware/tutorial001.py!}
```
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 CORS configurations ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}) 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>.
+!!! note "Technical Details"
+ You could also use `from starlette.requests import Request`.
+
+ **FastAPI** provides it as a convenience for you, the developer. But it comes directly from Starlette.
+
### Before and after the `response`
You can add code to be run with the `request`, before any *path operation* receives it.
For example, you could add a custom header `X-Process-Time` containing the time in seconds that it took to process the request and generate a response:
-```Python hl_lines="11 13 14"
+```Python hl_lines="10 12 13"
{!./src/middleware/tutorial001.py!}
```
-## Starlette's Middleware
-
-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.
+## Other middlewares
-Including:
+You can later read more about other middlewares in the [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank}.
-* `CORSMiddleware` (described in the next section).
-* `GZipMiddleware`.
-* `SentryMiddleware`.
-* ...and others.
+You will read about how to handle <abbr title="Cross-Origin Resource Sharing">CORS</abbr> with a middleware in the next section.
You can pass directly the `int` code, like `404`.
-But if you don't remember what each number code is for, you can use the shortcut constants from `starlette`:
+But if you don't remember what each number code is for, you can use the shortcut constants in `status`:
-```Python hl_lines="5 18"
+```Python hl_lines="3 17"
{!./src/path_operation_configuration/tutorial001.py!}
```
That status code will be used in the response and will be added to the OpenAPI schema.
+!!! note "Technical Details"
+ You could also use `from starlette import status`.
+
+ **FastAPI** provides the same `starlette.status` as `fastapi.status` just as a convenience for you, the developer. But it comes directly from Starlette.
+
## Tags
You can add tags to your *path operation*, pass the parameter `tags` with a `list` of `str` (commonly just one `str`):
So, whenever Swagger UI supports multi-file uploads, or any other tools that supports OpenAPI, they will be compatible with **FastAPI**.
+!!! note "Technical Details"
+ You could also use `from starlette.responses import HTMLResponse`.
+
+ **FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette.
+
## Recap
Use `File` to declare files to be uploaded as input parameters (as form data).
But you don't have to memorize what each of these codes mean.
-You can use the convenience variables from `starlette.status`.
+You can use the convenience variables from `fastapi.status`.
-```Python hl_lines="2 7"
+```Python hl_lines="1 6"
{!./src/response_status_code/tutorial002.py!}
```
<img src="/img/tutorial/response-status-code/image02.png">
+!!! note "Technical Details"
+ You could also use `from starlette import status`.
+
+ **FastAPI** provides the same `starlette.status` as `fastapi.status` just as a convenience for you, the developer. But it comes directly from Starlette.
+
## Changing the default
Later, in the **Advanced User Guide**, you will see how to return a different status code than the default you are declaring here.
And another one to authenticate and return a user.
-```Python hl_lines="7 39 56 57 60 61 70 71 72 73 74 75 76"
+```Python hl_lines="7 48 55 56 59 60 69 70 71 72 73 74 75"
{!./src/security/tutorial004.py!}
```
Create a utility function to generate a new access token.
-```Python hl_lines="3 6 13 14 15 29 30 31 79 80 81 82 83 84 85 86 87"
+```Python hl_lines="3 6 12 13 14 28 29 30 78 79 80 81 82 83 84 85 86"
{!./src/security/tutorial004.py!}
```
If the token is invalid, return an HTTP error right away.
-```Python hl_lines="90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107"
+```Python hl_lines="89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106"
{!./src/security/tutorial004.py!}
```
Create a real JWT access token and return it.
-```Python hl_lines="116 117 118 119 120 121 122 123 124 125 126 127 128 129"
+```Python hl_lines="115 116 117 118 119 120 121 122 123 124 125 126 127 128"
{!./src/security/tutorial004.py!}
```
First, import `OAuth2PasswordRequestForm`, and use it as a dependency with `Depends` for the path `/token`:
-```Python hl_lines="2 75"
+```Python hl_lines="2 74"
{!./src/security/tutorial003.py!}
```
For the error, we use the exception `HTTPException`:
-```Python hl_lines="1 76 77 78"
+```Python hl_lines="1 75 76 77"
{!./src/security/tutorial003.py!}
```
So, the thief won't be able to try to use those same passwords in another system (as many users use the same password everywhere, this would be dangerous).
-```Python hl_lines="79 80 81 82"
+```Python hl_lines="78 79 80 81"
{!./src/security/tutorial003.py!}
```
But for now, let's focus on the specific details we need.
-```Python hl_lines="84"
+```Python hl_lines="83"
{!./src/security/tutorial003.py!}
```
So, in our endpoint, we will only get a user if the user exists, was correctly authenticated, and is active:
-```Python hl_lines="57 58 59 60 61 62 63 64 65 68 69 70 71 88"
+```Python hl_lines="56 57 58 59 60 61 62 63 64 65 67 68 69 70 88"
{!./src/security/tutorial003.py!}
```
The middleware we'll add (just a function) will create a new SQLAlchemy `SessionLocal` for each request, add it to the request and then close it once the request is finished.
-```Python hl_lines="16 17 18 19 20 21 22 23 24"
+```Python hl_lines="14 15 16 17 18 19 20 21 22"
{!./src/sql_databases/sql_app/alt_main.py!}
```
### About `request.state`
-<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.
+`request.state` is a property of each `Request` object. It is there to store arbitrary objects attached to the request itself, like the database session in this case. You can read more about it in <a href="https://www.starlette.io/requests/#other-state" class="external-link" target="_blank">Starlette's docs about `Request` state</a>.
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).
-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>.
+You can serve static files automatically from a directory using `StaticFiles`.
## Install `aiofiles`
## Use `StaticFiles`
-* Import `StaticFiles` from Starlette.
+* Import `StaticFiles`.
* "Mount" a `StaticFiles()` instance in a specific path.
```Python hl_lines="2 6"
{!./src/static_files/tutorial001.py!}
```
+!!! note "Technical Details"
+ You could also use `from starlette.staticfiles import StaticFiles`.
+
+ **FastAPI** provides the same `starlette.staticfiles` as `fastapi.staticfiles` just as a convenience for you, the developer. But it actually comes directly from Starlette.
+
### What is "Mounting"
"Mounting" means adding a complete "independent" application in a specific path, that then takes care of handling all the sub-paths.
-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.
+Thanks to <a href="https://www.starlette.io/testclient/" class="external-link" target="_blank">Starlette</a>, testing **FastAPI** applications is easy and enjoyable.
It is based on <a href="http://docs.python-requests.org" class="external-link" target="_blank">Requests</a>, so it's very familiar and intuitive.
## Using `TestClient`
-Import `TestClient` from `starlette.testclient`.
+Import `TestClient`.
Create a `TestClient` passing to it your **FastAPI**.
Write simple `assert` statements with the standard Python expressions that you need to check (again, standard `pytest`).
-```Python hl_lines="2 12 15 16 17 18"
+```Python hl_lines="2 12 15 16 17 18"
{!./src/app_testing/tutorial001.py!}
```
This allows you to use `pytest` directly without complications.
+!!! note "Technical Details"
+ You could also use `from starlette.testclient import TestClient`.
+
+ **FastAPI** provides the same `starlette.testclient` as `fastapi.testclient` just as a convenience for you, the developer. But it comes directly from Starlette.
+
## Separating tests
In a real application, you probably would have your tests in a different file.
__version__ = "0.50.0"
-from starlette.background import BackgroundTasks
+from starlette import status
from .applications import FastAPI
+from .background import BackgroundTasks
from .datastructures import UploadFile
from .exceptions import HTTPException
from .param_functions import (
Query,
Security,
)
+from .requests import Request
+from .responses import Response
from .routing import APIRouter
+from .websockets import WebSocket
--- /dev/null
+from starlette.background import BackgroundTasks # noqa
from typing import Any, Callable
from starlette.concurrency import iterate_in_threadpool # noqa
-from starlette.concurrency import run_in_threadpool
+from starlette.concurrency import run_in_threadpool # noqa
+from starlette.concurrency import run_until_first_complete # noqa
asynccontextmanager_error_message = """
FastAPI's contextmanager_in_threadpool require Python 3.7 or above,
--- /dev/null
+from starlette.middleware import Middleware
--- /dev/null
+from starlette.middleware.cors import CORSMiddleware # noqa
--- /dev/null
+from starlette.middleware.gzip import GZipMiddleware # noqa
--- /dev/null
+from starlette.middleware.httpsredirect import HTTPSRedirectMiddleware # noqa
--- /dev/null
+from starlette.middleware.trustedhost import TrustedHostMiddleware # noqa
--- /dev/null
+from starlette.middleware.wsgi import WSGIMiddleware # noqa
--- /dev/null
+from starlette.requests import Request # noqa
--- /dev/null
+from starlette.responses import FileResponse # noqa
+from starlette.responses import HTMLResponse # noqa
+from starlette.responses import JSONResponse # noqa
+from starlette.responses import PlainTextResponse # noqa
+from starlette.responses import RedirectResponse # noqa
+from starlette.responses import Response # noqa
+from starlette.responses import StreamingResponse # noqa
+from starlette.responses import UJSONResponse # noqa
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.responses import JSONResponse, Response
+from starlette.routing import Mount # noqa
from starlette.routing import (
compile_path,
get_name,
--- /dev/null
+from starlette.staticfiles import StaticFiles # noqa
--- /dev/null
+from starlette.templating import Jinja2Templates # noqa
--- /dev/null
+from starlette.testclient import TestClient # noqa
--- /dev/null
+from starlette.websockets import WebSocket # noqa
+from starlette.websockets import WebSocketDisconnect # noqa
- Sub-dependencies: 'tutorial/dependencies/sub-dependencies.md'
- Dependencies in path operation decorators: 'tutorial/dependencies/dependencies-in-path-operation-decorators.md'
- Dependencies with yield: 'tutorial/dependencies/dependencies-with-yield.md'
- - Security:
+ - Security:
- Security Intro: 'tutorial/security/index.md'
- First Steps: 'tutorial/security/first-steps.md'
- Get Current User: 'tutorial/security/get-current-user.md'
- Simple OAuth2 with Password and Bearer: 'tutorial/security/simple-oauth2.md'
- OAuth2 with Password (and hashing), Bearer with JWT tokens: 'tutorial/security/oauth2-jwt.md'
- - Middleware: 'tutorial/middleware.md'
- - CORS (Cross-Origin Resource Sharing): 'tutorial/cors.md'
+ - Middleware: 'tutorial/middleware.md'
+ - CORS (Cross-Origin Resource Sharing): 'tutorial/cors.md'
- SQL (Relational) Databases: 'tutorial/sql-databases.md'
- Bigger Applications - Multiple Files: 'tutorial/bigger-applications.md'
- Background Tasks: 'tutorial/background-tasks.md'
- Path Operation Advanced Configuration: 'advanced/path-operation-advanced-configuration.md'
- Additional Status Codes: 'advanced/additional-status-codes.md'
- Return a Response Directly: 'advanced/response-directly.md'
- - Custom Response Class: 'advanced/custom-response.md'
+ - Custom Response - HTML, Stream, File, others: 'advanced/custom-response.md'
- Additional Responses in OpenAPI: 'advanced/additional-responses.md'
- Response Cookies: 'advanced/response-cookies.md'
- Response Headers: 'advanced/response-headers.md'
- Response - Change Status Code: 'advanced/response-change-status-code.md'
- Advanced Dependencies: 'advanced/advanced-dependencies.md'
- Advanced Security:
- - Advanced Security - Intro: advanced/security/index.md
+ - Advanced Security - Intro: 'advanced/security/index.md'
- OAuth2 scopes: 'advanced/security/oauth2-scopes.md'
- HTTP Basic Auth: 'advanced/security/http-basic-auth.md'
- Using the Request Directly: 'advanced/using-request-directly.md'
+ - Advanced Middleware: 'advanced/middleware.md'
- SQL (Relational) Databases with Peewee: 'advanced/sql-databases-peewee.md'
- Async SQL (Relational) Databases: 'advanced/async-sql-databases.md'
- NoSQL (Distributed / Big Data) Databases: 'advanced/nosql-databases.md'
- - Sub Applications - Behind a Proxy: 'advanced/sub-applications-proxy.md'
+ - Sub Applications - Behind a Proxy, Mounts: 'advanced/sub-applications-proxy.md'
- Templates: 'advanced/templates.md'
- GraphQL: 'advanced/graphql.md'
- WebSockets: 'advanced/websockets.md'
- Testing Dependencies with Overrides: 'advanced/testing-dependencies.md'
- Extending OpenAPI: 'advanced/extending-openapi.md'
- OpenAPI Callbacks: 'advanced/openapi-callbacks.md'
+ - Including WSGI - Flask, Django, others: 'advanced/wsgi.md'
- Concurrency and async / await: 'async.md'
- Deployment: 'deployment.md'
- Project Generation - Template: 'project-generation.md'
- Benchmarks: 'benchmarks.md'
- Help FastAPI - Get Help: 'help-fastapi.md'
- Development - Contributing: 'contributing.md'
- - Release Notes: release-notes.md
+ - Release Notes: 'release-notes.md'
markdown_extensions:
- toc:
"async_generator",
"python-multipart",
"aiofiles",
- "ujson"
+ "ujson",
+ "flask"
]
doc = [
"mkdocs",
from typing import Dict
from fastapi import FastAPI
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import APIRouter, FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
router = APIRouter()
import pytest
from fastapi import FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
import typing
from fastapi import FastAPI
+from fastapi.responses import JSONResponse
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.responses import JSONResponse
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
import typing
from fastapi import FastAPI
+from fastapi.responses import JSONResponse
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.responses import JSONResponse
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import APIRouter, FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
router = APIRouter()
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from .main import app
from functools import partial
from fastapi import FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
def main(some_arg, q: str = None):
import pytest
from fastapi import APIRouter, FastAPI
from fastapi.routing import APIRoute
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
swagger_ui_oauth2_redirect_url = "/docs/redirect"
from datetime import datetime, timezone
from fastapi import FastAPI
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
class ModelWithDatetimeField(BaseModel):
import orjson
from fastapi import APIRouter, FastAPI
-from starlette.responses import HTMLResponse, JSONResponse, PlainTextResponse
-from starlette.testclient import TestClient
+from fastapi.responses import HTMLResponse, JSONResponse, PlainTextResponse
+from fastapi.testclient import TestClient
class ORJSONResponse(JSONResponse):
from fastapi import APIRouter, FastAPI
-from starlette.responses import HTMLResponse, JSONResponse, PlainTextResponse
-from starlette.testclient import TestClient
+from fastapi.responses import HTMLResponse, JSONResponse, PlainTextResponse
+from fastapi.testclient import TestClient
class OverrideResponse(JSONResponse):
from fastapi import Depends, FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
import pytest
from fastapi import Depends, FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
import pytest
from fastapi import BackgroundTasks, Depends, FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
state = {
import pytest
from fastapi import APIRouter, Depends, FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
import pytest
from fastapi import APIRouter, FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI
+from fastapi.responses import JSONResponse
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.responses import JSONResponse
-from starlette.testclient import TestClient
app = FastAPI()
import pytest
from fastapi import Depends, FastAPI
+from fastapi.testclient import TestClient
from pydantic import BaseModel, ValidationError, validator
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI, Form
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
-from fastapi import APIRouter, FastAPI
-from starlette.requests import Request
-from starlette.responses import JSONResponse
-from starlette.testclient import TestClient
+from fastapi import APIRouter, FastAPI, Request
+from fastapi.responses import JSONResponse
+from fastapi.testclient import TestClient
app = FastAPI()
router = APIRouter()
from fastapi import APIRouter, FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
import pytest
from fastapi import FastAPI
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
app = FastAPI()
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from .app.main import app
from typing import List
from fastapi import FastAPI
+from fastapi.testclient import TestClient
from pydantic import BaseModel, condecimal
-from starlette.testclient import TestClient
app = FastAPI()
from typing import List
from fastapi import FastAPI, Query
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI(swagger_ui_oauth2_redirect_url=None)
from fastapi import FastAPI
from fastapi.params import Param
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
from fastapi import Depends, FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from .main import app
from fastapi import FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from .main import app
-from fastapi import Depends, FastAPI, Header
-from starlette.status import HTTP_200_OK
-from starlette.testclient import TestClient
+from fastapi import Depends, FastAPI, Header, status
+from fastapi.testclient import TestClient
app = FastAPI()
def test_schema():
response = client.get("/openapi.json")
- assert response.status_code == HTTP_200_OK
+ assert response.status_code == status.HTTP_200_OK
actual_schema = response.json()
assert actual_schema == schema
assert (
def test_response():
response = client.get("/", headers={"someheader": "hello"})
- assert response.status_code == HTTP_200_OK
+ assert response.status_code == status.HTTP_200_OK
assert response.json() == {"dep1": "hello", "dep2": "hello123"}
import typing
from fastapi import Body, FastAPI
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
app = FastAPI()
-from fastapi import Depends, FastAPI
-from starlette.responses import Response
-from starlette.testclient import TestClient
+from fastapi import Depends, FastAPI, Response
+from fastapi.testclient import TestClient
app = FastAPI()
import typing
-from fastapi import FastAPI
+from fastapi import FastAPI, Response
+from fastapi.responses import JSONResponse
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.responses import JSONResponse, Response
-from starlette.testclient import TestClient
app = FastAPI()
import typing
from fastapi import FastAPI
+from fastapi.responses import JSONResponse
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.responses import JSONResponse
-from starlette.testclient import TestClient
app = FastAPI()
from typing import List
from fastapi import FastAPI
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
class Model(BaseModel):
from fastapi import APIRouter, FastAPI
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
class State(BaseModel):
from fastapi import APIRouter, FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
from fastapi import Depends, FastAPI, Security
from fastapi.security import APIKeyCookie
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import Depends, FastAPI, Security
from fastapi.security import APIKeyCookie
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import Depends, FastAPI, Security
from fastapi.security import APIKeyHeader
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import Depends, FastAPI, Security
from fastapi.security import APIKeyHeader
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import Depends, FastAPI, Security
from fastapi.security import APIKeyQuery
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import Depends, FastAPI, Security
from fastapi.security import APIKeyQuery
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI, Security
from fastapi.security.http import HTTPAuthorizationCredentials, HTTPBase
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI, Security
from fastapi.security.http import HTTPAuthorizationCredentials, HTTPBase
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI, Security
from fastapi.security import HTTPBasic, HTTPBasicCredentials
+from fastapi.testclient import TestClient
from requests.auth import HTTPBasicAuth
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI, Security
from fastapi.security import HTTPBasic, HTTPBasicCredentials
+from fastapi.testclient import TestClient
from requests.auth import HTTPBasicAuth
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI, Security
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI, Security
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI, Security
from fastapi.security import HTTPAuthorizationCredentials, HTTPDigest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI, Security
from fastapi.security import HTTPAuthorizationCredentials, HTTPDigest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
from fastapi import Depends, FastAPI, Security
from fastapi.security import OAuth2
from fastapi.security.oauth2 import OAuth2PasswordRequestFormStrict
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI, Security
from fastapi.security import OAuth2AuthorizationCodeBearer
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
from fastapi import Depends, FastAPI, Security
from fastapi.security import OAuth2
from fastapi.security.oauth2 import OAuth2PasswordRequestFormStrict
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI, Security
from fastapi.security import OAuth2PasswordBearer
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
from fastapi import Depends, FastAPI, Security
from fastapi.security.open_id_connect_url import OpenIdConnect
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import Depends, FastAPI, Security
from fastapi.security.open_id_connect_url import OpenIdConnect
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
app = FastAPI()
from typing import List
from fastapi import FastAPI
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
app = FastAPI()
from typing import List
from fastapi import FastAPI
+from fastapi.testclient import TestClient
from pydantic.dataclasses import dataclass
-from starlette.testclient import TestClient
app = FastAPI()
from typing import Optional
from fastapi import FastAPI
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI, HTTPException
+from fastapi.testclient import TestClient
from starlette.exceptions import HTTPException as StarletteHTTPException
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI, Path
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
app = FastAPI()
from fastapi import APIRouter, FastAPI
+from fastapi.responses import JSONResponse
+from fastapi.testclient import TestClient
from pydantic import BaseModel, HttpUrl
-from starlette.responses import JSONResponse
-from starlette.testclient import TestClient
app = FastAPI()
from fastapi import FastAPI
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
swagger_ui_init_oauth = {"clientId": "the-foo-clients", "appName": "The Predendapp"}
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from additional_responses.tutorial001 import app
import os
import shutil
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from additional_responses.tutorial002 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from additional_responses.tutorial003 import app
import os
import shutil
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from additional_responses.tutorial004 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from additional_status_codes.tutorial001 import app
--- /dev/null
+from fastapi.testclient import TestClient
+
+from advanced_middleware.tutorial001 import app
+
+
+def test_middleware():
+ client = TestClient(app, base_url="https://testserver")
+ response = client.get("/")
+ assert response.status_code == 200
+
+ client = TestClient(app)
+ response = client.get("/", allow_redirects=False)
+ assert response.status_code == 307
+ assert response.headers["location"] == "https://testserver/"
--- /dev/null
+from fastapi.testclient import TestClient
+
+from advanced_middleware.tutorial002 import app
+
+
+def test_middleware():
+ client = TestClient(app, base_url="http://example.com")
+ response = client.get("/")
+ assert response.status_code == 200
+ client = TestClient(app, base_url="http://subdomain.example.com")
+ response = client.get("/")
+ assert response.status_code == 200
+ client = TestClient(app, base_url="http://invalidhost")
+ response = client.get("/")
+ assert response.status_code == 400
--- /dev/null
+from fastapi.responses import PlainTextResponse
+from fastapi.testclient import TestClient
+
+from advanced_middleware.tutorial003 import app
+
+
+@app.get("/large")
+async def large():
+ return PlainTextResponse("x" * 4000, status_code=200)
+
+
+client = TestClient(app)
+
+
+def test_middleware():
+ response = client.get("/large", headers={"accept-encoding": "gzip"})
+ assert response.status_code == 200
+ assert response.text == "x" * 4000
+ assert response.headers["Content-Encoding"] == "gzip"
+ assert int(response.headers["Content-Length"]) < 4000
+ response = client.get("/")
+ assert response.status_code == 200
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from application_configuration.tutorial001 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from async_sql_databases.tutorial001 import app
import os
from pathlib import Path
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from background_tasks.tutorial001 import app
import os
from pathlib import Path
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from background_tasks.tutorial002 import app
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from bigger_applications.app.main import app
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from body.tutorial001 import app
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from body_fields.tutorial001 import app
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from body_multiple_params.tutorial001 import app
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from body_multiple_params.tutorial003 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from body_nested_models.tutorial009 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from body_updates.tutorial001 import app
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from cookie_params.tutorial001 import app
--- /dev/null
+from fastapi.testclient import TestClient
+
+from cors.tutorial001 import app
+
+
+def test_cors():
+ client = TestClient(app)
+ # Test pre-flight response
+ headers = {
+ "Origin": "https://localhost.tiangolo.com",
+ "Access-Control-Request-Method": "GET",
+ "Access-Control-Request-Headers": "X-Example",
+ }
+ response = client.options("/", headers=headers)
+ assert response.status_code == 200
+ assert response.text == "OK"
+ assert (
+ response.headers["access-control-allow-origin"]
+ == "https://localhost.tiangolo.com"
+ )
+ assert response.headers["access-control-allow-headers"] == "X-Example"
+
+ # Test standard response
+ headers = {"Origin": "https://localhost.tiangolo.com"}
+ response = client.get("/", headers=headers)
+ assert response.status_code == 200
+ assert response.json() == {"message": "Hello World"}
+ assert (
+ response.headers["access-control-allow-origin"]
+ == "https://localhost.tiangolo.com"
+ )
+
+ # Test non-CORS response
+ response = client.get("/")
+ assert response.status_code == 200
+ assert response.json() == {"message": "Hello World"}
+ assert "access-control-allow-origin" not in response.headers
import json
import pytest
-from starlette.requests import Request
-from starlette.testclient import TestClient
+from fastapi import Request
+from fastapi.testclient import TestClient
from custom_request_and_route.tutorial001 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from custom_request_and_route.tutorial002 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from custom_request_and_route.tutorial003 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from custom_response.tutorial001 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from custom_response.tutorial004 import app
--- /dev/null
+from fastapi.testclient import TestClient
+
+from custom_response.tutorial005 import app
+
+client = TestClient(app)
+
+openapi_schema = {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/": {
+ "get": {
+ "summary": "Main",
+ "operationId": "main__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"text/plain": {"schema": {"type": "string"}}},
+ }
+ },
+ }
+ }
+ },
+}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == openapi_schema
+
+
+def test_get():
+ response = client.get("/")
+ assert response.status_code == 200
+ assert response.text == "Hello World"
--- /dev/null
+from fastapi.testclient import TestClient
+
+from custom_response.tutorial006 import app
+
+client = TestClient(app)
+
+
+def test_get():
+ response = client.get("/typer", allow_redirects=False)
+ assert response.status_code == 307
+ assert response.headers["location"] == "https://typer.tiangolo.com"
--- /dev/null
+from fastapi.testclient import TestClient
+
+from custom_response.tutorial007 import app
+
+client = TestClient(app)
+
+
+def test_get():
+ fake_content = b"some fake video bytes"
+ response = client.get("/")
+ assert response.content == fake_content * 10
--- /dev/null
+from pathlib import Path
+
+from fastapi.testclient import TestClient
+
+from custom_response import tutorial008
+from custom_response.tutorial008 import app
+
+client = TestClient(app)
+
+
+def test_get(tmp_path: Path):
+ file_path: Path = tmp_path / "large-video-file.mp4"
+ tutorial008.some_file_path = str(file_path)
+ test_content = b"Fake video bytes"
+ file_path.write_bytes(test_content)
+ response = client.get("/")
+ assert response.content == test_content
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from dependencies.tutorial001 import app
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from dependencies.tutorial004 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from dependencies.tutorial006 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from events.tutorial001 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from events.tutorial002 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from extending_openapi.tutorial001 import app
from pathlib import Path
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
@pytest.fixture(scope="module")
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from extra_data_types.tutorial001 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from extra_models.tutorial003 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from extra_models.tutorial004 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from extra_models.tutorial005 import app
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from first_steps.tutorial001 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from handling_errors.tutorial001 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from handling_errors.tutorial002 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from handling_errors.tutorial003 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from handling_errors.tutorial004 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from handling_errors.tutorial005 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from handling_errors.tutorial006 import app
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from header_params.tutorial001 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from openapi_callbacks.tutorial001 import app, invoice_notification
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from path_operation_advanced_configuration.tutorial001 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from path_operation_advanced_configuration.tutorial002 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from path_operation_advanced_configuration.tutorial003 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from path_operation_advanced_configuration.tutorial004 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from path_operation_configuration.tutorial005 import app
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from path_operation_configuration.tutorial006 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from path_params.tutorial004 import app
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from path_params.tutorial005 import app
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from query_params.tutorial005 import app
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from query_params.tutorial006 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from query_params.tutorial007 import app
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from query_params_str_validations.tutorial010 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from query_params_str_validations.tutorial011 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from query_params_str_validations.tutorial012 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from query_params_str_validations.tutorial013 import app
import os
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from request_files.tutorial001 import app
import os
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from request_files.tutorial002 import app
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from request_forms.tutorial001 import app
import os
from pathlib import Path
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from request_forms_and_files.tutorial001 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from response_change_status_code.tutorial001 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from response_cookies.tutorial001 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from response_cookies.tutorial002 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from response_headers.tutorial001 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from response_headers.tutorial002 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from response_model.tutorial003 import app
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from response_model.tutorial004 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from response_model.tutorial005 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from response_model.tutorial006 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from security.tutorial001 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from security.tutorial003 import app
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from security.tutorial005 import (
app,
from base64 import b64encode
+from fastapi.testclient import TestClient
from requests.auth import HTTPBasicAuth
-from starlette.testclient import TestClient
from security.tutorial006 import app
from pathlib import Path
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
openapi_schema = {
"openapi": "3.0.2",
from pathlib import Path
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
openapi_schema = {
"openapi": "3.0.2",
from unittest.mock import MagicMock
import pytest
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from ...utils import skip_py36
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
from sub_applications.tutorial001 import app
import shutil
-from starlette.testclient import TestClient
+from fastapi.testclient import TestClient
def test_main():
import pytest
-from starlette.testclient import TestClient
-from starlette.websockets import WebSocketDisconnect
+from fastapi.testclient import TestClient
+from fastapi.websockets import WebSocketDisconnect
from websockets.tutorial001 import app
client = TestClient(app)
import pytest
-from starlette.testclient import TestClient
-from starlette.websockets import WebSocketDisconnect
+from fastapi.testclient import TestClient
+from fastapi.websockets import WebSocketDisconnect
from websockets.tutorial002 import app
client = TestClient(app)
--- /dev/null
+from fastapi.testclient import TestClient
+
+from wsgi.tutorial001 import app
+
+client = TestClient(app)
+
+
+def test_flask():
+ response = client.get("/v1/")
+ assert response.status_code == 200
+ assert response.text == "Hello, World from Flask!"
+
+
+def test_app():
+ response = client.get("/v2")
+ assert response.status_code == 200
+ assert response.json() == {"message": "Hello World"}
from typing import Optional, Union
from fastapi import FastAPI
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
app = FastAPI()
from typing import Optional, Union
from fastapi import FastAPI
+from fastapi.testclient import TestClient
from pydantic import BaseModel
-from starlette.testclient import TestClient
from .utils import skip_py36
import pytest
from fastapi import FastAPI
+from fastapi.testclient import TestClient
from pydantic import BaseModel, ValidationError
-from starlette.testclient import TestClient
app = FastAPI()
import pytest
from fastapi import FastAPI
+from fastapi.testclient import TestClient
from pydantic import ValidationError
from pydantic.dataclasses import dataclass
-from starlette.testclient import TestClient
app = FastAPI()
-from fastapi import APIRouter, FastAPI
-from starlette.testclient import TestClient
-from starlette.websockets import WebSocket
+from fastapi import APIRouter, FastAPI, WebSocket
+from fastapi.testclient import TestClient
router = APIRouter()
prefix_router = APIRouter()