Response Return Styles
Robyn automatically converts your handler's return value into a proper HTTP response. Here's a complete reference of every supported return style.
String
The simplest return style. Returns the string as text/plain with status 200. The string is encoded as UTF-8 automatically.
Response
from robyn import Robyn
app = Robyn(__file__)
@app.get("/hello")
def hello():
return "Hello, World!"
Dictionary or List
Returning a dict or list automatically serializes the value to JSON and sets Content-Type: application/json with status 200.
Response
@app.get("/user")
def get_user():
return {"name": "Alice", "age": 30}
Response Object
The Response object gives you full control over status code, headers, and body. Use it when you need to customize everything about the response.
Response
from robyn import Robyn, Response, Headers
app = Robyn(__file__)
@app.get("/custom")
async def custom_response():
return Response(
status_code=200,
headers=Headers({"X-Custom": "value"}),
description="OK",
)
Bytes
Returning a bytes object sets Content-Type: application/octet-stream with status 200. Useful for binary data such as images or file content generated in memory.
Response
@app.get("/binary")
async def binary_data():
return b"binary data"
Pydantic BaseModel
If you return a Pydantic BaseModel instance, Robyn serializes it to JSON automatically with Content-Type: application/json and status 200.
Caveat: Pydantic must be installed as an optional dependency (pip install pydantic). If it is not installed, the model will not be detected and will fall through to the default string serialization.
Response
from pydantic import BaseModel
from robyn import Robyn
app = Robyn(__file__)
class User(BaseModel):
name: str
email: str
age: int
@app.get("/model")
def get_model():
return User(name="Alice", email="alice@example.com", age=30)
Tuple (body, headers, status_code)
A 3-element tuple of (body, headers, status_code) lets you set a custom status code and headers inline. The body element is itself formatted using the same rules (string, dict, bytes, etc.).
Caveat: The tuple must have exactly 3 elements. Passing a tuple with a different number of elements raises a ValueError.
Response
from robyn import Headers
@app.get("/not-found")
def not_found():
return (
{"error": "Resource not found"},
Headers({"X-Error": "true"}),
404,
)
FileResponse / serve_file / serve_html
Robyn provides helper functions for serving files. serve_file sets Content-Disposition: attachment and auto-detects the MIME type. serve_html sets Content-Type: text/html. You can also construct a FileResponse directly for full control.
Response
from robyn import Robyn
from robyn.responses import serve_file
app = Robyn(__file__)
@app.get("/download")
def download():
return serve_file("report.pdf")
html()
The html() helper wraps a raw HTML string into a Response with Content-Type: text/html and status 200. Useful for returning dynamically generated HTML without a template engine.
Response
from robyn import Robyn
from robyn.responses import html
app = Robyn(__file__)
@app.get("/page")
def page():
return html("<h1>Hello, World!</h1><p>Welcome to Robyn.</p>")
StreamingResponse
StreamingResponse sends chunked responses using a generator (sync or async). The default media_type is text/event-stream, but you can set it to any MIME type. The body is streamed chunk by chunk, so the client receives data as it is produced.
Response
from robyn import Robyn
from robyn.responses import StreamingResponse
app = Robyn(__file__)
@app.get("/stream")
def stream():
def generate():
for i in range(5):
yield f"chunk {i}\n"
return StreamingResponse(
content=generate(),
media_type="text/plain",
)
SSEResponse
SSEResponse is a convenience wrapper around StreamingResponse pre-configured for Server-Sent Events. Use it with the SSEMessage helper to format messages in the SSE protocol. Each message can have optional event, id, and retry fields.
For a deeper guide on Server-Sent Events, see the SSE documentation.
Response
from robyn import Robyn
from robyn.responses import SSEResponse, SSEMessage
import time
app = Robyn(__file__)
@app.get("/events")
def events():
def event_stream():
for i in range(10):
yield SSEMessage(
f"Event {i}",
event="update",
id=str(i),
)
time.sleep(1)
return SSEResponse(event_stream())
What's next?
Now that you know every way to return data from a Robyn handler, explore file uploads to learn how to receive files from clients.
