Skip to content
Learni
View all tutorials
Backend

How to Develop a REST API with Koa.js in 2026

14 minINTERMEDIATE
Lire en français

Introduction

Koa.js is a minimalist Node.js framework created by the team behind Express. It emphasizes generators and async/await for cleaner, more readable code. Unlike Express, Koa does not include a built-in router or default error handling, giving you complete freedom. This intermediate tutorial guides you through building a complete REST API: from a basic server to advanced error management and middleware. You'll learn how to structure a professional project while avoiding common pitfalls in asynchronous applications.

Prerequisites

  • Node.js 20+
  • Basic knowledge of modern JavaScript and async/await
  • npm or yarn installed
  • A code editor (VS Code recommended)

Project Initialization

terminal
mkdir koa-api-2026 && cd koa-api-2026
npm init -y
npm install koa koa-router @koa/cors dotenv
npm install --save-dev nodemon

We initialize the project and install Koa with its official router, the CORS middleware, and dotenv for environment variables. Nodemon simplifies development by automatically restarting the server.

Creating the Base Server

src/app.js
import Koa from 'koa';
import dotenv from 'dotenv';

dotenv.config();

const app = new Koa();
const PORT = process.env.PORT || 3000;

app.use(async (ctx) => {
  ctx.body = { message: 'API Koa opérationnelle' };
});

app.listen(PORT, () => {
  console.log(`Serveur démarré sur le port ${PORT}`);
});

This file creates a minimal Koa instance. The default middleware responds to all requests. We will use separate files for routing in the following steps.

Setting Up Routing

src/routes/users.js
import Router from 'koa-router';

const router = new Router({ prefix: '/api/users' });

router.get('/', async (ctx) => {
  ctx.body = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
});

router.get('/:id', async (ctx) => {
  ctx.body = { id: ctx.params.id, name: 'Utilisateur ' + ctx.params.id };
});

export default router;

We create a router with a prefix and two GET routes. ctx.params allows retrieving URL parameters in a simple and readable way.

Integrating Middlewares

src/app.js
import Koa from 'koa';
import Router from 'koa-router';
import cors from '@koa/cors';
import usersRouter from './routes/users.js';

const app = new Koa();
const router = new Router();

app.use(cors());
app.use(async (ctx, next) => {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  ctx.set('X-Response-Time', `${ms}ms`);
});

router.use(usersRouter.routes());
app.use(router.routes());
app.use(router.allowedMethods());

export default app;

Middlewares are executed in the order they are added. The timing middleware measures the duration of each request. We then connect the user routes.

Centralized Error Handling

src/middleware/errorHandler.js
export default async function errorHandler(ctx, next) {
  try {
    await next();
  } catch (err) {
    ctx.status = err.status || 500;
    ctx.body = {
      success: false,
      message: err.message || 'Erreur interne du serveur'
    };
    ctx.app.emit('error', err, ctx);
  }
}

This middleware intercepts all errors, returns a consistent JSON response, and emits the error event for centralized logging.

Best Practices

  • Always place the error handling middleware first
  • Use route prefixes to organize the API
  • Validate input data with a schema (e.g., Joi or Zod)
  • Separate routes, middlewares, and controllers into distinct files
  • Log errors with a structured tool like Winston or Pino

Common Mistakes to Avoid

  • Forgetting to call await next() in a middleware (blocks the chain)
  • Not handling asynchronous errors (uncaught rejected promises)
  • Using ctx.throw without an appropriate HTTP status
  • Installing too many global middlewares that slow down all requests

Going Further

Discover our advanced training on modern Node.js frameworks and API architectures: https://learni-group.com/formations

How to Develop a REST API with Koa.js in 2026 | Learni