266 lines
6.5 KiB
Markdown
266 lines
6.5 KiB
Markdown
# Response
|
|
|
|
All [handlers](./handlers.md) *usually* return a response object, and [middleware](./middleware.md) may optionally return a response object.
|
|
|
|
To clarify that statement:
|
|
- unless the handler is a streaming endpoint handling its own pattern for sending bytes to the client, the return value must be an instance of `sanic.HTTPResponse` (to learn more about this exception see [streaming responses](../advanced/streaming.md#response-streaming))
|
|
- if a middleware returns a response object, that will be used instead of whatever the handler would do (see [middleware](./middleware.md) to learn more)
|
|
|
|
A most basic handler would look like the following. The `HTTPResponse` object will allow you to set the status, body, and headers to be returned to the client.
|
|
|
|
```python
|
|
from sanic import HTTPResponse, Sanic
|
|
|
|
app = Sanic("TestApp")
|
|
|
|
@app.route("")
|
|
def handler(_):
|
|
return HTTPResponse()
|
|
```
|
|
|
|
However, usually it is easier to use one of the convenience methods discussed below.
|
|
|
|
## Methods
|
|
|
|
The easiest way to generate a response object is to use one of the nine (9) convenience methods.
|
|
|
|
### Text
|
|
|
|
.. column::
|
|
|
|
**Default Content-Type**: `text/plain; charset=utf-8`
|
|
**Description**: Returns plain text
|
|
|
|
.. column::
|
|
|
|
```python
|
|
from sanic import text
|
|
|
|
@app.route("/")
|
|
async def handler(request):
|
|
return text("Hi 😎")
|
|
```
|
|
|
|
### HTML
|
|
|
|
.. column::
|
|
|
|
**Default Content-Type**: `text/html; charset=utf-8`
|
|
**Description**: Returns an HTML document
|
|
|
|
.. column::
|
|
|
|
```python
|
|
from sanic import html
|
|
|
|
@app.route("/")
|
|
async def handler(request):
|
|
return html('<!DOCTYPE html><html lang="en"><meta charset="UTF-8"><div>Hi 😎</div>')
|
|
```
|
|
|
|
### JSON
|
|
|
|
.. column::
|
|
|
|
**Default Content-Type**: `application/json`
|
|
**Description**: Returns a JSON document
|
|
|
|
.. column::
|
|
|
|
```python
|
|
from sanic import json
|
|
|
|
@app.route("/")
|
|
async def handler(request):
|
|
return json({"foo": "bar"})
|
|
```
|
|
|
|
By default, Sanic ships with [`ujson`](https://github.com/ultrajson/ultrajson) as its JSON encoder of choice. It is super simple to change this if you want.
|
|
|
|
```python
|
|
from orjson import dumps
|
|
|
|
json({"foo": "bar"}, dumps=dumps)
|
|
```
|
|
|
|
If `ujson` is not installed, it will fall back to the standard library `json` module.
|
|
|
|
You may additionally declare which implementation to use globally across your application at initialization:
|
|
|
|
```python
|
|
from orjson import dumps
|
|
|
|
app = Sanic(..., dumps=dumps)
|
|
```
|
|
|
|
### File
|
|
|
|
.. column::
|
|
|
|
**Default Content-Type**: N/A
|
|
**Description**: Returns a file
|
|
|
|
.. column::
|
|
|
|
```python
|
|
from sanic import file
|
|
|
|
@app.route("/")
|
|
async def handler(request):
|
|
return await file("/path/to/whatever.png")
|
|
```
|
|
|
|
Sanic will examine the file, and try and guess its mime type and use an appropriate value for the content type. You could be explicit, if you would like:
|
|
|
|
```python
|
|
file("/path/to/whatever.png", mime_type="image/png")
|
|
```
|
|
|
|
You can also choose to override the file name:
|
|
|
|
```python
|
|
file("/path/to/whatever.png", filename="super-awesome-incredible.png")
|
|
```
|
|
|
|
### File Streaming
|
|
|
|
.. column::
|
|
|
|
**Default Content-Type**: N/A
|
|
**Description**: Streams a file to a client, useful when streaming large files, like a video
|
|
|
|
.. column::
|
|
|
|
```python
|
|
from sanic.response import file_stream
|
|
|
|
@app.route("/")
|
|
async def handler(request):
|
|
return await file_stream("/path/to/whatever.mp4")
|
|
```
|
|
|
|
Like the `file()` method, `file_stream()` will attempt to determine the mime type of the file.
|
|
|
|
|
|
|
|
### Raw
|
|
|
|
.. column::
|
|
|
|
**Default Content-Type**: `application/octet-stream`
|
|
**Description**: Send raw bytes without encoding the body
|
|
|
|
.. column::
|
|
|
|
```python
|
|
from sanic import raw
|
|
|
|
@app.route("/")
|
|
async def handler(request):
|
|
return raw(b"raw bytes")
|
|
```
|
|
|
|
### Redirect
|
|
|
|
.. column::
|
|
|
|
**Default Content-Type**: `text/html; charset=utf-8`
|
|
**Description**: Send a `302` response to redirect the client to a different path
|
|
|
|
.. column::
|
|
|
|
```python
|
|
from sanic import redirect
|
|
|
|
@app.route("/")
|
|
async def handler(request):
|
|
return redirect("/login")
|
|
```
|
|
|
|
### Empty
|
|
|
|
.. column::
|
|
|
|
**Default Content-Type**: N/A
|
|
**Description**: For responding with an empty message as defined by [RFC 2616](https://tools.ietf.org/search/rfc2616#section-7.2.1)
|
|
|
|
.. column::
|
|
|
|
```python
|
|
from sanic import empty
|
|
|
|
@app.route("/")
|
|
async def handler(request):
|
|
return empty()
|
|
```
|
|
|
|
Defaults to a `204` status.
|
|
|
|
## Default status
|
|
|
|
The default HTTP status code for the response is `200`. If you need to change it, it can be done by the response method.
|
|
|
|
```python
|
|
@app.post("/")
|
|
async def create_new(request):
|
|
new_thing = await do_create(request)
|
|
return json({"created": True, "id": new_thing.thing_id}, status=201)
|
|
```
|
|
|
|
## Returning JSON data
|
|
|
|
Starting in v22.12, When you use the `sanic.json` convenience method, it will return a subclass of `HTTPResponse` called `JSONResponse`. This object will
|
|
have several convenient methods available to modify common JSON body.
|
|
|
|
```python
|
|
from sanic import json
|
|
|
|
resp = json(...)
|
|
```
|
|
|
|
- `resp.set_body(<raw_body>)` - Set the body of the JSON object to the value passed
|
|
- `resp.append(<value>)` - Append a value to the body like `list.append` (only works if the root JSON is an array)
|
|
- `resp.extend(<value>)` - Extend a value to the body like `list.extend` (only works if the root JSON is an array)
|
|
- `resp.update(<value>)` - Update the body with a value like `dict.update` (only works if the root JSON is an object)
|
|
- `resp.pop()` - Pop a value like `list.pop` or `dict.pop` (only works if the root JSON is an array or an object)
|
|
|
|
.. warning::
|
|
|
|
The raw Python object is stored on the `JSONResponse` object as `raw_body`. While it is safe to overwrite this value with a new one, you should **not** attempt to mutate it. You should instead use the methods listed above.
|
|
|
|
```python
|
|
resp = json({"foo": "bar"})
|
|
|
|
# This is OKAY
|
|
resp.raw_body = {"foo": "bar", "something": "else"}
|
|
|
|
# This is better
|
|
resp.set_body({"foo": "bar", "something": "else"})
|
|
|
|
# This is also works well
|
|
resp.update({"something": "else"})
|
|
|
|
# This is NOT OKAY
|
|
resp.raw_body.update({"something": "else"})
|
|
```
|
|
|
|
```python
|
|
# Or, even treat it like a list
|
|
resp = json(["foo", "bar"])
|
|
|
|
# This is OKAY
|
|
resp.raw_body = ["foo", "bar", "something", "else"]
|
|
|
|
# This is better
|
|
resp.extend(["something", "else"])
|
|
|
|
# This is also works well
|
|
resp.append("something")
|
|
resp.append("else")
|
|
|
|
# This is NOT OKAY
|
|
resp.raw_body.append("something")
|
|
```
|
|
|
|
*Added in v22.9*
|