Response
This page shows how to use vix::Response in Vix Core.
Use it when you want to send text, JSON, files, redirects, templates, headers, status codes, or empty responses from route handlers.
Public header
#include <vix.hpp>You can also include the response headers directly:
#include <vix/http/Response.hpp>
#include <vix/http/ResponseWrapper.hpp>
#include <vix/http/Status.hpp>What Response provides
vix::Response is the public response helper used in route handlers.
It lets you build HTTP responses with:
- status codes
- plain text
- JSON
- redirects
- static files
- templates
- headers
- content types
- empty responses
- default HTTP status messages
Most handlers receive a response by reference.
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.text("Hello from Vix");
});Basic response
#include <vix.hpp>
int main()
{
vix::App app;
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.text("Home");
});
app.run(8080);
return 0;
}Run:
vix run main.cppExpected response:
HomeSend text
Use text(...) to send plain text.
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.text("Hello from Vix");
});The response content type is set to text when needed.
Send JSON
Use json(...) to send JSON.
app.get("/api/status", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.json({
{"status", "ok"},
{"server", "Vix.cpp"}
});
});Example response:
{
"status": "ok",
"server": "Vix.cpp"
}Set status code
Use status(...) before sending the response body.
app.post("/users", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.status(201).json({
{"created", true}
});
});Example response:
{
"created": true
}Send an error response
app.get("/admin", [](vix::Request &req, vix::Response &res)
{
(void)req;
const bool allowed = false;
if (!allowed)
{
res.status(403).json({
{"error", "forbidden"}
});
return;
}
res.text("admin");
});Send an empty response
Use send() for an empty response.
app.get("/empty", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.status(204).send();
});A 204 No Content response should not contain a body.
Send a status response
Use sendStatus(...) when you want to send a response based on an HTTP status code.
app.get("/missing", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.sendStatus(404);
});For no-content statuses such as 204, Vix sends an empty response.
For other statuses, Vix can send a default status message.
Redirect
Use redirect(...) to send a redirect.
app.get("/old", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.redirect("/new");
});By default, this sends a redirect response.
You can also pass a status code.
app.get("/old", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.redirect(301, "/new");
});Set headers
Use header(...) to set a response header.
app.get("/custom", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.header("X-App", "Vix.cpp");
res.text("custom header");
});Append header values
Use append(...) to append a value to an existing header.
app.get("/cache", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.header("Cache-Control", "public");
res.append("Cache-Control", "max-age=3600");
res.text("cached");
});Result shape:
Cache-Control: public, max-age=3600Set content type
Use type(...) to set Content-Type.
app.get("/plain", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.type("text/plain; charset=utf-8");
res.send("plain text");
});contentType(...) is an alias.
res.contentType("application/json; charset=utf-8");Send a file
Use file(...) to send a file.
app.get("/download", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.file("public/file.txt");
});Vix detects common MIME types from file extensions.
Examples:
.html -> text/html; charset=utf-8
.css -> text/css; charset=utf-8
.js -> application/javascript
.json -> application/json; charset=utf-8
.png -> image/png
.jpg -> image/jpeg
.svg -> image/svg+xmlFile safety
res.file(...) performs basic path safety checks.
If the path contains .., Vix returns a bad request response.
res.file("../secret.txt");This protects against simple path traversal mistakes.
Send static HTML
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.file("public/index.html");
});Render a template
First configure templates on the app.
app.templates("views");Then render from a handler.
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
vix::tmpl::Context ctx;
ctx.set("title", "Home");
res.render("index.html", ctx);
});If templates were not configured, render(...) throws.
Send custom HTML
app.get("/html", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.type("text/html; charset=utf-8");
res.send("<h1>Hello from Vix</h1>");
});Send raw string
Use send(...) when you want the response helper to send a value.
app.get("/hello", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.send("Hello");
});For plain text, prefer:
res.text("Hello");JSON with status
app.post("/users", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.status(201).json({
{"id", 42},
{"created", true}
});
});Error JSON helper pattern
A common pattern is to return errors as JSON.
app.get("/private", [](vix::Request &req, vix::Response &res)
{
if (!req.has_header("Authorization"))
{
res.status(401).json({
{"error", "unauthorized"}
});
return;
}
res.json({
{"ok", true}
});
});Response chaining
Most response helper methods return the response wrapper.
This allows chaining.
res.status(201).json({
{"created", true}
});Another example:
res.status(403)
.header("X-Reason", "auth")
.json({{"error", "forbidden"}});Access the native response
vix::Response is an alias for vix::http::ResponseWrapper.
The wrapper stores the native response as:
res.resAdvanced code can access it directly.
res.res.set_status(200);
res.res.set_header("X-App", "Vix");
res.res.set_body("hello");Most application code should prefer the wrapper methods.
res.status(200).text("hello");Native response object
The lower-level native response object is vix::http::Response.
It stores:
- status code
- body
- headers
- reason phrase
- HTTP version
- close flag
It can serialize itself as HTTP text.
vix::http::Response raw;
raw.set_status(200);
raw.set_header("Content-Type", "text/plain; charset=utf-8");
raw.set_body("OK");
const std::string wire = raw.to_http_string();Most applications use vix::Response, not vix::http::Response directly.
Common headers
Core automatically applies common response headers when needed.
Examples:
Server: Vix.cpp
Date: <http date>
Content-Length: <body size>
Connection: keep-aliveThe session may also adjust connection behavior depending on the request and response.
Connection close
Use the native response when you need to control connection closing.
res.res.set_should_close(true);
res.header("Connection", "close");Most application handlers do not need this.
Status constants
Vix provides HTTP status constants.
vix::http::OK
vix::http::CREATED
vix::http::NO_CONTENT
vix::http::BAD_REQUEST
vix::http::UNAUTHORIZED
vix::http::FORBIDDEN
vix::http::NOT_FOUND
vix::http::INTERNAL_ERRORExample:
app.get("/status", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.status(vix::http::OK).json({
{"status", "ok"}
});
});Validate status codes
The lower-level status API can validate status codes.
vix::http::is_valid_status(200);
vix::http::is_valid_status(999);A valid HTTP status code is in the range:
100..599Invalid status codes are normalized to 500 by the lower-level helpers.
Reason phrases
Use reason_phrase(...) to read a standard reason phrase.
auto phrase = vix::http::reason_phrase(404);Result:
Not FoundResponse lifecycle
A response is created for each request.
Session
-> create Response
-> Router
-> RequestHandler
-> user handler writes response
-> response is finalized
-> Session serializes response
-> Transport writes bytesApplication code usually writes the response here:
app.get("/path", [](vix::Request &req, vix::Response &res)
{
res.text("OK");
});Response and handlers
Handlers should write exactly one response.
Recommended:
app.get("/ok", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.json({{"ok", true}});
});When sending an error early, return immediately.
if (!allowed)
{
res.status(403).json({{"error", "forbidden"}});
return;
}Response and middleware
Middleware can set response headers before the handler runs.
app.use([](vix::Request &req, vix::Response &res, vix::App::Next next)
{
(void)req;
res.header("X-Powered-By", "Vix.cpp");
next();
});Middleware can also stop the request early.
app.use("/admin", [](vix::Request &req, vix::Response &res, vix::App::Next next)
{
if (!req.has_header("Authorization"))
{
res.status(401).json({{"error", "unauthorized"}});
return;
}
next();
});Response and templates
res.render(...) uses the template view configured on the app.
app.templates("views");
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
vix::tmpl::Context ctx;
ctx.set("title", "Home");
res.render("index.html", ctx);
});Response and static files
Use res.file(...) for one file.
app.get("/logo", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.file("public/logo.svg");
});Use app.static_dir(...) when you want to expose a whole directory.
app.static_dir("public", "/assets");Complete example
#include <vix.hpp>
int main()
{
vix::App app;
app.get("/", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.text("Home");
});
app.get("/api/status", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.json({
{"status", "ok"},
{"server", "Vix.cpp"}
});
});
app.post("/api/users", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.status(201).json({
{"created", true}
});
});
app.get("/old", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.redirect("/new");
});
app.get("/download", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.file("public/file.txt");
});
app.get("/empty", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.status(204).send();
});
app.run(8080);
return 0;
}API summary
| API | Purpose |
|---|---|
res.status(code) | Set the HTTP status code. |
res.set_status(code) | Alias for status(code). |
res.status_c<Code>() | Set a compile-time status code. |
res.send() | Send an empty or current response. |
res.send(value) | Send a value. |
res.sendStatus(code) | Send a status response. |
res.text(data) | Send plain text. |
res.json(value) | Send JSON. |
res.redirect(url) | Send a redirect. |
res.redirect(code, url) | Send a redirect with a status code. |
res.file(path) | Send a file. |
res.render(name, context) | Render a template. |
res.header(name, value) | Set a header. |
res.set(name, value) | Alias for header(name, value). |
res.append(name, value) | Append a header value. |
res.type(mime) | Set Content-Type. |
res.contentType(mime) | Alias for type(mime). |
res.has_header(name) | Check whether a header is set. |
res.has_body() | Check whether the response body is non-empty. |
Native response API summary
| API | Purpose |
|---|---|
status() | Return the status code. |
set_status(code) | Set the status code. |
body() | Return the body. |
set_body(body) | Replace the body. |
headers() | Return response headers. |
set_header(name, value) | Set one header. |
remove_header(name) | Remove one header. |
clear_headers() | Remove all headers. |
should_close() | Return whether the connection should close. |
set_should_close(value) | Set close behavior. |
reason() | Return custom reason phrase. |
set_reason(reason) | Set custom reason phrase. |
version() | Return HTTP version. |
set_version(version) | Set HTTP version. |
to_http_string() | Serialize the response to HTTP text. |
Best practices
Send one clear response per handler.
res.json({{"ok", true}});Return immediately after sending an error.
if (!allowed)
{
res.status(403).json({{"error", "forbidden"}});
return;
}Use json(...) for API responses.
res.json({{"status", "ok"}});Use text(...) for simple plain text.
res.text("OK");Use status(...) before the body.
res.status(201).json({{"created", true}});Use static_dir(...) for directories and file(...) for single files.
app.static_dir("public", "/assets");
res.file("public/file.txt");Use render(...) only after configuring templates.
app.templates("views");Next steps
Read the next pages: