Responses
Starlette includes a few response classes that handle sending back the
appropriate ASGI messages on the send channel.
Response
Signature: Response(content, status_code=200, headers=None, media_type=None)
content- A string or bytestring.status_code- An integer HTTP status code.headers- A dictionary of strings.media_type- A string giving the media type. eg. "text/html"
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, unless a charset has already been specified in the media_type.
Once you've instantiated a response, you can send it by calling it as an ASGI application instance.
from starlette.responses import Response
async def app(scope, receive, send):
assert scope['type'] == 'http'
response = Response('Hello, world!', media_type='text/plain')
await response(scope, receive, send)
Set Cookie
Starlette provides a set_cookie method to allow you to set cookies on the response object.
Signature: Response.set_cookie(key, value, max_age=None, expires=None, path="/", domain=None, secure=False, httponly=False, samesite="lax", partitioned=False)
key- A string that will be the cookie's key.value- A string that will be the cookie's value.max_age- An integer that defines the lifetime of the cookie in seconds. A negative integer or a value of0will discard the cookie immediately.Optionalexpires- Either an integer that defines the number of seconds until the cookie expires, or a datetime.Optionalpath- A string that specifies the subset of routes to which the cookie will apply.Optionaldomain- A string that specifies the domain for which the cookie is valid.Optionalsecure- A bool indicating that the cookie will only be sent to the server if request is made using SSL and the HTTPS protocol.Optionalhttponly- A bool indicating that the cookie cannot be accessed via JavaScript throughDocument.cookieproperty, theXMLHttpRequestorRequestAPIs.Optionalsamesite- A string that specifies the samesite strategy for the cookie. Valid values are'lax','strict'and'none'. Defaults to'lax'.Optionalpartitioned- A bool that indicates to user agents that these cross-site cookies should only be available in the same top-level context that the cookie was first set in. Only available for Python 3.14+, otherwise an error will be raised.Optional
Delete Cookie
Conversely, Starlette also provides a delete_cookie method to manually expire a set cookie.
Signature: Response.delete_cookie(key, path='/', domain=None, secure=False, httponly=False, samesite="lax", partitioned=False)
To delete a partitioned cookie on Python 3.14+:
from starlette.responses import Response
response = Response()
response.delete_cookie("session", secure=True, samesite="none", partitioned=True)
Pass partitioned=True to expire the cookie in the current partition. It defaults to False.
Use the same path and domain as the original cookie, within the same top-level site context.
For cross-site requests, use samesite="none".
Partitioned cookies require Secure
Pass secure=True when deleting a partitioned cookie over HTTPS.
Browsers reject the expiration header if it includes Partitioned without Secure.
HTMLResponse
Takes some text or bytes and returns an HTML response.
from starlette.responses import HTMLResponse
async def app(scope, receive, send):
assert scope['type'] == 'http'
response = HTMLResponse('<html><body><h1>Hello, world!</h1></body></html>')
await response(scope, receive, send)
PlainTextResponse
Takes some text or bytes and returns a plain text response.
from starlette.responses import PlainTextResponse
async def app(scope, receive, send):
assert scope['type'] == 'http'
response = PlainTextResponse('Hello, world!')
await response(scope, receive, send)
JSONResponse
Takes some data and returns an application/json encoded response.
from starlette.responses import JSONResponse
async def app(scope, receive, send):
assert scope['type'] == 'http'
response = JSONResponse({'hello': 'world'})
await response(scope, receive, send)
Custom JSON serialization
If you need fine-grained control over JSON serialization, you can subclass
JSONResponse and override the render method.
For example, if you wanted to use a third-party JSON library such as orjson:
from typing import Any
import orjson
from starlette.responses import JSONResponse
class OrjsonResponse(JSONResponse):
def render(self, content: Any) -> bytes:
return orjson.dumps(content)
In general you probably want to stick with JSONResponse by default unless
you are micro-optimising a particular endpoint or need to serialize non-standard
object types.
RedirectResponse
Returns an HTTP redirect. Uses a 307 status code by default.
from starlette.responses import PlainTextResponse, RedirectResponse
async def app(scope, receive, send):
assert scope['type'] == 'http'
if scope['path'] != '/':
response = RedirectResponse(url='/')
else:
response = PlainTextResponse('Hello, world!')
await response(scope, receive, send)
StreamingResponse
Takes an async generator or a normal generator/iterator and streams the response body.
from starlette.responses import StreamingResponse
import asyncio
async def slow_numbers(minimum, maximum):
yield '<html><body><ul>'
for number in range(minimum, maximum + 1):
yield '<li>%d</li>' % number
await asyncio.sleep(0.5)
yield '</ul></body></html>'
async def app(scope, receive, send):
assert scope['type'] == 'http'
generator = slow_numbers(1, 10)
response = StreamingResponse(generator, media_type='text/html')
await response(scope, receive, send)
Have in mind that file-like objects (like those created by open()) are normal iterators. So, you can return them directly in a StreamingResponse.
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 responseContent-Disposition.content_disposition_type- will be included in the responseContent-Disposition. Can be set to "attachment" (default) or "inline".
File responses will include appropriate Content-Length, Last-Modified and ETag headers.
from starlette.responses import FileResponse
async def app(scope, receive, send):
assert scope['type'] == 'http'
response = FileResponse('statics/favicon.ico')
await response(scope, receive, send)
File responses also supports HTTP range requests.
The Accept-Ranges: bytes header will be included in the response if the file exists. For now, only the bytes
range unit is supported.
If the request includes a Range header, and the file exists, the response will be a 206 Partial Content response
with the requested range of bytes. If the range is invalid, the response will be a 416 Range Not Satisfiable response.
Third party responses
EventSourceResponse
A response class that implements Server-Sent Events. It enables event streaming from the server to the client without the complexity of websockets.