Nextjs Koa API is a library that packages Koa.js framework for use with the Next.js API routes.
Using Next.js routes is pretty straightforward, however, doing something like REST API with CRUD routes requires a more complicated setup. You end up using the switch
statement to check which http method
is used and then which url
is requested, and soon you end up with a spaghetti code in your API route that is hard to maintain and test. It would be great if we could use tried and tested HTTP
framework directly inside the routes.
So I decided to set up Koa.js to run inside the Next.js API route.
There are a lot of frameworks in Node.js land for handling HTTP responses, I've decided on Koa.js because it supports async
middleware out of the box. And the way the middleware is run via the onion model
is superior to other frameworks.
Koa.js source is very small and it can be initialized fast, which is important for a serverless function.
npm install nextjs-koa-api
This library bundles Koa.js and Koa router in one easy to use class. It is important to note that nothing is changed in regards to working with Koa or Koa Router.
The simplest example that would mimic the original Next.js api router is this:
//pages/api/[[...demo]].ts
import { KoaApi, withKoaApi } from 'nextjs-koa-api'
const api = new KoaApi({ router: { prefix: '/api' } })
api.use((ctx) => {
ctx.body = 'Hello World'
})
//use helper function
export default withKoaApi(api)
//or the standard way
export default function handler(req: NextApiRequest, res: NextApiResponse) {
return api.run(req, res)
}
KoaApi
class extends Koa
so all Koa
methods are available. It does not modify Koa or override any of its methods.
When you create a new KoaApi
instance you have Koa Router
available as the router
property on the instance. The router is connected to the KoaApi
instance so all that is left is to attach the routes.
//pages/api/[[...demo]].ts
const api = new KoaApi({ router: { prefix: '/api' } })
api.router
.get('/', (ctx, next) => {})
.post('/', (ctx, next) => {})
.delete('/', (ctx, next) => {})
In the above example the { prefix: '/api' }
that is passed to the KoaApi
instance is an option on the router that enables you to prefix
the router routes with a part of the url
.
so instead of writing:
api.router.get('/api', (ctx, next) => {}).delete('/api', (ctx, next) => {})
we can write:
api.router.get('/', (ctx, next) => {}).delete('/', (ctx, next) => {})
If your api file is nested deep: pages/api/dir_one/dir_two/[[...]].ts
using te prefix makes using routes a lot simpler: prefix: api/dir_one/dir_two
.
You can also work with nested routes by creating and mounting new routers. You can get a new router like this:
import {Router} from 'nextjs-koa-api`
const router = new Router()
For more info check out Koa Router docs
There is a convenient function for attaching a custom router. Internally it sets the prefix
path on the router,and calls router.routes()
and router.allowedMethods()
import {Router, KoaApi,attachRouter} from 'nextjs-koa-api`
const api = new KoaApi()
const router = new Router()
router.get('/',(ctx,next)=>{
ctx.body = 'hello'
return next()
})
attachRouter('/some/deep-path',api, router)
Router options that are passed to the
KoaApi
are not associated with the custom router. They are only applicable to the default router that is created.
Just like in the regular Kao.js app where the Node request
and response
objects are available on the context
object via the req
and res
properties, the same is with the KoaApi
api.use((ctx) => {
ctx.req // nextjs request
ctx.res // nextjs response
ctx.request //Koa request
ctx.response // Koa response
})
Nextjs automatically parses incoming body data and sets it up on the req.body
. With KoaApi
data from the req.body
(ctx.req
) will also be available on the ctx.request.body
. That means that for most cases you don't need other body parsing middleware.
If you want to disable setting the body data
on ctx.request.body
you can do that while creating the KoaApi
instance.
new KoaApi({ attachBody: false })
This library exports everything from the Kao and Koa Router libraries, which includes all the types.
import { Koa, KoaApi, Router, withKoaApi } from 'nextjs-koa-api'
interface ApiState extends Koa.DefaultState {
seesion: boolean
}
interface ApiContext extends Koa.Context {
user: { name: string }
}
const api = new KoaApi<ApiState, ApiContext>()
api.use(async (ctx, next) => {
ctx.user.name
ctx.state.seesion
})
Testing can be done with supertest
(https://github.com/visionmedia/supertest)
import request from 'supertest'
test('status is 200', async () => {
const api = new KoaApi()
api.router.get('/hello', (ctx) => {
ctx.body = 'hello'
})
const result = await request(withKoaApi(api)).post('/hello')
expect(result.status).toBe(200)
})
There is also @shopify/jest-koa-mocks
(https://github.com/Shopify/quilt/blob/main/packages/jest-koa-mocks/README.md) to easily stub Koa context and cookies.
There is a example directory in this repository, which is a Next.js app with one exported api route that uses KoaApi
.
This project is licensed under the MIT License - see the LICENSE file for details
Automatically generated API documentation can be found here