Search code examples
javascriptnode.jshttp-status-code-404koakoa-router

How to handle a 404 in Koa 2?


I have a 404.jade file that I want to render whenever there is an invalid GET request.

Here is my current code:

app.js

import Koa from 'koa'
import views from 'koa-views'
import serve from 'koa-static'
import rootRoutes from './routes/index'
import userRoutes from './routes/user'

const app = new Koa()

app.use(views(`${__dirname}/views`, { extension: 'jade' }))
app.use(serve(`${__dirname}/public`))
app.use(rootRoutes.routes())
app.use(userRoutes.routes())

app.listen(3000, () => {
  console.log('Server running at http://localhost:3000')
})

export default app

routes/index.js

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

router.get('/', async ctx => {
  await ctx.render('index')
})

router.get('/about', async ctx => {
  await ctx.render('about')
})

export default router

routes/user.js

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

router.get('/:name', async ctx => {
  const user = ctx.params.name
  await ctx.render('user', { user })
})

export default router

How can I handle any type of invalid GET request and somehow use await ctx.render('404') whenever it happens?


Solution

  • You can add a custom middleware in your app.js file.

    import Koa from 'koa'
    import views from 'koa-views'
    import serve from 'koa-static'
    import rootRoutes from './routes/index'
    import userRoutes from './routes/user'
    
    const app = new Koa()
    
    app.use(async(ctx, next) => {
      try {
        await next()
        const status = ctx.status || 404
        if (status === 404) {
            ctx.throw(404)
        }
      } catch (err) {
        ctx.status = err.status || 500
        if (ctx.status === 404) {
          //Your 404.jade
          await ctx.render('404')
        } else {
          //other_error jade
          await ctx.render('other_error')
        }
      }
    })
    
    app.use(views(`${__dirname}/views`, { extension: 'jade' }))
    app.use(serve(`${__dirname}/public`))
    app.use(rootRoutes.routes())
    app.use(userRoutes.routes())
    
    app.listen(3000, () => {
      console.log('Server running at http://localhost:3000')
    })
    
    export default app