Skip to content

Commit 09c6d83

Browse files
committed
implement koa api
1 parent e6d20a8 commit 09c6d83

File tree

4 files changed

+99
-31
lines changed

4 files changed

+99
-31
lines changed
Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,86 @@
1-
import { demo } from '../index'
1+
import type { NextApiRequest, NextApiResponse } from 'next'
2+
import request from 'supertest'
3+
import { KoaApi, KoaApiOptions, withKoaApi } from '../index'
24

3-
describe('Test', () => {
4-
test('Demo Test', () => {
5-
expect(demo).toBeDefined()
5+
describe('Koa Api', () => {
6+
describe('Request body', () => {
7+
test('body data is attached from original request', async () => {
8+
const bodyData = { name: 'ivan' }
9+
const api = new KoaApi()
10+
11+
api.use((ctx) => {
12+
ctx.body = ctx.request.body
13+
})
14+
15+
const result = await request(
16+
(req: NextApiRequest, res: NextApiResponse) => {
17+
req.body = bodyData
18+
19+
api.run(req, res)
20+
}
21+
).get('/')
22+
23+
expect(result.body).toEqual(bodyData)
24+
})
25+
26+
test('body data is not attached', async () => {
27+
const bodyData = { name: 'ivan' }
28+
const api = new KoaApi({ attachBody: false })
29+
30+
api.use((ctx) => {
31+
ctx.body = ctx.request.body
32+
})
33+
34+
const result = await request(
35+
(req: NextApiRequest, res: NextApiResponse) => {
36+
req.body = bodyData
37+
api.run(req, res)
38+
}
39+
).get('/')
40+
41+
expect(result.body).toEqual({})
42+
})
43+
})
44+
45+
describe('Router', () => {
46+
test('router options are passed down to the router', () => {
47+
const routerOptions: KoaApiOptions['router'] = {
48+
prefix: '/abc',
49+
strict: true
50+
}
51+
const api = new KoaApi({ router: routerOptions })
52+
53+
expect(api.router.opts).toEqual(routerOptions)
54+
})
55+
56+
test('handle method not allowed', async () => {
57+
const api = new KoaApi()
58+
const getHello = jest.fn()
59+
60+
api.router.get('/hello', getHello)
61+
62+
const result = await request(withKoaApi(api)).post('/hello')
63+
64+
expect(getHello).not.toHaveBeenCalled()
65+
expect(result.status).toBe(405)
66+
})
67+
68+
test('handle route not implemented', async () => {
69+
const api = new KoaApi()
70+
const getHello = jest.fn()
71+
72+
api.router.get('/hello', getHello)
73+
74+
const result = await request(withKoaApi(api)).search('/hello')
75+
76+
expect(result.status).toBe(501)
77+
})
78+
79+
test('can create new router', () => {
80+
const api = new KoaApi()
81+
82+
const router = api.createNewRouter()
83+
expect(router).toBeInstanceOf(router.constructor)
84+
})
685
})
7-
test.todo('Write more tests!')
886
})

lib/koa-api/src/globals.d.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.

lib/koa-api/src/index.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1 @@
1-
/**
2-
* Demo function for template repository
3-
*
4-
* @remarks
5-
* Read more about TSDoc at: {@link https://github.com/microsoft/tsdoc}
6-
*
7-
* @returns Nothing!
8-
*
9-
* @beta
10-
*/
11-
export function demo(): void {}
12-
demo()
1+
export * from './koa-api'

lib/koa-api/src/koa-api.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import Router, { RouterOptions } from '@koa/router'
22
import { default as Koa } from 'koa'
33
import type { NextApiRequest, NextApiResponse } from 'next'
4+
import onFinished from 'on-finished'
45

56
declare module 'koa' {
67
type IncomingMessage = NextApiRequest
@@ -19,7 +20,7 @@ type KoaOptions = {
1920
maxIpsCount?: number
2021
}
2122

22-
type KoaApiOptions = {
23+
export type KoaApiOptions = {
2324
koa?: KoaOptions
2425
attachBody?: boolean
2526
router?: Router.RouterOptions
@@ -36,17 +37,13 @@ export class KoaApi extends Koa {
3637
constructor(options: KoaApiOptions = {}) {
3738
super(options.koa)
3839

39-
const { router: routerOpts = {} } = options || {}
4040
this.options = {
4141
...options,
42-
attachBody: options?.attachBody ?? true,
43-
router: {
44-
...routerOpts,
45-
prefix: routerOpts.prefix ?? '/api'
46-
}
42+
attachBody: options?.attachBody ?? true
4743
}
4844

4945
this.router = new Router(this.options.router)
46+
5047
if (this.options.attachBody) {
5148
this.use((ctx, next) => {
5249
ctx.request.body = ctx.req.body
@@ -55,18 +52,26 @@ export class KoaApi extends Koa {
5552
}
5653
}
5754

58-
run(req: NextApiRequest, res: NextApiResponse) {
55+
async run(req: NextApiRequest, res: NextApiResponse) {
56+
const p = new Promise((resolve) => onFinished(res, resolve))
57+
58+
this.callback()(req, res) as unknown as Promise<void>
59+
60+
return p
61+
}
62+
63+
override callback() {
5964
if (this.firstRun) {
6065
this.firstRun = false
6166
this.use(this.router.routes()).use(
6267
this.router.allowedMethods(this.options.routerAllowedMethods)
6368
)
6469
}
6570

66-
return this.callback()(req, res)
71+
return super.callback()
6772
}
6873

69-
getNewRouter(opts?: RouterOptions) {
74+
createNewRouter(opts?: RouterOptions) {
7075
return new Router(opts)
7176
}
7277
}

0 commit comments

Comments
 (0)