Commit e9e99dc8 authored by 苏文雄's avatar 苏文雄

Merge branch 'master' of https://github.com/YMFE/yapi

parents a526a1c7 396fb48c
## YApi 可视化接口管理平台
示例站点:
<p><a target="_blank" href="http://yapi.demo.qunar.com">yapi.demo.qunar.com</a></p>
文档:
<p><a target="_blank" href="https://hellosean1025.github.io/yapi">hellosean1025.github.io/yapi</a></p>
......@@ -83,6 +80,7 @@ YApi 是<strong>高效</strong>、<strong>易用</strong>、<strong>功能强大
* [使用DockerCompose构建部署Yapi](https://github.com/MyHerux/daily-code/blob/master/Program/%E5%B7%A5%E5%85%B7%E7%AF%87/Yapi/%E4%BD%BF%E7%94%A8DockerCompose%E6%9E%84%E5%BB%BA%E9%83%A8%E7%BD%B2Yapi.md)
### YApi 一些工具
* [Api Generator](https://github.com/Forgus/api-generator) 接口文档自动生成插件(零入侵)
* [mysql服务http工具,可配合做自动化测试](https://github.com/hellosean1025/http-mysql-server)
* [idea 一键上传接口到yapi插件](https://github.com/diwand/YapiIdeaUploadPlugin)
* [idea 接口上传调试插件 easy-yapi](https://easyyapi.com/)
......
......@@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { Table } from 'antd';
import json5 from 'json5';
import PropTypes from 'prop-types';
import { schemaTransformToTable } from '../../../common/shema-transformTo-table.js';
import { schemaTransformToTable } from '../../../common/schema-transformTo-table.js';
import _ from 'underscore';
import './index.scss';
......
const schema = require('./shema-transformTo-table.js');
const schema = require('./schema-transformTo-table.js');
const _ = require('underscore');
const json_parse = function(json) {
......
{
"port": "3000",
"adminAccount": "admin@admin.com",
"timeout":120000,
"db": {
"servername": "127.0.0.1",
"DATABASE": "yapi",
......
......@@ -26,7 +26,7 @@ npm run dev #启动开发服务器
可参考 项目vendors/exts 目录下的插件
在 vendors/node_modules 下新建 yapi-plugin-demo 目录和 npm init,最后生成的目录接口如下
在 vendors/node_modules 下新建 yapi-plugin-demo 目录和 npm init,最后生成的目录结构如下
```
yapi-plugin-demo
client.js //客户端入口文件
......
......@@ -167,7 +167,7 @@ class exportSwaggerController extends baseController {
name: p.name,
in: 'header',
description: `${p.name} (Only:${p.value})`,
required: p.required === 1,
required: Number(p.required) === 1,
type: 'string', //always be type string
default: p.value
});
......@@ -187,7 +187,7 @@ class exportSwaggerController extends baseController {
paramArray.push({
name: p.name,
in: 'query',
required: p.required === 1,
required: Number(p.required) === 1,
description: p.desc,
type: 'string' //always be type string
});
......@@ -200,7 +200,7 @@ class exportSwaggerController extends baseController {
paramArray.push({
name: p.name,
in: 'formData',
required: p.required === 1,
required: Number(p.required) === 1,
description: p.desc,
type: p.type === 'text' ? 'string' : 'file' //in this time .formData type have only text or file
});
......@@ -285,4 +285,4 @@ class exportSwaggerController extends baseController {
}
}
module.exports = exportSwaggerController;
\ No newline at end of file
module.exports = exportSwaggerController;
......@@ -82,7 +82,8 @@
"underscore": "1.8.3",
"url": "0.11.0",
"yapi-plugin-qsso": "^1.1.0",
"qs": "^6.7.0"
"qs": "^6.7.0",
"vm2": "^3.8.4"
},
"devDependencies": {
"antd": "3.2.2",
......@@ -212,4 +213,4 @@
],
"babel": "inherit"
}
}
}
\ No newline at end of file
......@@ -54,9 +54,14 @@ app.use(async (ctx, next) => {
await next();
});
app.use(koaStatic(yapi.path.join(yapi.WEBROOT, 'static'), { index: indexFile, gzip: true }));
app.listen(yapi.WEBCONFIG.port);
const server = app.listen(yapi.WEBCONFIG.port);
server.setTimeout(yapi.WEBCONFIG.timeout);
commons.log(
`服务已启动,请打开下面链接访问: \nhttp://127.0.0.1${
yapi.WEBCONFIG.port == '80' ? '' : ':' + yapi.WEBCONFIG.port
......
......@@ -161,6 +161,7 @@ class interfaceController extends baseController {
path: minLengthStringField,
method: minLengthStringField,
message: minLengthStringField,
switch_notice: 'boolean',
dataSync: 'string'
},
addAndUpCommonField
......@@ -326,7 +327,6 @@ class interfaceController extends baseController {
* @param {String} [desc] 接口描述
* @returns {Object}
*/
async save(ctx) {
let params = ctx.params;
......@@ -358,7 +358,7 @@ class interfaceController extends baseController {
let validParams = Object.assign({}, params)
let validResult = yapi.commons.validateParams(this.schemaMap['up'], validParams);
if (validResult.valid) {
let data = {};
let data = Object.assign({}, ctx);
data.params = validParams;
if(params.res_body_is_json_schema && params.dataSync === 'good'){
......@@ -624,7 +624,6 @@ class interfaceController extends baseController {
* @returns {Object}
* @example ./api/interface/up.json
*/
async up(ctx) {
let params = ctx.params;
......@@ -1022,7 +1021,6 @@ class interfaceController extends baseController {
* @returns {Object}
* @example ./api/interface/getCatMenu
*/
async getCatMenu(ctx) {
let project_id = ctx.params.project_id;
......@@ -1117,7 +1115,6 @@ class interfaceController extends baseController {
* @returns {Object}
* @example
*/
async upIndex(ctx) {
try {
let params = ctx.request.body;
......@@ -1151,7 +1148,6 @@ class interfaceController extends baseController {
* @returns {Object}
* @example
*/
async upCatIndex(ctx) {
try {
let params = ctx.request.body;
......@@ -1180,7 +1176,7 @@ class interfaceController extends baseController {
let required = ctx.request.body.required;
let res = yapi.commons.schemaToJson(schema, {
alwaysFakeOptionals: _.isUndefined(required) ? true : require
alwaysFakeOptionals: _.isUndefined(required) ? true : required
});
// console.log('res',res)
return (ctx.body = res);
......
......@@ -130,7 +130,7 @@ function mockValidator(interfaceData, ctx) {
if (noRequiredArr.length > 0 || (validResult && !validResult.valid)) {
let message = `错误信息:`;
message += noRequiredArr.length > 0 ? `缺少必须字段 ${noRequiredArr.join(',')} ` : '';
message += validResult && !validResult.valid ? `shema 验证请求参数 ${validResult.message}` : '';
message += validResult && !validResult.valid ? `schema 验证请求参数 ${validResult.message}` : '';
return {
valid: false,
......
......@@ -22,10 +22,10 @@ const jsf = require('json-schema-faker');
const { schemaValidator } = require('../../common/utils');
const http = require('http');
jsf.extend ('mock', function () {
jsf.extend('mock', function () {
return {
mock: function (xx) {
return Mock.mock (xx);
return Mock.mock(xx);
}
};
});
......@@ -45,9 +45,9 @@ const defaultOptions = {
// });
// });
exports.schemaToJson = function(schema, options = {}) {
exports.schemaToJson = function (schema, options = {}) {
Object.assign(options, defaultOptions);
jsf.option(options);
let result;
try {
......@@ -183,7 +183,7 @@ exports.sendMail = (options, cb) => {
cb =
cb ||
function(err) {
function (err) {
if (err) {
yapi.commons.log('send mail ' + options.to + ' error,' + err.message, 'error');
} else {
......@@ -253,7 +253,7 @@ exports.handleVarPath = (pathname, params) => {
}
}
}
pathname.replace(/\{(.+?)\}/g, function(str, match) {
pathname.replace(/\{(.+?)\}/g, function (str, match) {
insertParams(match);
});
};
......@@ -281,15 +281,22 @@ exports.verifyPath = path => {
* a = {a: 2}
*/
exports.sandbox = (sandbox, script) => {
const vm = require('vm');
sandbox = sandbox || {};
script = new vm.Script(script);
const context = new vm.createContext(sandbox);
script.runInContext(context, {
timeout: 3000
});
try {
const { NodeVM } = require('vm2');
sandbox = sandbox || {};
const vm = new NodeVM({
require: {
external: true
},
sandbox: sandbox,
timeout: 3000
})
return sandbox;
vm.run(script)
return sandbox
} catch (err) {
throw err
}
};
function trim(str) {
......@@ -421,7 +428,7 @@ exports.createAction = (router, baseurl, routerController, action, path, method,
await inst.init(ctx);
ctx.params = Object.assign({}, ctx.request.query, ctx.request.body, ctx.params);
if (inst.schemaMap && typeof inst.schemaMap === 'object' && inst.schemaMap[action]) {
let validResult = yapi.commons.validateParams(inst.schemaMap[action], ctx.params);
if (!validResult.valid) {
......@@ -453,7 +460,7 @@ function handleParamsValue(params, val) {
let value = {};
try {
params = params.toObject();
} catch (e) {}
} catch (e) { }
if (params.length === 0 || val.length === 0) {
return params;
}
......@@ -512,7 +519,7 @@ function convertString(variable) {
return variable.name + ': ' + variable.message;
}
try {
if(variable && typeof variable === 'string'){
if (variable && typeof variable === 'string') {
return variable;
}
return JSON.stringify(variable, null, ' ');
......@@ -541,34 +548,34 @@ exports.runCaseScript = async function runCaseScript(params, colId, interfaceId)
let result = {};
try {
if(colData.checkHttpCodeIs200){
if (colData.checkHttpCodeIs200) {
let status = +params.response.status;
if(status !== 200){
if (status !== 200) {
throw ('Http status code 不是 200,请检查(该规则来源于于 [测试集->通用规则配置] )')
}
}
if(colData.checkResponseField.enable){
if(params.response.body[colData.checkResponseField.name] != colData.checkResponseField.value){
if (colData.checkResponseField.enable) {
if (params.response.body[colData.checkResponseField.name] != colData.checkResponseField.value) {
throw (`返回json ${colData.checkResponseField.name} 值不是${colData.checkResponseField.value},请检查(该规则来源于于 [测试集->通用规则配置] )`)
}
}
if(colData.checkResponseSchema){
if (colData.checkResponseSchema) {
const interfaceInst = yapi.getInst(interfaceModel);
let interfaceData = await interfaceInst.get(interfaceId);
if(interfaceData.res_body_is_json_schema && interfaceData.res_body){
if (interfaceData.res_body_is_json_schema && interfaceData.res_body) {
let schema = JSON.parse(interfaceData.res_body);
let result = schemaValidator(schema, context.body)
if(!result.valid){
if (!result.valid) {
throw (`返回Json 不符合 response 定义的数据结构,原因: ${result.message}
数据结构如下:
${JSON.stringify(schema,null,2)}`)
${JSON.stringify(schema, null, 2)}`)
}
}
}
if(colData.checkScript.enable){
if (colData.checkScript.enable) {
let globalScript = colData.checkScript.content;
// script 是断言
if (globalScript) {
......@@ -610,7 +617,7 @@ exports.getUserdata = async function getUserdata(uid, role) {
};
// 处理mockJs脚本
exports.handleMockScript = function(script, context) {
exports.handleMockScript = function (script, context) {
let sandbox = {
header: context.ctx.header,
query: context.ctx.query,
......@@ -625,7 +632,7 @@ exports.handleMockScript = function(script, context) {
sandbox.cookie = {};
context.ctx.header.cookie &&
context.ctx.header.cookie.split(';').forEach(function(Cookie) {
context.ctx.header.cookie.split(';').forEach(function (Cookie) {
var parts = Cookie.split('=');
sandbox.cookie[parts[0].trim()] = (parts[1] || '').trim();
});
......@@ -640,8 +647,8 @@ exports.handleMockScript = function(script, context) {
exports.createWebAPIRequest = function(ops) {
return new Promise(function(resolve, reject) {
exports.createWebAPIRequest = function (ops) {
return new Promise(function (resolve, reject) {
let req = '';
let http_client = http.request(
{
......@@ -650,25 +657,25 @@ exports.createWebAPIRequest = function(ops) {
port: ops.port,
path: ops.path
},
function(res) {
res.on('error', function(err) {
function (res) {
res.on('error', function (err) {
reject(err);
});
res.setEncoding('utf8');
if (res.statusCode != 200) {
reject({message: 'statusCode != 200'});
reject({ message: 'statusCode != 200' });
} else {
res.on('data', function(chunk) {
res.on('data', function (chunk) {
req += chunk;
});
res.on('end', function() {
res.on('end', function () {
resolve(req);
});
}
}
);
http_client.on('error', (e) => {
reject({message: `request error: ${e.message}`});
reject({ message: `request error: ${e.message}` });
});
http_client.end();
});
......
......@@ -114,8 +114,8 @@ exports.ldapQuery = (username, password) => {
const searchStandard = ldapLogin.searchStandard;
// 处理可以自定义filter
let customFilter;
if (/^&/gi.test(searchStandard)) {
customFilter = util.format(searchStandard, username);
if (/^(&|\|)/gi.test(searchStandard)) {
customFilter = searchStandard.replace(/%s/g,username);
} else {
customFilter = `${searchStandard}=${username}`;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment