@ -138,6 +138,14 @@ Takes some data and returns an `application/json` encoded response.
This is the default response used in **FastAPI**, as you read above.
/// note | Technical Details
But if you declare a response model or return type, that will be used directly to serialize the data to JSON, and a response with the right media type for JSON will be returned directly, without using the `JSONResponse` class.
This is the ideal way to get the best performance.
///
### `RedirectResponse` { #redirectresponse }
Returns an HTTP redirect. Uses a 307 status code (Temporary Redirect) by default.
@ -165,7 +173,7 @@ You can also use the `status_code` parameter combined with the `response_class`
### `StreamingResponse` { #streamingresponse }
Takes an async generator or a normal generator/iterator and streams the response body.
Takes an async generator or a normal generator/iterator (a function with `yield`) and streams the response body.
@ -179,27 +187,11 @@ This would be even more important with large or infinite streams.
///
#### Using `StreamingResponse` with file-like objects { #using-streamingresponse-with-file-like-objects }
If you have a <ahref="https://docs.python.org/3/glossary.html#term-file-like-object"class="external-link"target="_blank">file-like</a> object (e.g. the object returned by `open()`), you can create a generator function to iterate over that file-like object.
That way, you don't have to read it all first in memory, and you can pass that generator function to the `StreamingResponse`, and return it.
This includes many libraries to interact with cloud storage, video processing, and others.
1. This is the generator function. It's a "generator function" because it contains `yield` statements inside.
2. By using a `with` block, we make sure that the file-like object is closed after the generator function is done. So, after it finishes sending the response.
3. This `yield from` tells the function to iterate over that thing named `file_like`. And then, for each part iterated, yield that part as coming from this generator function (`iterfile`).
So, it is a generator function that transfers the "generating" work to something else internally.
By doing it this way, we can put it in a `with` block, and that way, ensure that the file-like object is closed after finishing.
/// 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`.
Instead of returning a `StreamingResponse` directly, you should probably follow the style in [Stream Data](./stream-data.md){.internal-link target=_blank}, it's much more convenient and handles cancellation behind the scenes for you.
If you are streaming JSON Lines, follow the [Stream JSON Lines](../tutorial/stream-json-lines.md){.internal-link target=_blank} tutorial.
@ -16,7 +16,7 @@ You will normally have much better performance using a [Response Model](../tutor
## Return a `Response` { #return-a-response }
You can return any`Response` or any sub-class of it.
You can return a `Response` or any sub-class of it.
/// info
@ -28,7 +28,9 @@ 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.
This gives you a lot of flexibility. You can return any data type, override any data declaration or validation, etc.
This gives you a lot of **flexibility**. You can return any data type, override any data declaration or validation, etc.
It also gives you a lot of **responsibility**. You have to make sure that the data you return is correct, in the correct format, that it can be serialized, etc.
## Using the `jsonable_encoder` in a `Response` { #using-the-jsonable-encoder-in-a-response }
@ -62,15 +64,15 @@ You could put your XML content in a string, put that in a `Response`, and return
## How a Response Model Works { #how-a-response-model-works }
When you declare a [Response Model](../tutorial/response-model.md){.internal-link target=_blank} in a path operation, **FastAPI** will use it to serialize the data to JSON, using Pydantic.
When you declare a [Response Model - Return Type](../tutorial/response-model.md){.internal-link target=_blank} in a path operation, **FastAPI** will use it to serialize the data to JSON, using Pydantic.
As that will happen on the Rust side, the performance will be much better than if it was done with regular Python and the `JSONResponse` class.
When using a response model FastAPI won't use the `jsonable_encoder` to convert the data (which would be slower) nor the `JSONResponse` class.
When using a `response_model` or return type, FastAPI won't use the `jsonable_encoder` to convert the data (which would be slower) nor the `JSONResponse` class.
Instead it takes the JSON bytes generated with Pydantic using the response model and returns a `Response` with the right media type for JSON directly (`application/json`).
Instead it takes the JSON bytes generated with Pydantic using the response model (or return type) and returns a `Response` with the right media type for JSON directly (`application/json`).
@ -72,6 +72,10 @@ Only so that it can live in the same file for this example and you can copy it a
///
By using a `with` block, we make sure that the file-like object is closed after the generator function (the function with `yield`) is done. So, after it finishes sending the response.
It wouldn't be that important in this specific example because it's a fake in-memory file (with `io.BytesIO`), but with a real file, it would be important to make sure the file is closed after the work with it is done.
### Files and Async { #files-and-async }
In most cases, file-like objects are not compatible with async and await by default.
@ -90,10 +94,18 @@ But in many cases reading a file or a file-like object would block.
To avoid blocking the event loop, you can simply declare the *path operation function* with regular `def` instead of `async def`, that way FastAPI will run it on a threadpool worker, to avoid blocking the main loop.
If you need to call blocking code from inside of an async function, or an async function from inside of a blocking function, you could use <ahref="https://asyncer.tiangolo.com"class="external-link"target="_blank">Asyncer</a>, a sibling library to FastAPI.
///
### `yield from` { #yield-from }
When you are iterating over something, like a file-like object, and then you are doing `yield` for each item, you could also use `yield from` to yield each item directly and skip the `for` loop.
This is not particular to FastAPI, it's just Python, but it's a nice trick to know. 😎