diff --git a/docs/src/encoder/tutorial001.py b/docs/src/encoder/tutorial001.py
new file mode 100644
index 000000000..11984dd96
--- /dev/null
+++ b/docs/src/encoder/tutorial001.py
@@ -0,0 +1,22 @@
+from datetime import datetime
+
+from fastapi import FastAPI
+from fastapi.encoders import jsonable_encoder
+from pydantic import BaseModel
+
+fake_db = {}
+
+
+class Item(BaseModel):
+ title: str
+ timestamp: datetime
+ description: str = None
+
+
+app = FastAPI()
+
+
+@app.put("/items/{id}")
+def update_item(id: str, item: Item):
+ json_compatible_item_data = jsonable_encoder(item)
+ fake_db[id] = json_compatible_item_data
diff --git a/docs/src/response_directly/tutorial001.py b/docs/src/response_directly/tutorial001.py
new file mode 100644
index 000000000..92ae0ca37
--- /dev/null
+++ b/docs/src/response_directly/tutorial001.py
@@ -0,0 +1,21 @@
+from datetime import datetime
+
+from fastapi import FastAPI
+from fastapi.encoders import jsonable_encoder
+from pydantic import BaseModel
+from starlette.responses import JSONResponse
+
+
+class Item(BaseModel):
+ title: str
+ timestamp: datetime
+ description: str = None
+
+
+app = FastAPI()
+
+
+@app.put("/items/{id}")
+def update_item(id: str, item: Item):
+ json_compatible_item_data = jsonable_encoder(item)
+ return JSONResponse(content=json_compatible_item_data)
diff --git a/docs/src/response_directly/tutorial002.py b/docs/src/response_directly/tutorial002.py
new file mode 100644
index 000000000..fe961335e
--- /dev/null
+++ b/docs/src/response_directly/tutorial002.py
@@ -0,0 +1,20 @@
+from fastapi import FastAPI
+from starlette.responses import Response
+
+app = FastAPI()
+
+
+@app.get("/legacy/")
+def get_legacy_data():
+ data = """
+
+
+
+ Apply shampoo here.
+
+
+ You'll have to use soap here.
+
+
+ """
+ return Response(content=data, media_type="application/xml")
diff --git a/docs/tutorial/custom-response.md b/docs/tutorial/custom-response.md
index 0f0763992..600033f15 100644
--- a/docs/tutorial/custom-response.md
+++ b/docs/tutorial/custom-response.md
@@ -1,98 +1,88 @@
!!! 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`.
-But you can override it.
+You can override it by returning a `Response` directly, as seen in a previous section.
-## Use `UJSONResponse`
+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`).
-For example, if you are squeezing performance, you can use `ujson` and set the response to be Starlette's `UJSONResponse`.
+But you can also declare the `Response` that you want to be used, in the *path operation decorator*.
-### Import `UJSONResponse`
+The contents that you return from your *path operation function* will be put inside of that `Response`.
-```Python hl_lines="2"
-{!./src/custom_response/tutorial001.py!}
-```
+And if that `Response` has a JSON media type (`application/json`), like is the case with the `JSONResponse` and `UJSONResponse`, the data you return will be automatically converted (and filtered) with any Pydantic `response_model` that you declared in the *path operation decorator*.
-!!! note
- Notice that you import it directly from `starlette.responses`, not from `fastapi`.
+## Use `UJSONResponse`
-### Make your path operation use it
+For example, if you are squeezing performance, you can install and use `ujson` and set the response to be Starlette's `UJSONResponse`.
-Make your path operation use `UJSONResponse` as the response class using the parameter `content_type`:
+Import the `Response` class (sub-class) you want to use and declare it in the *path operation decorator*.
-```Python hl_lines="7"
+```Python hl_lines="2 7"
{!./src/custom_response/tutorial001.py!}
```
+!!! note
+ Notice that you import it directly from `starlette.responses`, not from `fastapi`.
+
!!! info
- The parameter is called `content_type` because it will also be used to define the "media type" of the response.
+ The parameter `response_class` will also be used to define the "media type" of the response.
- And will be documented as such in OpenAPI.
+ In this case, the HTTP header `Content-Type` will be set to `application/json`.
+
+ And it will be documented as such in OpenAPI.
## HTML Response
To return a response with HTML directly from **FastAPI**, use `HTMLResponse`.
-### Import `HTMLResponse`
+* Import `HTMLResponse`.
+* Pass `HTMLResponse` as the parameter `content_type` of your path operation.
-```Python hl_lines="2"
+```Python hl_lines="2 7"
{!./src/custom_response/tutorial002.py!}
```
!!! note
Notice that you import it directly from `starlette.responses`, not from `fastapi`.
-
-### Define your `content_type` class
-
-Pass `HTMLResponse` as the parameter `content_type` of your path operation:
-
-```Python hl_lines="7"
-{!./src/custom_response/tutorial002.py!}
-```
-
!!! info
- The parameter is called `content_type` because it will also be used to define the "media type" of the response.
+ The parameter `response_class` will also be used to define the "media type" of the response.
In this case, the HTTP header `Content-Type` will be set to `text/html`.
And it will be documented as such in OpenAPI.
-
### Return a Starlette `Response`
-You can also override the response directly in your path operation.
-
-If you return an object that is an instance of Starlette's `Response`, it will be used as the response directly.
+As seen in another section, you can also override the response directly in your path operation, by returning it.
The same example from above, returning an `HTMLResponse`, could look like:
-```Python hl_lines="7"
+```Python hl_lines="2 7 19"
{!./src/custom_response/tutorial003.py!}
```
-!!! info
- Of course, the `Content-Type` header will come from the the `Response` object your returned.
-
!!! warning
- A `Response` returned directly by your path operation function won't be documented in OpenAPI and won't be visible in the automatic interactive docs.
+ A `Response` returned directly by your path operation function won't be documented in OpenAPI (for example, the `Content-Type` won't be documented) and won't be visible in the automatic interactive docs.
+!!! info
+ Of course, the actual `Content-Type` header, status code, etc, will come from the `Response` object your returned.
### Document in OpenAPI and override `Response`
-If you want to override the response from inside of the function but at the same time document the "media type" in OpenAPI, you can use the `content_type` parameter AND return a `Response` object.
+If you want to override the response from inside of the function but at the same time document the "media type" in OpenAPI, you can use the `response_class` parameter AND return a `Response` object.
-The `content_type` class will then be used only to document the OpenAPI path operation, but your `Response` will be used as is.
+The `response_class` will then be used only to document the OpenAPI path operation, but your `Response` will be used as is.
#### Return an `HTMLResponse` directly
For example, it could be something like:
-```Python hl_lines="7 23"
+```Python hl_lines="7 23 21"
{!./src/custom_response/tutorial004.py!}
```
@@ -100,16 +90,10 @@ In this example, the function `generate_html_response()` already generates a Sta
By returning the result of calling `generate_html_response()`, you are already returning a `Response` that will override the default **FastAPI** behavior.
-#### Declare `HTMLResponse` as `content_type`
-
-But by declaring it also in the path operation decorator:
+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`:
-```Python hl_lines="21"
-{!./src/custom_response/tutorial004.py!}
-```
-
-#### OpenAPI knows how to document it
+
-...**FastAPI** will be able to document it in OpenAPI and in the interactive docs as HTML with `text/html`:
+## Additional documentation
-
+You can also declare the media type and many other details in OpenAPI using `responses`: Additional Responses in OpenAPI.
diff --git a/docs/tutorial/encoder.md b/docs/tutorial/encoder.md
new file mode 100644
index 000000000..41893194e
--- /dev/null
+++ b/docs/tutorial/encoder.md
@@ -0,0 +1,32 @@
+There are some cases where you might need to convert a data type (like a Pydantic model) to something compatible with JSON (like a `dict`, `list`, etc).
+
+For example, if you need to store it in a database.
+
+For that, **FastAPI** provides a `jsonable_encoder()` function.
+
+## Using the `jsonable_encoder`
+
+Let's imagine that you have a database `fake_db` that only receives JSON compatible data.
+
+For example, it doesn't receive `datetime` objects, as those are not compatible with JSON.
+
+So, a `datetime` object would have to be converted to a `str` containing the data in ISO format.
+
+The same way, this database wouldn't receive a Pydantic model (an object with attributes), only a `dict`.
+
+You can use `jsonable_encoder` for that.
+
+It receives an object, like a Pydantic model, and returns a JSON compatible version:
+
+```Python hl_lines="4 21"
+{!./src/encoder/tutorial001.py!}
+```
+
+In this example, it would convert the Pydantic model to a `dict`, and the `datetime` to a `str`.
+
+The result of calling it is something that can be encoded with the Python standard `json.dumps()`.
+
+It doesn't return a large `str` containing the data in JSON format (as a string). It returns a Python standard data structure (e.g. a `dict`) with values and sub-values that are all compatible with JSON.
+
+!!! note
+ `jsonable_encoder` is actually used by **FastAPI** internally to convert data. But it is useful in many other scenarios.
diff --git a/docs/tutorial/response-directly.md b/docs/tutorial/response-directly.md
new file mode 100644
index 000000000..f622cab85
--- /dev/null
+++ b/docs/tutorial/response-directly.md
@@ -0,0 +1,63 @@
+When you create a **FastAPI** *path operation* you can normally return any data from it: a `dict`, a `list`, a Pydantic model, a database model, etc.
+
+By default, **FastAPI** would automatically convert that return value to JSON using the `jsonable_encoder`.
+
+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.
+
+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`
+
+In fact, you can return any Starlette `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.
+
+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.
+
+## Using the `jsonable_encoder` in a `Response`
+
+Because **FastAPI** doesn't do any change to a `Response` you return, you have to make sure it's contents are ready for it.
+
+For example, you cannot put a Pydantic model in a `JSONResponse` without first converting it to a `dict` with all the data types (like `datetime`, `UUID`, etc) converted to JSON-compatible types.
+
+For those cases, you can use the `jsonable_encoder` to convert your data before passing it to a response:
+
+```Python hl_lines="4 6 20 21"
+{!./src/response_directly/tutorial001.py!}
+```
+
+!!! note
+ Notice that you import it directly from `starlette.responses`, not from `fastapi`.
+
+## Returning a custom `Response`
+
+The example above shows all the parts you need, but it's not very useful yet, as you could have just returned the `item` directly, and **FastAPI** would put it in a `JSONResponse` for you, converting it to a `dict`, etc. All that by default.
+
+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 Starlette `Response`s.
+
+Let's say that you want to return XML.
+
+You could put your XML content in a string, put it in a Starlette Response, and return it:
+
+```Python hl_lines="2 20"
+{!./src/response_directly/tutorial002.py!}
+```
+
+## Notes
+
+When you return a `Response` directly its data is not validated, converted (serialized), nor documented automatically.
+
+But you can still document it.
+
+In the next sections you will see how to use/declare these custom `Response`s while still having automatic data conversion, documentation, etc.
+
+You will also see how to use them to set response Headers and Cookies.
diff --git a/mkdocs.yml b/mkdocs.yml
index 2ea289d8e..b53936384 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -44,7 +44,9 @@ nav:
- Path Operation Configuration: 'tutorial/path-operation-configuration.md'
- Path Operation Advanced Configuration: 'tutorial/path-operation-advanced-configuration.md'
- Additional Status Codes: 'tutorial/additional-status-codes.md'
- - Custom Response: 'tutorial/custom-response.md'
+ - JSON compatible encoder: 'tutorial/encoder.md'
+ - Return a Response directly: 'tutorial/response-directly.md'
+ - Custom Response Class: 'tutorial/custom-response.md'
- Additional Responses in OpenAPI: 'tutorial/additional-responses.md'
- Dependencies:
- First Steps: 'tutorial/dependencies/first-steps.md'