feat: 增加对大括号变量路径支持

This commit is contained in:
suxiaoxin 2017-12-07 10:05:16 +08:00
parent d557287efd
commit 6ea790636c
13 changed files with 142 additions and 43 deletions

View File

@ -1,3 +1,9 @@
### v1.2.9
#### Bug Fixed
1. Api 路径兼容 postman {varible}
### v1.2.8
#### Bug Fixed

View File

@ -13,4 +13,9 @@
.fullScreen {
overflow: hidden
}
.ace_editor.ace-xcode {
background-color: #f5f5f5;
color: #000000;
}

View File

@ -105,6 +105,7 @@ function handleParams(interfaceData, handleValue, requestParams) {
}
path = path.replace(`:${item.name}`, val || `:${item.name}`);
path = path.replace(`{${item.name}}`, val || `{${item.name}}`)
});

View File

@ -339,6 +339,15 @@ class InterfaceEditForm extends Component {
handlePath = (e) => {
let val = e.target.value, queue = [];
let insertParams =(name)=>{
let findExist = _.find(this.state.req_params, { name: name });
if (findExist) {
queue.push(findExist)
} else {
queue.push({ name: name, desc: '' })
}
}
val = handlePath(val)
this.props.form.setFieldsValue({
path: val
@ -348,15 +357,17 @@ class InterfaceEditForm extends Component {
for (i = 1; i < paths.length; i++) {
if (paths[i][0] === ':') {
name = paths[i].substr(1);
let findExist = _.find(this.state.req_params, { name: name });
if (findExist) {
queue.push(findExist)
} else {
queue.push({ name: name, desc: '' })
}
insertParams(name)
}
}
}
if(val && val.length > 3){
val.replace(/\{(.+?)\}/g, function(str, match){
insertParams(match)
})
}
this.setState({
req_params: queue
})
@ -595,6 +606,8 @@ class InterfaceEditForm extends Component {
const requestBodyList = this.state.req_body_form.map((item, index) => {
return requestBodyTpl(item, index)
})
const DEMOPATH= '/api/user/{id}'
return (
<Form onSubmit={this.handleSubmit}>
@ -639,7 +652,7 @@ class InterfaceEditForm extends Component {
<span>
接口路径&nbsp;
<Tooltip title={<div>
<p>1. 支持动态路由,例如:/api/user/:id</p>
<p>1. 支持动态路由,例如:{DEMOPATH}</p>
<p>2. 支持 ?controller=xxx 的QueryRouter,非router的Query参数请定义到 Request设置-&#62;Query</p>
</div>}>
<Icon type="question-circle-o" style={{ width: "10px" }} />

View File

@ -75,12 +75,7 @@ function postman(importDataModule){
if(!path) return '';
path = path.replace(/{{\w*}}/g, '');
path = path.replace(/{(\w*)}/,function(data, match){
if(match){
return ':' + match;
}
return '';
});
if(path[0] != "/"){
path = "/" + path;
}

View File

@ -69,12 +69,7 @@ function postman(importDataModule){
if(!path) return '';
path = path.replace(/{{\w*}}/g, '');
path = path.replace(/{(\w*)}/,function(data, match){
if(match){
return ':' + match;
}
return '';
});
if(path[0] != "/"){
path = "/" + path;
}

View File

@ -7,7 +7,6 @@ var jsf = require('common/json-schema-mockjs');
function improtData(importDataModule){
var SwaggerData;
function handlePath(path){
path = path.replace(/{(\w*)}/,":$1");
if(path.charAt(0) != "/"){
path = "/" + path;
}

View File

@ -128,21 +128,7 @@ class interfaceController extends baseController {
if (!_.isUndefined(params.req_body_form)) {
data.req_body_form = params.req_body_form;
}
if (params.path.indexOf(":") > 0) {
let paths = params.path.split("/"), name, i;
for (i = 1; i < paths.length; i++) {
if (paths[i][0] === ':') {
name = paths[i].substr(1);
if (!_.find(params.req_params, { name: name })) {
params.req_params.push({
name: name,
desc: ''
})
}
}
}
}
yapi.commons.handleVarPath(params.path, params.req_params);
if (params.req_params.length > 0) {
data.type = 'var'

View File

@ -28,7 +28,7 @@ class projectController extends baseController {
if (basepath === '/') return "";
if (basepath[0] !== '/') basepath = '/' + basepath;
if (basepath[basepath.length - 1] === '/') basepath = basepath.substr(0, basepath.length - 1);
if (!yapi.commons.verifyPath(basepath)) {
if (!/^\/[a-zA-Z0-9\-\/_]+$/.test(basepath)) {
return false;
}
return basepath;
@ -42,6 +42,8 @@ class projectController extends baseController {
return false;
}
/**
* 添加项目分组
* @interface /project/add

View File

@ -22,13 +22,29 @@ function matchApi(apiPath, apiRule) {
apiRules[i] = apiRules[i].trim();
}else{
continue;
}
if (apiRules[i].indexOf(":") !== 0) {
}
if(apiRules[i].length > 2 && apiRules[i][0] === '{' && apiRules[i][apiRules[i].length - 1] === '}'){
pathRules[apiRules[i].substr(1, apiRules[i].length - 2)] = apiPaths[i];
}else if (apiRules[i].indexOf(":") === 0) {
pathRules[apiRules[i].substr(1)] = apiPaths[i]
}else if(apiRules[i].length > 2 && apiRules[i].indexOf('{') > -1 && apiRules[i].indexOf('}') > -1){
let params = [];
apiRules[i] = apiRules[i].replace(/\{(.+?)\}/g, function(src, match){
params.push(match);
return '(.+?)';
})
apiRules[i] = new RegExp(apiRules[i]);
if(!apiRules[i].test(apiPaths[i])){
return false;
}
let matchs = apiPaths[i].match(apiRules[i]);
params.forEach((item,index)=>{
pathRules[item] = matchs[index+1];
})
}else {
if (apiRules[i] !== apiPaths[i]) {
return false;
}
} else {
pathRules[apiRules[i].substr(1)] = apiPaths[i]
}
}
return pathRules;

View File

@ -4,6 +4,7 @@ const yapi = require('../yapi.js');
const sha1 = require('sha1');
const logModel = require('../models/log.js');
const json5 = require('json5');
const _ = require('underscore');
exports.resReturn = (data, num, errmsg) => {
num = num || 0;
@ -160,12 +161,38 @@ exports.filterRes = (list, rules) => {
});
};
exports.handleVarPath = (pathname, params)=>{
function insertParams(name){
if (!_.find(params, { name: name })) {
params.push({
name: name,
desc: ''
})
}
}
if(!pathname) return;
if(pathname.indexOf(':') !== -1){
let paths = pathname.split("/"), name, i;
for (i = 1; i < paths.length; i++) {
if (paths[i] && paths[i][0] === ':') {
name = paths[i].substr(1);
insertParams(name)
}
}
}
pathname.replace(/\{(.+?)\}/g, function(str, match){
insertParams(match)
})
}
/**
* 验证一个 path 是否合法
* path第一位必需为 /, path 只允许由 字母数字-/_:.
* path第一位必需为 /, path 只允许由 字母数字-/_:.{}=
*/
exports.verifyPath = (path) => {
if (/^\/[a-zA-Z0-9\-\/_:\.\!]+$/.test(path)) {
if (/^\/[a-zA-Z0-9\-\/_:\.\{\}\=]+$/.test(path)) {
return true;
} else {
return false;

View File

@ -5,7 +5,8 @@ import {
trim,
handleParams,
verifyPath,
sandbox
sandbox,
handleVarPath
} from '../../server/utils/commons.js';
test('trim', t => {
@ -46,4 +47,40 @@ test('sandbox', t=>{
t.deepEqual(sandbox({
a: 1
}, 'a=2'), {a : 2});
})
test('handleVarPath', t=>{
let result = [];
let pathname = '/a/:id'
handleVarPath(pathname, result);
t.deepEqual(result, [{
name: 'id',
desc: ''
}])
})
test('handleVarPath2', t=>{
let result = [];
let pathname = '/a/{id}'
handleVarPath(pathname, result);
t.deepEqual(result, [{
name: 'id',
desc: ''
}])
})
test('handleVarPath4', t=>{
let result = [];
let pathname = '/a/id={id}/tt/:sub/kk'
handleVarPath(pathname, result);
t.deepEqual(result, [{
name: 'sub',
desc: ''
}, {
name: 'id',
desc: ''
}])
})

View File

@ -20,5 +20,22 @@ test('matchApi', t => {
t.truthy(matchApi('/user/a/ttt/b', apiRule_3));
t.false(matchApi('/user/a/ttt2/b', apiRule_3))
const apiRule_4 = '/user/{aaa}/ttt/{bbbb}';
t.truthy(matchApi('/user/a/ttt/b', apiRule_4));
t.false(matchApi('/user/a/ttt2/b', apiRule_4))
const apiRule_5 = '/user/{aaa}/ttt/{bbbb}';
let r5 = matchApi('/user/a/ttt/b', apiRule_5);
t.deepEqual(r5, {
aaa: 'a',
bbbb: 'b'
});
const apiRule_6 = '/user/a1={aaa}/ttt/b1={bbbb}';
let r6 = matchApi('/user/a1=a/ttt/b1=b', apiRule_6);
t.deepEqual(r6, {
aaa: 'a',
bbbb: 'b'
});
});