From 5d40da9162a6ffc7e5d59f9a07bb178a390f6085 Mon Sep 17 00:00:00 2001 From: zwjamnsss Date: Thu, 14 Sep 2017 20:40:42 +0800 Subject: [PATCH 1/8] =?UTF-8?q?fix:=20casename=20=E8=BF=87=E9=95=BF=20?= =?UTF-8?q?=E6=8C=A1=E4=BD=8F=E5=88=A0=E9=99=A4=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Project/Interface/InterfaceCol/InterfaceColMenu.js | 4 ++-- .../Project/Interface/InterfaceCol/InterfaceColMenu.scss | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/client/containers/Project/Interface/InterfaceCol/InterfaceColMenu.js b/client/containers/Project/Interface/InterfaceCol/InterfaceColMenu.js index 93f5e30d..77097b53 100755 --- a/client/containers/Project/Interface/InterfaceCol/InterfaceColMenu.js +++ b/client/containers/Project/Interface/InterfaceCol/InterfaceColMenu.js @@ -247,8 +247,8 @@ export default class InterfaceColMenu extends Component { style={{width: '100%'}} key={'case_' + interfaceCase._id} title={ -
- {interfaceCase.casename} +
+ {interfaceCase.casename} { this.showDelCaseConfirm(interfaceCase._id) }} />
} diff --git a/client/containers/Project/Interface/InterfaceCol/InterfaceColMenu.scss b/client/containers/Project/Interface/InterfaceCol/InterfaceColMenu.scss index 815fa8ae..4fb8a4ab 100755 --- a/client/containers/Project/Interface/InterfaceCol/InterfaceColMenu.scss +++ b/client/containers/Project/Interface/InterfaceCol/InterfaceColMenu.scss @@ -6,7 +6,11 @@ display: flex; justify-content: space-between; overflow: hidden; + .casename { + overflow: hidden; + } .case-delete-icon{ + margin-left: 5px; display: none; } i:before{ From bd821e30bc5e9aae955d58ec3e7d2451613ba498 Mon Sep 17 00:00:00 2001 From: zwjamnsss Date: Fri, 15 Sep 2017 17:42:01 +0800 Subject: [PATCH 2/8] =?UTF-8?q?opti:=20=E6=B2=A1=E6=9C=89=E6=9D=83?= =?UTF-8?q?=E9=99=90=E7=9A=84=E5=88=86=E7=BB=84=E7=A6=81=E7=94=A8=E6=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/containers/AddProject/AddProject.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/containers/AddProject/AddProject.js b/client/containers/AddProject/AddProject.js index 28f1b551..8842c4e3 100755 --- a/client/containers/AddProject/AddProject.js +++ b/client/containers/AddProject/AddProject.js @@ -131,7 +131,9 @@ class ProjectList extends Component { }] })( )} From c3f367915b538ca570ddce7be5a44423c5f1e31e Mon Sep 17 00:00:00 2001 From: suxiaoxin Date: Sun, 17 Sep 2017 20:43:34 +0800 Subject: [PATCH 3/8] opti: opti postman domain tip --- client/components/Postman/Postman.js | 42 +++++++++++++++------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/client/components/Postman/Postman.js b/client/components/Postman/Postman.js index f81df4e9..bcd4d71e 100755 --- a/client/components/Postman/Postman.js +++ b/client/components/Postman/Postman.js @@ -19,24 +19,24 @@ function json_parse(data) { } } -function isValidJson(json){ - if(!json) return false; - if(typeof json === 'object') return true; - try{ - if(typeof json === 'string'){ +function isValidJson(json) { + if (!json) return false; + if (typeof json === 'object') return true; + try { + if (typeof json === 'string') { json5.parse(json); return true; } - }catch(e){ + } catch (e) { return false; } } -function isJsonData(headers, res){ - if(isValidJson(res)){ +function isJsonData(headers, res) { + if (isValidJson(res)) { return true; } - if(!headers || typeof headers !== 'object') return false; + if (!headers || typeof headers !== 'object') return false; let isResJson = false; Object.keys(headers).map(key => { if (/content-type/i.test(key) && /application\/json/i.test(headers[key])) { @@ -192,7 +192,7 @@ export default class Run extends Component { const href = URL.format({ protocol: urlObj.protocol || 'http', host: urlObj.host, - pathname: urlObj.pathname? urlObj.pathname + path : path, + pathname: urlObj.pathname ? urlObj.pathname + path : path, query: this.getQueryObj(query) }); @@ -207,7 +207,7 @@ export default class Run extends Component { file: bodyType === 'file' ? 'single-file' : null, success: (res, header) => { try { - if(isJsonData(header)){ + if (isJsonData(header)) { res = json_parse(res); } @@ -243,9 +243,9 @@ export default class Run extends Component { }, error: (err, header) => { try { - if(isJsonData(header)){ + if (isJsonData(header)) { err = json_parse(err); - } + } } catch (e) { message.error(e.message) } @@ -554,20 +554,24 @@ export default class Run extends Component { }
- + 请求部分 } noHovering className="req-part">
+ + + +
} key="3" - className={HTTP_METHOD[method].request_body?'POST':'hidden'} + className={HTTP_METHOD[method].request_body ? 'POST' : 'hidden'} > -
-
+
+
{ HTTP_METHOD[method].request_body && bodyType === 'form' &&
- { + { bodyForm.map((item, index) => { return (
From bdfa5a62bdb392f001abba8bfc236976ddc1e0e5 Mon Sep 17 00:00:00 2001 From: suxiaoxin Date: Mon, 18 Sep 2017 07:08:52 +0800 Subject: [PATCH 4/8] chore: add version num --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2245163a..7a45f5c3 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yapi", - "version": "1.0.0", + "version": "1.0.1", "description": "YAPI", "main": "index.js", "scripts": { From 0e707e4520c403c39c6df279d860c1b969ee9049 Mon Sep 17 00:00:00 2001 From: suxiaoxin Date: Mon, 18 Sep 2017 10:18:34 +0800 Subject: [PATCH 5/8] =?UTF-8?q?fix:=20=E6=8E=A5=E5=8F=A3=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=A4=87=E6=B3=A8=E4=BF=A1=E6=81=AF=E6=B2=A1=E6=9C=89=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E5=88=B0bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Project/Interface/InterfaceList/InterfaceEditForm.js | 1 + 1 file changed, 1 insertion(+) diff --git a/client/containers/Project/Interface/InterfaceList/InterfaceEditForm.js b/client/containers/Project/Interface/InterfaceList/InterfaceEditForm.js index 10a00197..9e4a1554 100755 --- a/client/containers/Project/Interface/InterfaceList/InterfaceEditForm.js +++ b/client/containers/Project/Interface/InterfaceList/InterfaceEditForm.js @@ -198,6 +198,7 @@ class InterfaceEditForm extends Component { let editor = this.editor = new Editor('#desc'); editor.create(); + editor.txt.html(this.state.desc) } addParams = (name, data) => { From 92f796408def7c3c50b353b155c369f16dde1c6b Mon Sep 17 00:00:00 2001 From: suxiaoxin Date: Mon, 18 Sep 2017 11:32:15 +0800 Subject: [PATCH 6/8] =?UTF-8?q?opti:=20interface=20edit=20desc=20input=20?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=20textarea?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Interface/InterfaceList/InterfaceEditForm.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client/containers/Project/Interface/InterfaceList/InterfaceEditForm.js b/client/containers/Project/Interface/InterfaceList/InterfaceEditForm.js index 9e4a1554..a65b93cf 100755 --- a/client/containers/Project/Interface/InterfaceList/InterfaceEditForm.js +++ b/client/containers/Project/Interface/InterfaceList/InterfaceEditForm.js @@ -282,7 +282,7 @@ class InterfaceEditForm extends Component { {getFieldDecorator('req_query[' + index + '].desc', { initialValue: data.desc })( - + )} @@ -309,14 +309,14 @@ class InterfaceEditForm extends Component { {getFieldDecorator('req_headers[' + index + '].value', { initialValue: data.value })( - + )} {getFieldDecorator('req_headers[' + index + '].desc', { initialValue: data.desc })( - + )} @@ -359,7 +359,7 @@ class InterfaceEditForm extends Component { {getFieldDecorator('req_body_form[' + index + '].desc', { initialValue: data.desc })( - + )} @@ -381,7 +381,7 @@ class InterfaceEditForm extends Component { {getFieldDecorator('req_params[' + index + '].desc', { initialValue: data.desc })( - + )} From 7cd34ccdb1364add6de89b4126319b2b83a58e7a Mon Sep 17 00:00:00 2001 From: zwjamnsss Date: Mon, 18 Sep 2017 13:46:15 +0800 Subject: [PATCH 7/8] =?UTF-8?q?opti:=20=E4=BC=98=E5=8C=96=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=88=97=E8=A1=A8=20tab?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Project/Interface/interface.scss | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/client/containers/Project/Interface/interface.scss b/client/containers/Project/Interface/interface.scss index 906eb46e..bec79253 100755 --- a/client/containers/Project/Interface/interface.scss +++ b/client/containers/Project/Interface/interface.scss @@ -8,24 +8,34 @@ // .item-all-interface { // background-color: red; // } - .ant-tabs-bar{ - border-bottom: none; - margin-bottom: 0 - } + // .ant-tabs-bar{ + // border-bottom: none; + // margin-bottom: 0 + // } .ant-tabs-nav{ width:100%; - background-color: #ececec } .ant-tabs-tab{ min-width: 50%; } .ant-tabs.ant-tabs-card > .ant-tabs-bar .ant-tabs-tab{ - background-color: #fff; + height: 39px; + background: #fff; + border: 1px solid #d9d9d9; + border-bottom: 0; + } + .ant-tabs.ant-tabs-card > .ant-tabs-bar .ant-tabs-tab:nth-of-type(2) { + border-left: 0; + } + .ant-tabs.ant-tabs-card > .ant-tabs-bar .ant-tabs-tab:last-of-type { + border-right: 0; } .ant-tabs.ant-tabs-card > .ant-tabs-bar .ant-tabs-tab-active{ + height: 40px; background-color: #efefef; color:#021b2d; font-weight: 500; + // margin-bottom: 0; } .ant-tabs.ant-tabs-card > .ant-tabs-bar .ant-tabs-nav-container{ @@ -34,13 +44,13 @@ .ant-tabs.ant-tabs-card > .ant-tabs-bar{ text-align: center; - line-height: 40px; - height:40px; + background: #ececec; } .ant-tabs-nav-wrap{ height: 40px; line-height: 31px; + // border-bottom: 1px solid #d9d9d9; } .ant-input { width: 100%; From 2b2c82b1ce379e112bad3db38d890186c34d9f18 Mon Sep 17 00:00:00 2001 From: suxiaoxin Date: Tue, 19 Sep 2017 13:22:36 +0800 Subject: [PATCH 8/8] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81query=20path?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/controllers/interface.js | 45 +++++++++++++++++++--------- server/middleware/mockServer.js | 52 ++++++++++++++++++++++++++++----- server/models/interface.js | 15 ++++++++++ 3 files changed, 91 insertions(+), 21 deletions(-) diff --git a/server/controllers/interface.js b/server/controllers/interface.js index 4556048a..f9e53293 100755 --- a/server/controllers/interface.js +++ b/server/controllers/interface.js @@ -79,20 +79,22 @@ class interfaceController extends baseController { let http_path = url.parse(params.path, true); - params.path = http_path.pathname; if (!yapi.commons.verifyPath(http_path.pathname)) { return ctx.body = yapi.commons.resReturn(null, 400, '接口path第一位必须是/,最后一位不能为/'); } - if (!params.req_query) { - params.req_query = []; - Object.keys(http_path.query).forEach((item) => { - params.req_query.push({ - name: item - }) + + params.query_path = {}; + params.query_path.path = http_path.pathname; + params.query_path.params = []; + Object.keys(http_path.query).forEach((item) => { + params.query_path.params.push({ + name: item, + value: http_path.query[item] }) - } + }) + let checkRepeat = await this.Model.checkRepeat(params.project_id, params.path, params.method); @@ -109,6 +111,7 @@ class interfaceController extends baseController { path: params.path, desc: params.desc, method: params.method, + query_path: params.query_path, req_headers: params.req_headers, req_body_type: params.req_body_type, res_body: params.res_body, @@ -118,11 +121,11 @@ class interfaceController extends baseController { up_time: yapi.commons.time() }; - if (params.req_query) { + if (!_.isUndefined(params.req_query)) { data.req_query = params.req_query; } - if (params.req_body_form) { + if (!_.isUndefined(params.req_body_form)) { data.req_body_form = params.req_body_form; } @@ -147,7 +150,7 @@ class interfaceController extends baseController { } else { data.type = 'static' } - if (params.req_body_other) { + if (!_.isUndefined(params.req_body_other)) { data.req_body_other = params.req_body_other; } @@ -350,10 +353,24 @@ class interfaceController extends baseController { return ctx.body = yapi.commons.resReturn(null, 400, '没有权限'); } - if (params.path && !yapi.commons.verifyPath(params.path)) { + + + let http_path = url.parse(params.path, true); + + if (!yapi.commons.verifyPath(http_path.pathname)) { return ctx.body = yapi.commons.resReturn(null, 400, '接口path第一位必须是/,最后一位不能为/'); } + params.query_path = {}; + params.query_path.path = http_path.pathname; + params.query_path.params = []; + Object.keys(http_path.query).forEach((item) => { + params.query_path.params.push({ + name: item, + value: http_path.query[item] + }) + }) + if (params.path && (params.path !== interfaceData.path || params.method !== interfaceData.method)) { let checkRepeat = await this.Model.checkRepeat(interfaceData.project_id, params.path, params.method); if (checkRepeat > 0) { @@ -362,7 +379,8 @@ class interfaceController extends baseController { } let data = { - up_time: yapi.commons.time() + up_time: yapi.commons.time(), + query_path: params.query_path }; if (!_.isUndefined(params.path)) { @@ -400,6 +418,7 @@ class interfaceController extends baseController { if (!_.isUndefined(params.req_query)) { data.req_query = params.req_query; } + if (!_.isUndefined(params.req_body_other)) { data.req_body_other = params.req_body_other; } diff --git a/server/middleware/mockServer.js b/server/middleware/mockServer.js index 64e03a11..6895bf84 100755 --- a/server/middleware/mockServer.js +++ b/server/middleware/mockServer.js @@ -8,6 +8,7 @@ const Mock = require('mockjs'); function matchApi(apiPath, apiRule) { let apiRules = apiRule.split("/"); + let apiPaths = apiPath.split("/"); if (apiPaths.length !== apiRules.length) { return false; } @@ -59,20 +60,51 @@ module.exports = async (ctx, next) => { try { newpath = path.substr(project.basepath.length); interfaceData = await interfaceInst.getByPath(project._id, newpath, ctx.method); + + //处理query_path情况 if (!interfaceData || interfaceData.length === 0) { - //非正常跨域预检请求回应 - if (ctx.method === 'OPTIONS') { - ctx.set("Access-Control-Allow-Origin", "*") - ctx.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE") - return ctx.body = 'ok' - } - let newData = await interfaceInst.getVar(project._id, ctx.method); + interfaceData = await interfaceInst.getByQueryPath(project._id, newpath, ctx.method); + let i, l, j, len, curQuery, match = false; + for (i = 0, l = interfaceData.length; i < l; i++) { + match = false; + currentInterfaceData = interfaceData[i]; + curQuery = currentInterfaceData.query_path; + if (!curQuery || typeof curQuery !== 'object' || !curQuery.path) { + continue; + } + for (j = 0, len = curQuery.params.length; j < len; j++) { + if (ctx.query[curQuery.params[j].name] !== curQuery.params[j].value) { + continue; + } + if(j === len -1){ + match = true; + } + } + if (match) { + interfaceData = [currentInterfaceData]; + break; + } + if(i === l -1){ + interfaceData = []; + } + } + } + + //处理动态路由 + if (!interfaceData || interfaceData.length === 0) { + let newData = await interfaceInst.getVar(project._id, ctx.method); let findInterface = _.find(newData, (item) => { return matchApi(newpath, item.path) }); if (!findInterface) { + //非正常跨域预检请求回应 + if (ctx.method === 'OPTIONS') { + ctx.set("Access-Control-Allow-Origin", "*") + ctx.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE") + return ctx.body = 'ok' + } return ctx.body = yapi.commons.resReturn(null, 404, '不存在的api'); } interfaceData = [ @@ -82,10 +114,14 @@ module.exports = async (ctx, next) => { } if (interfaceData.length > 1) { + + return ctx.body = yapi.commons.resReturn(null, 405, '存在多个api,请检查数据库'); + } else { + interfaceData = interfaceData[0]; } - interfaceData = interfaceData[0]; + ctx.set("Access-Control-Allow-Origin", "*") if (interfaceData.res_body_type === 'json') { try { diff --git a/server/models/interface.js b/server/models/interface.js index 69314498..32e4a4d9 100755 --- a/server/models/interface.js +++ b/server/models/interface.js @@ -20,6 +20,12 @@ class interfaceModel extends baseModel { add_time: Number, up_time: Number, type: {type: String, enum: ['static', 'var'], default:'static'}, + query_path: { + path: String, + params: [{ + name: String, value: String + }], + }, req_query:[{ name: String, value: String, desc: String, required: { type:String, @@ -83,6 +89,15 @@ class interfaceModel extends baseModel { }).select('_id path').exec() } + getByQueryPath(project_id, path, method) { + return this.model.find({ + project_id: project_id, + "query_path.path": path, + method: method + }) + .exec(); + } + getByPath(project_id, path, method) { return this.model.find({ project_id: project_id,