Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes in cache and pathParams validation #2

Merged
merged 3 commits into from Jan 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions lib/joi.js
Expand Up @@ -18,9 +18,10 @@ let myJoi = _joi2.default.extend({
base: _joi2.default.object(),
name: 'object',
language: {
json: 'invalid json' },
json: 'invalid json' // Used below as 'number.round'
},
coerce(value, state, options) {
if (this._flags.json && typeof value.toJSON === 'function') {
if (this._flags.json && value && typeof value.toJSON === 'function') {
return value.toJSON();
}
return value;
Expand Down
11 changes: 6 additions & 5 deletions lib/validate.js
Expand Up @@ -163,9 +163,9 @@ function mixedValidate(document, opts = {}) {
});
function matchPath(si, ctx) {
const path = ctx.path.replace(new RegExp(`^${document.basePath}`), '');
const match = path.match(si.pathRe) && ctx.method.toLowerCase() in si.schema;
return match && si.keys.reduce((params, key, i) => {
params[key] = match[i + 1];
const match = path.match(si.pathRe);
return match && ctx.method.toLowerCase() in si.schema && si.keys.reduce((params, key, i) => {
params[key.name] = match[i + 1];
return params;
}, {});
}
Expand All @@ -176,11 +176,12 @@ function mixedValidate(document, opts = {}) {
let schemaInfo = schemaInfos.find(function (si) {
return pathParams = pathParams || matchPath(si, ctx);
});
ctx.request.pathParams = pathParams;
if (!schemaInfo) return next();
const key = schemaInfo.path;
const method = ctx.method.toLowerCase();
const key = method + schemaInfo.path;
let validate = cache[key];
if (!validate) {
const method = ctx.method.toLowerCase();
(0, _utils.debug)('schemaInfo', method, schemaInfo.schema);
const schema = schemaInfo.schema[method];
const joiValidateSchema = (0, _extends3.default)({
Expand Down
2 changes: 1 addition & 1 deletion src/joi.js
Expand Up @@ -7,7 +7,7 @@ let myJoi = Joi.extend({
json: 'invalid json', // Used below as 'number.round'
},
coerce(value, state, options) {
if (this._flags.json &&
if (this._flags.json && value &&
typeof value.toJSON === 'function') {
return value.toJSON()
}
Expand Down
11 changes: 6 additions & 5 deletions src/validate.js
Expand Up @@ -114,9 +114,9 @@ export default function mixedValidate(document, opts = {}) {
})
function matchPath(si, ctx) {
const path = ctx.path.replace(new RegExp(`^${document.basePath}`), '')
const match = path.match(si.pathRe) && (ctx.method.toLowerCase() in si.schema)
return match && si.keys.reduce((params, key, i) => {
params[key] = match[i + 1]
const match = path.match(si.pathRe)
return match && (ctx.method.toLowerCase() in si.schema) && si.keys.reduce((params, key, i) => {
params[key.name] = match[i + 1]
return params
}, {})
}
Expand All @@ -125,11 +125,12 @@ export default function mixedValidate(document, opts = {}) {
let pathParams
let schemaInfo = schemaInfos.find(
si => (pathParams = pathParams || matchPath(si, ctx)))
ctx.request.pathParams = pathParams;
if (!schemaInfo) return next()
const key = schemaInfo.path
const method = ctx.method.toLowerCase()
const key = method + schemaInfo.path
let validate = cache[key]
if (!validate) {
const method = ctx.method.toLowerCase()
debug('schemaInfo', method, schemaInfo.schema)
const schema = schemaInfo.schema[method]
const joiValidateSchema = {
Expand Down
29 changes: 27 additions & 2 deletions test/fixtures/controllers/Post.js
@@ -1,4 +1,4 @@
import { controller, get, post } from 'koa-dec-router'
import { controller, get, post, put } from 'koa-dec-router'
import BaseCtrl from './Base'

const posts = []
Expand Down Expand Up @@ -55,7 +55,7 @@ export default class PostCtrl extends BaseCtrl {

@get('/:id')
async get(ctx) {
console.log(ctx)
console.log('get', ctx)
const { okMore, okMatch, errorMore } = ctx.query
const { id } = ctx.params
const post = posts.find(p => p.get('_id') === id)
Expand Down Expand Up @@ -83,6 +83,31 @@ export default class PostCtrl extends BaseCtrl {
}
}

@put('/:id')
async put(ctx) {
console.log('put', ctx)
const { errorMore } = ctx.query
const { id } = ctx.params
const post = posts.find(p => p.get('_id') === id)
if (!post) {
ctx.status = 404
ctx.body = {
code: 1,
message: 'not_found',
data: {},
}
if (errorMore) {
ctx.body.more_field = 'more_field'
}
return
}
Object.assign(post.data, ctx.body)
ctx.body = {
code: 0,
data: post.data,
}
}

@post('/create')
async create(ctx) {
const { entity } = ctx.request.body
Expand Down
26 changes: 24 additions & 2 deletions test/fixtures/posts.js
@@ -1,6 +1,7 @@
import { Err, pageQuery, api, page, pageApi } from './utils'

import joiSwagger from '../../src'

const { Joi } = joiSwagger
import Debug from 'debug'

Expand All @@ -25,7 +26,7 @@ const Post = PostLite.concat(Joi.object().json().keys({
}))

const pathId = (msg = 'path id') => Joi.object().keys({
id: Joi.string().required().description(msg),
id: Joi.number().integer().required().description(msg),
})

export default {
Expand Down Expand Up @@ -66,6 +67,27 @@ export default {
},
},
},
put: {
summary: 'Edit post',
description: 'Edit post',
tags: ['Post'],
parameters: {
pathParams: pathId(),
body: Joi.object().keys({
entity: PostCreate.required(),
}),
},
responses: {
'200': {
description: '文章详情',
schema: api(Post),
},
'default': {
description: '出现错误(请求错误4xx)',
schema: Err,
},
},
},
},
'/post/create': {
post: {
Expand All @@ -74,7 +96,7 @@ export default {
tags: ['Post'],
parameters: {
body: Joi.object().keys({
entity: PostCreate,
entity: PostCreate.required(),
}),
},
responses: {
Expand Down
56 changes: 44 additions & 12 deletions test/test.js
Expand Up @@ -31,6 +31,11 @@ const notFound = {
message: 'not_found',
}

async function createPost() {
let res = await agent.post('/api/v1/post/create').send({ entity: postCreate })
return res.body.data;
}

test.before(async () => {
const port = await getPort(3457).then(port => {
app.listen(port)
Expand All @@ -41,7 +46,6 @@ test.before(async () => {

test('success', async t => {
let res = await agent.get('/api/v1/posts').expect(200)
console.log(res.body)
t.deepEqual(res.body, {
'code': 0,
'data': {
Expand All @@ -57,39 +61,39 @@ test('success', async t => {
entity: postCreate,
})
.expect(200)
let createdPost = res.body.data;

t.deepEqual(res.body, {
code: 0,
data: post,
})

res = await agent.get('/api/v1/post/1').expect(200)
res = await agent.get(`/api/v1/post/${createdPost._id}`).expect(200)
t.deepEqual(res.body, {
code: 0,
data: post,
data: createdPost,
})
})

test('error', async t => {
let res = await agent.get('/api/v1/post/2').expect(404)
console.log(res.body)
let res = await agent.get('/api/v1/post/666').expect(404)
t.deepEqual(res.body, notFound)
})

test('remove more field', async t => {
let createdPost = await createPost();
let res = await agent
.get('/api/v1/post/1')
.get(`/api/v1/post/${createdPost._id}`)
.query({
okMore: true,
})
.expect(200)
t.deepEqual(res.body, {
code: 0,
data: post,
data: createdPost,
})

res = await agent
.get('/api/v1/post/2')
.get('/api/v1/post/666')
.query({
failMore: true,
})
Expand All @@ -98,21 +102,23 @@ test('remove more field', async t => {
})

test('error type', async t => {
let createdPost = await createPost();
let res = await agent
.get('/api/v1/post/1')
.get(`/api/v1/post/${createdPost._id}`)
.query({
okMatch: true,
})
.expect(500)

t.deepEqual(res.body, {
code: 1,
message: 'response.body:child "data" fails because [child "read_count" fails because ["read_count" must be a number]]',
data: {
code: 0,
data: {
...post,
...createdPost,
read_count: 'stringType',
more_field: 'more_field',
//more_field: 'more_field',
},
},
})
Expand All @@ -139,3 +145,29 @@ test('request validation', async t => {
},
})
})


test('do not cache different methods with same path', async t => {
let createdPost = await createPost();
let res = await agent.get(`/api/v1/post/${createdPost._id}`)
.expect(200)
t.deepEqual(res.body, {
code: 0,
data: createdPost,
})

res = await agent
.put(`/api/v1/post/${createdPost._id}`)
.expect(400)

t.deepEqual(res.body, {
code: 1,
data: {},
message: 'request.body:child "entity" fails because ["entity" is required]',
})
})


test('validate pathParams', async t => {
await agent.get(`/api/v1/post/test`).expect(400)
})