How can I split my koa routes into separate files?
Asked Answered
B

8

40

I'm trying to figure out how to split my routes into separate files.

I have this so far, but it doesn't work. I just get Not found when I try to access http://localhost:3001/api/things

//server.js
var koa = require('koa');
var app = koa();
var router = require('koa-router');

app.use(router(app));
require('./routes')(app);


// routes.js
module.exports = function *(app){
  app.use('/api/things', require('./api/things'));
};


// api/things/index.js

var Router = require('koa-router');
var router = new Router({
  prefix: '/api/things'
});

router.get('/', function *(){
  this.body = [{ name: 'Foo'}, { name: 'Bar' }];
});

module.exports = router;
Bostic answered 17/5, 2015 at 10:4 Comment(1)
Hi if you're still active can you change the accepted answer? To the one with 47 votes.Sprinkling
A
76

EDIT: I've updated the code examples below because the koa-router package on npm is no longer maintained. The Koa team has made an official fork of it under the name @koa/router.


For anyone reading this, who is curious on how to do this in Koa 2.X:

app.js

import Koa from 'koa'
import rootRouter from './routes/root'
import userRouter from './routes/user'

const app = new Koa()

app.use(rootRouter.routes())
app.use(rootRouter.allowedMethods())
app.use(userRouter.routes())
app.use(userRouter.allowedMethods())

export default app

routes/root.js

import Router from '@koa/router'
const router = new Router()

router.get('/', async (ctx, next) => {
  ctx.body = 'Hello'
})

export default router

routes/user.js

import Router from '@koa/router'
const router = new Router({ prefix: '/user' })

router.get('/', async (ctx, next) => {
  ctx.body = 'Some User'
})

export default router

If you want to avoid the repetition with the routes() and the allowedMethods(), you can use koa-compose to compose the middleware together. For simplicity, I made a wrapper around it to simplify working with koa-router. Using it would look something like this:

app.js

import Koa from 'koa'
import router from './routes'

const app = new Koa()

app.use(router())

export default app  

routes/index.js

import combineRouters from 'koa-combine-routers'
import rootRouter from './root'
import userRouter from './user'

const router = combineRouters(
  rootRouter,
  userRouter
)

export default router

And it would do the same thing.

Agneta answered 2/9, 2016 at 23:51 Comment(2)
I have tried this solution but I have the next error: Router is not defined.Rosiorosita
@nole. do you have a code sample you can share with something like GitHub gist?Agneta
I
19

server.js

var app = require('koa')();
var router = require('./routes');
app.use(router.routes());
app.use(router.allowedMethods());
app.listen(3000);

routes.js

var router = require('koa-router')();
router.get('/', function* () {
    this.body = 'router test';
});
module.exports = router;
Illuminative answered 20/5, 2015 at 9:34 Comment(0)
C
12

Something like this should work:

// app.js
var koa = require('koa'),
    app = koa();

require('./routes1')(app);
require('./routes2')(app);

app.listen(3000);

// routes1.js
var Router = require('koa-router');
function register (app) {
  var router = new Router({
    prefix: '/api'
  });
  router.get('/', ...); // responds to "/api"
  router.get('/messages', ...); // responds to "/api/messages"
  app.use(router.routes());
  app.use(router.allowedMethods());
}

module.exports = register

// routes2.js
var Router = require('koa-router');
function register (app) {
  var router = new Router();
  router.get('/', ...); // responds to "/"
  app.use(router.routes());
  app.use(router.allowedMethods());
}

module.exports = register
Cleareyed answered 18/5, 2015 at 13:54 Comment(4)
what is the purpose of the allowedMethods() call?Bostic
Supports http OPTIONS method and responds with something like this: 200 OK Allow: HEAD,GET,PUT,DELETE,OPTIONS Essentially specifying the methods the server supports for the given URLCleareyed
This is a great solution, but it is now outdated and will not work.Mireielle
I forget the details. This is an old post. I believe there was a major update to koa or koa-router that changed the syntax. I ended up needing to do the following: var api = new Router(); var api1 = require('./methods/api1'); api.use('/api1/v0/', api1.routes(), api1.allowedMethods()); var api2 = require('./methods/api2'); api.use('/api2/v0/', api2.routes(), api2.allowedMethods()); app.use(api.routes());Mireielle
A
7

For Koa 2.x I find nested routes with prefixes to deliver the goods, with no additional packages.

Assuming /api/dogs and /api/cats are the required outcomes.

Like so:

app.js

import Koa from 'koa';
import Router from 'koa-router';
import apiRouter from './routes/apiRouter';

const app = new Koa();

app.use(apiRouter.routes(), apiRouter.allowedMethods());

app.listen(3000);

export default app;

routes/apiRouter.js

import Router from 'koa-router'

import dogsRouter from './dogsRouter'
import catsRouter from './catsRouter'

const apiRouter = new Router({ prefix: '/api' })

const nestedRoutes = [dogsRouter, catsRouter]
for (var router of nestedRoutes) {
    apiRouter.use(router.routes(), router.allowedMethods())
}

export default apiRouter;

routes/dogsRouter.js

import Router from 'koa-router'

const dogsRouter = new Router({ prefix: '/dogs' });

dogsRouter.get('/', async (ctx, next) => {
  ctx.body = 'Dogs be here'
});

