最近公司新的專案想用koa2來實作API服務,除了一般的post data外還會有第三方傳來的multipart-post data。我們使用koa-joi-router這個套件驗證傳進來的資料,同時使用supertest做測試。
首先說明koa-joi-router跟其它套件有什麼不同,它使用joi這個物件描述語言定義javascript object的schema,我們能限制輸入參數的型態、字元個數及是不是必要欄位。
而joi這個套件也能用在一般的javascript object
由於koa-joi-router己內建co-body及await-busboy這二套body-parser,我們不需要再另外裝body-parser。
以下是一個post API的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const koa = require('koa'); const router = require('koa-joi-router'); const Joi = router.Joi;
const public = router();
public.route({ method: 'post', path: '/comments', validate: { type: 'json', body: { title: Joi.string().max(100).required, content: Joi.string().required } }, handler: async (ctx) => { } });
const app = new koa(); app.use(public.middleware()); app.listen(3000);
|
我們必須指定傳進來的資料類型及body要檢查的參數,koa-joi-router有三種type可以使用:json, form和multipart。要注意的是,如果傳進來資料型態和宣告的不同,會直接return 400. 要檢查的參數如果條件不符也會直接回400
而測試程式碼如下(使用mocha和supertest):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const superagent = require('supertest');
const app = require('src/app');
function request() { return superagent(app.listen()); }
describe('API Test /1/comments', () => { it('Create a new comment', (done) => { const testData = { title: 'Test', content: 'This is a test comment' }; request() .post('/1/comments') .send(testData) .expect(200) .end(done); }); });
|
假如API傳進來的資料為form data,則validate的type設定要改為form
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public.route({ method: 'post', path: '/blog', validate: { type: 'form', body: { title: Joi.string().max(100).required, content: Joi.string().required } }, handler: async (ctx) => { } });
|
測試如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| describe('API Test /1/blog', () => { it('Create a new blog post', (done) => { const testData = { title: 'Blog Test', content: 'This is a test post' }; request() .post('/1/blog') .type('form') .send(testData) .expect(200) .end(done); }); });
|
最後則是multipart的資料,此種資料一般為上傳檔案或是stream會用到。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public.route({ method: 'post', path: '/files', validate: { type: 'multipart', }, handler: async (ctx) => { const parts = ctx.request.parts; let part; try { while ((part = await parts)) { console.log(`Receive stream key: ${part[0]}, value: ${part[1]}); } } catch (err) { throw new Error(err); } const fileContent = parts.field.File; // upload file ... } });
|
Test code:
1 2 3 4 5 6 7 8 9 10 11 12 13
| describe('API Test /1/files', () => { it('Upload a file', (done) => { const testData = { File: 'file content' }; request() .post('/1/blog') .field('File', testData.File) .expect(200) .end(done); }); });
|
如果本地端使用postman測試的話,這篇文章的答案對於設定會有幫助。
參考資料:
koa-joi-router github
supertest github