ctx.request Exposes Method, URL, Headers, and Content Negotiation
The Request Object
ctx.request wraps Node's IncomingMessage with convenient getters for method, path, query, headers, IP address, and content-negotiation helpers.
What you'll learn
- Access method, url, path, query, and headers from ctx.request
- Retrieve the client IP address safely with ctx.request.ip
- Use ctx.request.is() and ctx.request.accepts() for content negotiation
ctx.request is Koa’s enriched wrapper around Node’s raw IncomingMessage.
Most of its properties are also available as direct aliases on ctx (e.g.,
ctx.method === ctx.request.method), but accessing them through ctx.request
makes the intent explicit.
Method, URL, and Path
app.use(async (ctx) => {
console.log(ctx.request.method); // "GET", "POST", etc.
console.log(ctx.request.url); // "/items?page=2"
console.log(ctx.request.path); // "/items"
console.log(ctx.request.querystring); // "page=2"
}); Query String
ctx.request.query parses the query string into a plain object for you. It is
always an object, even when there is no query string (returns {}):
// GET /search?q=koa&limit=10
app.use(async (ctx) => {
const { q, limit } = ctx.request.query;
ctx.body = `Searching for "${q}", limit ${limit}`;
}); Headers
app.use(async (ctx) => {
const auth = ctx.request.get("Authorization");
const ua = ctx.request.headers["user-agent"];
ctx.body = { auth, ua };
}); ctx.request.get(field) is a case-insensitive header getter. You can also
read ctx.request.headers directly for the full headers object.
Client IP Address
app.use(async (ctx) => {
ctx.body = `Your IP: ${ctx.request.ip}`;
}); When app.proxy = true, Koa reads X-Forwarded-For to resolve the real
client IP. Without it, ctx.request.ip falls back to the socket’s remote
address.
Content Negotiation
ctx.request.is() checks the Content-Type of the incoming request:
app.use(async (ctx, next) => {
if (!ctx.request.is("application/json")) {
ctx.throw(415, "JSON required");
}
await next();
}); ctx.request.accepts() inspects the Accept header to determine what the
client can receive:
app.use(async (ctx) => {
if (ctx.request.accepts("json")) {
ctx.type = "json";
ctx.body = { hello: "world" };
} else {
ctx.type = "text";
ctx.body = "hello world";
}
}); Up Next
Learn how to shape responses with ctx.response.