export default dogsRouter;

routes/catsRouter.js

import Router from 'koa-router'

const catsRouter = new Router({ prefix: '/cats' });

catsRouter.get('/', async (ctx, next) => {
  ctx.body = 'Cats be here'
});

export default catsRouter;
Alsoran answered 13/2, 2019 at 9:56 Comment(0)
I
4

Minimalistic approach which i think TJ kept in mind when he did

koa, koa-route, koa-mount

Approach with small independent apps which mounted the way you like then:

index.js

var app = require('./app')
app.listen(3000);

app.js

const Koa = require('koa')
const _ = require('koa-route')
const mount = require('koa-mount')
const app = new Koa()
const pets = require('./pets')

// sub apps
app.use(mount('/pets', pets))

// root app
app.use(_.get('/', function(){
  this.body = "hello";
}))

module.exports = app;

pets.js

var Koa = require('koa');
var _ = require('koa-route');
var app = new Koa();


app.use(_.get('/', ctx => ctx.body = "pets" ));
app.use(_.get('/:name', (ctx, name) => ctx.body = "pet: "+ name));

module.exports = app;
Irrespirable answered 3/11, 2016 at 10:58 Comment(0)
B
3

Here's what I ended up going with:

//server.js
'use strict';

var koa = require('koa');
var app = koa();
var serve = require('koa-static');
var path = require('path');
var router = require('koa-router');
var cfg = require('./config');
var mw = require('./middleware');

app.use(serve(path.resolve(__dirname, '../client')));
app.use(mw.requestTime('Response-time'));
app.use(router(app));
app.use(cfg.db.connect);

require('./routes')(app);

app.get('/api', function *(){
  this.body = 'Welcome to API v1';
});

app.use(cfg.db.close);
app.listen(cfg.env.port);



//routes.js
module.exports = function (app){
  app.use(require('./api/things').routes());
};


// api/things/index.js
var Router = require('koa-router');

var router = new Router({
  prefix: '/api/things'
});

var ctrl = require('./controllers');

router.get('/', ctrl.list);
router.get('/:id', ctrl.get);
router.post('/', ctrl.post);
router.put('/:id', ctrl.put);
router.del('/:id', ctrl.del);

module.exports = router;


// api/things/controllers.js

var r = require('rethinkdb');
var http = require('http');
var parse = require('co-body');
var ctrl = module.exports = {};

ctrl.list = function *(next){
};

ctrl.get = function *(next){
};

ctrl.post = function *(next){
};

ctrl.put = function *(next){
};

ctrl.del = function *(next){
};
Bostic answered 18/5, 2015 at 21:53 Comment(0)
K
3

You can put all your routes inside a single folder called routes, then loop through all files in that folder, require them and init. That way for any new route, just create a file in routes folder and thats it.

So something like this:

index.js

const Koa = require("koa");
const logger = require("koa-logger");
const bodyParser = require("koa-bodyparser");

const app = new Koa();

app.use(logger());
app.use(bodyParser());

require("./routes")(app);

const server = app.listen(config.server.port);

module.exports = server;

/routes/index.js

const fs = require("fs");
const path = require("path");
const baseName = path.basename(module.filename);

const routes = fs
    .readdirSync(path.join(__dirname))
    .filter(
        file =>
            file.indexOf(".") !== 0 &&
            file !== baseName &&
            file.slice(-3) === ".js"
    )
    .map(file => require(path.join(__dirname, file)));

module.exports = function(app) {
    for (var router of routes) {
        app.use(router.routes());
    }
};

Then inside /routes folder you would have like

/routes/user.js

/routes/customer.js

which are all router exports such as

/routes/auth.js

const Router = require("koa-router");
const authControllers = require("../controllers/auth");

const {
    jwtAuth,
    login,
    register,
    forgotPassword,
    resetPassword,
    getAuthenticatedUser
} = authControllers;

const router = new Router({ prefix: "/auth" });

router.post("/register", register);
router.post("/login", login);
router.post("/forgot-password", forgotPassword);
router.post("/reset-password/:resetToken", resetPassword);
router.get("/profile", jwtAuth, getAuthenticatedUser);

module.exports = router;
Katrinakatrine answered 29/1, 2020 at 10:35 Comment(2)
I don't know why this answer is underrated. This can typically used in large applications to omit redundancy. Simple and follows DRY Principle. Thank you @Goran. Do you mind sharing any other tips for building large Koa apps?Windstorm
Hi! I think your solution is the most valuable and simple solution there is. Do you know if there are any downsides by using multiple files (thus creating multiple routers with each have his own routes) than using a single router with multiple routes in terms of performance?Evvy
A
0

Simular, but exactly what I needed was:

app.js

"use strict";
import Koa from 'koa';
const app = new Koa();

import Router from 'koa-router';
const router = new Router();

import mount from 'koa-mount';
import routes from "./router/index.mjs";

app.use(mount(routes));
app.use(router.routes());

app.listen(3000, () => console.log("Listening on port: 3000"));

router/index.mjs

"use strict";
import Koa from 'koa';
const app = new Koa();

import Router from 'koa-router';
const router = new Router();

router.get('/', async (ctx, next) => {
    ctx.body = {success: true};
    await next();
});

app.use(router.routes());

export default app;
Agribusiness answered 28/5, 2021 at 7:19 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.