# 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('
Hi 😎
') ``` ### 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()` - Set the body of the JSON object to the value passed - `resp.append()` - Append a value to the body like `list.append` (only works if the root JSON is an array) - `resp.extend()` - Extend a value to the body like `list.extend` (only works if the root JSON is an array) - `resp.update()` - 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*