Comprehensive Guide to Building Web Applications with Koa
This tutorial walks you through setting up a Node.js environment, installing Koa, and progressively building a web application by covering basic HTTP services, context handling, response types, routing, middleware, error handling, cookies, form processing, and file uploads with clear code examples.
Koa is a lightweight, elegant web framework for Node.js that follows the Unix philosophy by keeping the core small and extending functionality through plugins. This guide starts from zero, showing how to prepare the environment, check Node version (>=7.6), clone the demo repository, and install dependencies.
Basic Usage
With just three lines of code you can create an HTTP server:
// demos/01.js
const Koa = require('koa');
const app = new Koa();
app.listen(3000);Running node demos/01.js starts the server, which initially returns "Not Found" because no response body is set.
The Context object (available as ctx ) gives access to request and response. Setting ctx.response.body defines the output:
// demos/02.js
const Koa = require('koa');
const app = new Koa();
const main = ctx => {
ctx.response.body = 'Hello World';
};
app.use(main);
app.listen(3000);Koa can return different content types by inspecting ctx.request.accepts and setting ctx.response.type :
// demos/03.js
const main = ctx => {
if (ctx.request.accepts('xml')) {
ctx.response.type = 'xml';
ctx.response.body = '
Hello World
';
} else if (ctx.request.accepts('json')) {
ctx.response.type = 'json';
ctx.response.body = { data: 'Hello World' };
} else if (ctx.request.accepts('html')) {
ctx.response.type = 'html';
ctx.response.body = '
Hello World
';
} else {
ctx.response.type = 'text';
ctx.response.body = 'Hello World';
}
};Templates can be served by streaming a file:
// demos/04.js
const fs = require('fs');
const main = ctx => {
ctx.response.type = 'html';
ctx.response.body = fs.createReadStream('./demos/template.html');
};Routing
Simple routing can be done by inspecting ctx.request.path :
// demos/05.js
const main = ctx => {
if (ctx.request.path !== '/') {
ctx.response.type = 'html';
ctx.response.body = '
Index Page
';
} else {
ctx.response.body = 'Hello World';
}
};For more convenient routing, the koa-route module is used:
// demos/06.js
const route = require('koa-route');
const about = ctx => {
ctx.response.type = 'html';
ctx.response.body = '
Index Page
';
};
const main = ctx => {
ctx.response.body = 'Hello World';
};
app.use(route.get('/', main));
app.use(route.get('/about', about));Static assets are served with koa-static :
// demos/12.js
const path = require('path');
const serve = require('koa-static');
const main = serve(path.join(__dirname));
app.use(main);Redirects are performed via ctx.response.redirect() :
// demos/13.js
const redirect = ctx => {
ctx.response.redirect('/');
ctx.response.body = '
Index Page
';
};
app.use(route.get('/redirect', redirect));Middleware
Logging can be added as a middleware function:
// demos/07.js
const main = ctx => {
console.log(`${Date.now()} ${ctx.request.method} ${ctx.request.url}`);
ctx.response.body = 'Hello World';
};Middleware can be composed and chained, with the next() function passing control downstream. An example of a middleware stack demonstrates the first‑in‑last‑out execution order:
// demos/09.js
const one = (ctx, next) => { console.log('>> one'); next(); console.log('<< one'); };
const two = (ctx, next) => { console.log('>> two'); next(); console.log('<< two'); };
const three = (ctx, next) => { console.log('>> three'); next(); console.log('<< three'); };
app.use(one);
app.use(two);
app.use(three);Asynchronous middleware uses async and await for operations like reading files:
// demos/10.js
const fs = require('fs.promised');
const Koa = require('koa');
const app = new Koa();
const main = async function (ctx, next) {
ctx.response.type = 'html';
ctx.response.body = await fs.readFile('./demos/template.html', 'utf8');
};
app.use(main);
app.listen(3000);Multiple middleware can be combined with koa-compose :
// demos/11.js
const compose = require('koa-compose');
const logger = (ctx, next) => { console.log(`${Date.now()} ${ctx.request.method} ${ctx.request.url}`); next(); };
const main = ctx => { ctx.response.body = 'Hello World'; };
const middlewares = compose([logger, main]);
app.use(middlewares);Error Handling
Errors can be thrown with ctx.throw(500) or by setting ctx.response.status = 404 . Centralized error handling middleware catches exceptions and formats the response:
// demos/16.js
const handler = async (ctx, next) => {
try { await next(); } catch (err) {
ctx.response.status = err.statusCode || err.status || 500;
ctx.response.body = { message: err.message };
}
};
const main = ctx => { ctx.throw(500); };
app.use(handler);
app.use(main);The error event can also be listened to for logging:
// demos/17.js
const main = ctx => { ctx.throw(500); };
app.on('error', (err, ctx) => console.error('server error', err));When errors are caught manually, the event must be emitted explicitly with ctx.app.emit('error', err, ctx) :
// demos/18.js
const handler = async (ctx, next) => {
try { await next(); } catch (err) {
ctx.response.status = err.statusCode || err.status || 500;
ctx.response.type = 'html';
ctx.response.body = '
Something wrong, please contact administrator.
';
ctx.app.emit('error', err, ctx);
}
};Web Application Features
Cookies are accessed via ctx.cookies :
// demos/19.js
const main = function(ctx) {
const n = Number(ctx.cookies.get('view') || 0) + 1;
ctx.cookies.set('view', n);
ctx.response.body = n + ' views';
};Form data can be parsed with koa-body and validated:
// demos/20.js
const koaBody = require('koa-body');
const main = async function(ctx) {
const body = ctx.request.body;
if (!body.name) ctx.throw(400, '.name required');
ctx.body = { name: body.name };
};
app.use(koaBody());File uploads are also handled by koa-body with multipart support:
// demos/21.js
const os = require('os');
const path = require('path');
const koaBody = require('koa-body');
const main = async function(ctx) {
const tmpdir = os.tmpdir();
const filePaths = [];
const files = ctx.request.body.files || {};
for (let key in files) {
const file = files[key];
const filePath = path.join(tmpdir, file.name);
const reader = fs.createReadStream(file.path);
const writer = fs.createWriteStream(filePath);
reader.pipe(writer);
filePaths.push(filePath);
}
ctx.body = filePaths;
};
app.use(koaBody({ multipart: true }));The article concludes with reference links to the Koa workshop, kick‑off‑koa, and official Koa examples repositories.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.