interface module

This commit is contained in:
sean 2017-07-10 20:02:44 +08:00
parent fb58f369dc
commit e83d42a673
20 changed files with 412 additions and 55 deletions

36
doc/build/api.html vendored
View File

@ -1131,8 +1131,28 @@
<tr>
<td>env</td>
<td>Array</td>
<td>项目环境配置</td>
<td>
</td>
<td></td>
</tr>
<tr>
<td>env[].name</td>
<td>String</td>
<td>JSON字符串,例如{"local": "http://www.api.com"}</td>
<td>环境名称</td>
<td>
</td>
<td></td>
</tr>
<tr>
<td>env[].host</td>
<td>String</td>
<td>环境域名</td>
<td>
</td>
@ -1144,7 +1164,19 @@
<div>示例:</div>
<pre class="ydoc-example" data-foldnumber=10><code><span class="token punctuation">{</span>
<pre class="ydoc-example" data-foldnumber=10><code>
<span class="token comment" spellcheck="true">//请求示例</span>
<span class="token punctuation">{</span>
<span class="token string">"id"</span><span class="token punctuation">:</span> <span class="token number">8</span><span class="token punctuation">,</span>
<span class="token string">"env"</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span>
<span class="token string">"name"</span><span class="token punctuation">:</span> <span class="token string">"本地开发环境"</span><span class="token punctuation">,</span>
<span class="token string">"domain"</span><span class="token punctuation">:</span> <span class="token string">"http://api.quar.com"</span>
<span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string">"desc"</span><span class="token punctuation">:</span> <span class="token string">"yapi项目"</span>
<span class="token punctuation">}</span>
<span class="token comment" spellcheck="true">//返回示例</span>
<span class="token punctuation">{</span>
<span class="token string">"errcode"</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token string">"errmsg"</span><span class="token punctuation">:</span> <span class="token string">"success"</span><span class="token punctuation">,</span>
<span class="token string">"data"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>

View File

@ -248,7 +248,9 @@ class projectController extends baseController {
* @param {String} basepath 项目基本路径,不能为空
* @param {String} prd_host 项目线上域名不能为空。可通过配置的域名访问到mock数据
* @param {String} [desc] 项目描述
* @param {String} [env] JSON字符串,例如{"local": "http://www.api.com"}
* @param {Array} [env] 项目环境配置
* @param {String} [env[].name] 环境名称
* @param {String} [env[].host] 环境域名
* @returns {Object}
* @example ./api/project/up.json
*/

View File

@ -1,3 +1,15 @@
//
{
"id": 8,
"env": [{
"name": "本地开发环境",
"domain": "http://api.quar.com"
}],
"desc": "yapi项目"
}
//
{
"errcode": 0,
"errmsg": "success",

View File

@ -25,6 +25,7 @@
"koa-session-minimal": "^3.0.3",
"koa-static": "^3.0.0",
"koa-views": "^5.2.0",
"mockjs": "^1.0.1-beta3",
"mongoose": "4.10.8",
"mongoose-auto-increment": "^5.0.1"
},

View File

@ -6,7 +6,7 @@ yapi.commons = commons;
import dbModule from './utils/db.js';
import userauth from './middleware/userauth.js'
import mockServer from './middleware/mockServer.js'
import Koa from 'koa'
import convert from 'koa-convert'
@ -17,7 +17,7 @@ import router from './router.js'
yapi.connect = dbModule.connect()
const app = new Koa()
app.use(userauth)
app.use(mockServer)
app.use(bodyParser())
app.use(router.routes())
app.use(router.allowedMethods())

View File

@ -1,5 +1,6 @@
{
"port": "3000",
"webhost": "127.0.0.1",
"db": {
"servername": "127.0.0.1",
"DATABASE": "yapi",

View File

@ -1,5 +1,6 @@
{
"port":"80",
"webhost": "127.0.0.1",
"db": {
"servername": "127.0.0.1",
"DATABASE": "yapi",

View File

@ -1,6 +1,7 @@
import groupModel from '../models/group.js'
import yapi from '../yapi.js'
import baseController from './base.js'
import projectModel from '../models/project.js'
//
class groupController extends baseController{
@ -83,7 +84,16 @@ class groupController extends baseController{
async del(ctx){
try{
var groupInst = yapi.getInst(groupModel);
let id = ctx.request.body.id;
var projectInst = yapi.getInst(projectModel);
let id = ctx.request.body.id;
if(!id){
return ctx.body = yapi.commons.resReturn(null, 402, 'id不能为空');
}
let count = projectInst.countByGroupId(id);
if(count > 0){
return ctx.body = yapi.commons.resReturn(null, 403, '请先删除该分组下的项目');
}
let result = await groupInst.del(id);
ctx.body = yapi.commons.resReturn(result)
}catch(err){

View File

@ -1,6 +1,7 @@
import projectModel from '../models/project.js'
import yapi from '../yapi.js'
import baseController from './base.js'
import interfaceModel from '../models/interface.js'
class projectController extends baseController {
@ -200,11 +201,17 @@ class projectController extends baseController {
if(!id){
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
}
let interfaceInst = yapi.getInst(interfaceModel);
let count = await interfaceInst.countByProjectId(id);
if(count > 0){
return ctx.body = yapi.commons.resReturn(null, 400, '请先删除该项目下所有接口');
}
if(await this.jungeProjectAuth(id) !== true){
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
let result = await this.Model.del(id);
ctx.body = yapi.commons.resReturn(result)
ctx.body = yapi.commons.resReturn(result);
}catch(err){
ctx.body = yapi.commons.resReturn(null, 402, e.message)
}
@ -221,7 +228,9 @@ class projectController extends baseController {
* @param {String} basepath 项目基本路径不能为空
* @param {String} prd_host 项目线上域名不能为空可通过配置的域名访问到mock数据
* @param {String} [desc] 项目描述
* @param {String} [env] JSON字符串,例如{"local": "http://www.api.com"}
* @param {Array} [env] 项目环境配置
* @param {String} [env[].name] 环境名称
* @param {String} [env[].host] 环境域名
* @returns {Object}
* @example ./api/project/up.json
*/

View File

@ -1,7 +1,64 @@
import yapi from '../yapi.js';
import projectModel from '../models/project.js'
import interfaceModel from '../models/interface.js'
import Mock from 'mockjs'
module.exports = async (ctx, next) => {
let hostname = ctx.hostname
yapi.commons.log('mock Server running...')
let hostname = ctx.protocol + "://" + ctx.hostname;
let config = yapi.WEBCONFIG;
if(hostname === config.webhost){
if(next) await next();
return true;
}
let projectInst = yapi.getInst(projectModel), projects;
try{
projects = await projectInst.getByDomain(hostname);
}catch(e){
return ctx.body = yapi.commons.resReturn(null, 403, e.message);
}
let matchProject = [];
for(let i=0, l = projects.length; i< l; i++){
let project = projects[i];
if(ctx.path && ctx.path.indexOf(project.basepath) === 0 && project.basepath[project.basepath.length -1] === '/'){
matchProject.push(project);
}
}
if(matchProject.length === 0){
return ctx.body = yapi.commons.resReturn(null, 400, '不存在的domain');
}
if(matchProject.length > 1){
return ctx.body = yapi.commons.resReturn(null, 401, '存在多个project,请检查数据库');
}
let project = matchProject[0], interfaceData;
let interfaceInst = yapi.getInst(interfaceModel);
try{
interfaceData = await interfaceInst.getByPath(project._id, ctx.path.substr(project.basepath.length));
if(!interfaceData || interfaceData.length === 0){
return ctx.body = yapi.commons.resReturn(null, 404, '不存在的api');
}
if(interfaceData.length > 1){
return ctx.body = yapi.commons.resReturn(null, 405, '存在多个api请检查数据库');
}
interfaceData = interfaceData[0];
if(interfaceData.res_body_type === 'json'){
return ctx.body = Mock.mock(
yapi.commons.json_parse(interfaceData.res_body)
);
}
return ctx.body = interfaceData.res_body;
}catch(e){
return ctx.body = yapi.commons.resReturn(null, 409, e.message);
}
if(next) await next();
}

View File

@ -9,7 +9,12 @@ class interfaceModel extends baseModel{
getSchema(){
return {
uid: {type: Number, required: true},
path: {type: String, required: true},
path: {type: String, required: true, validate: {
validator: (v) => {
return v && v[0] !== '/';
},
message: '接口路径第一位不能是/'
}},
method: {type: String, required: true},
project_id: {type: Number, required: true},
desc: String,
@ -46,6 +51,13 @@ class interfaceModel extends baseModel{
}).exec()
}
getByPath(project_id, path){
return this.model.find({
project_id: project_id,
path: path
}).exec()
}
checkRepeat(path, method){
return this.model.count({
path: path,
@ -53,7 +65,11 @@ class interfaceModel extends baseModel{
})
}
countByProjectId(id){
return this.model.count({
project_id: id
})
}
list (group_id){
return this.model.find({

View File

@ -10,12 +10,19 @@ class projectModel extends baseModel{
return {
uid: {type: Number, required: true},
name: {type: String, required: true},
basepath: {type: String, required: true},
basepath: {type: String, required: true, validate: {
validator: (v) => {
return v && v[v.length - 1] === '/'
},
message: 'basepath字符串结尾必须是/'
}},
desc: String,
group_id: {type: Number, required: true},
members: Array,
prd_host: {type: String, required: true},
env: Object,
env: [
{name: String, domain: String}
],
add_time: Number,
up_time: Number
}
@ -33,6 +40,12 @@ class projectModel extends baseModel{
}).exec()
}
getByDomain(domain){
return this.model.find({
prd_host: domain
}).exec()
}
checkNameRepeat(name){
return this.model.count({
name: name
@ -53,6 +66,12 @@ class projectModel extends baseModel{
}).exec()
}
countByGroupId(group_id){
return this.model.count({
group_id: group_id
})
}
del(id){
return this.model.deleteOne({
_id: id
@ -66,7 +85,6 @@ class projectModel extends baseModel{
}
addMember(id, uid){
console.log(id, uid)
return this.model.update({
_id: id
}, {

View File

@ -12,9 +12,9 @@ var _db = require('./utils/db.js');
var _db2 = _interopRequireDefault(_db);
var _userauth = require('./middleware/userauth.js');
var _mockServer = require('./middleware/mockServer.js');
var _userauth2 = _interopRequireDefault(_userauth);
var _mockServer2 = _interopRequireDefault(_mockServer);
var _koa = require('koa');
@ -43,7 +43,7 @@ _yapi2.default.commons = _commons2.default;
_yapi2.default.connect = _db2.default.connect();
var app = new _koa2.default();
app.use(_userauth2.default);
app.use(_mockServer2.default);
app.use((0, _koaBodyparser2.default)());
app.use(_router2.default.routes());
app.use(_router2.default.allowedMethods());

View File

@ -1,5 +1,6 @@
{
"port": "3000",
"webhost": "127.0.0.1",
"db": {
"servername": "127.0.0.1",
"DATABASE": "yapi",

View File

@ -1,5 +1,6 @@
{
"port":"80",
"webhost": "127.0.0.1",
"db": {
"servername": "127.0.0.1",
"DATABASE": "yapi",

View File

@ -44,6 +44,10 @@ var _base = require('./base.js');
var _base2 = _interopRequireDefault(_base);
var _project = require('../models/project.js');
var _project2 = _interopRequireDefault(_project);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
//
@ -213,36 +217,56 @@ var groupController = function (_baseController) {
key: 'del',
value: function () {
var _ref3 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee3(ctx) {
var groupInst, id, result;
var groupInst, projectInst, id, count, result;
return _regenerator2.default.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
_context3.prev = 0;
groupInst = _yapi2.default.getInst(_group2.default);
projectInst = _yapi2.default.getInst(_project2.default);
id = ctx.request.body.id;
_context3.next = 5;
if (id) {
_context3.next = 6;
break;
}
return _context3.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 402, 'id不能为空'));
case 6:
count = projectInst.countByGroupId(id);
if (!(count > 0)) {
_context3.next = 9;
break;
}
return _context3.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 403, '请先删除该分组下的项目'));
case 9:
_context3.next = 11;
return groupInst.del(id);
case 5:
case 11:
result = _context3.sent;
ctx.body = _yapi2.default.commons.resReturn(result);
_context3.next = 12;
_context3.next = 18;
break;
case 9:
_context3.prev = 9;
case 15:
_context3.prev = 15;
_context3.t0 = _context3['catch'](0);
ctx.body = _yapi2.default.commons.resReturn(null, 402, e.message);
case 12:
case 18:
case 'end':
return _context3.stop();
}
}
}, _callee3, this, [[0, 9]]);
}, _callee3, this, [[0, 15]]);
}));
function del(_x3) {

View File

@ -40,6 +40,10 @@ var _base = require('./base.js');
var _base2 = _interopRequireDefault(_base);
var _interface = require('../models/interface.js');
var _interface2 = _interopRequireDefault(_interface);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var projectController = function (_baseController) {
@ -490,7 +494,7 @@ var projectController = function (_baseController) {
key: 'del',
value: function () {
var _ref6 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee6(ctx) {
var id, result;
var id, interfaceInst, count, result;
return _regenerator2.default.wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
@ -506,42 +510,57 @@ var projectController = function (_baseController) {
return _context6.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 400, '项目id不能为空'));
case 4:
_context6.next = 6;
interfaceInst = _yapi2.default.getInst(_interface2.default);
_context6.next = 7;
return interfaceInst.countByProjectId(id);
case 7:
count = _context6.sent;
if (!(count > 0)) {
_context6.next = 10;
break;
}
return _context6.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 400, '请先删除该项目下所有接口'));
case 10:
_context6.next = 12;
return this.jungeProjectAuth(id);
case 6:
case 12:
_context6.t0 = _context6.sent;
if (!(_context6.t0 !== true)) {
_context6.next = 9;
_context6.next = 15;
break;
}
return _context6.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 405, '没有权限'));
case 9:
_context6.next = 11;
case 15:
_context6.next = 17;
return this.Model.del(id);
case 11:
case 17:
result = _context6.sent;
ctx.body = _yapi2.default.commons.resReturn(result);
_context6.next = 18;
_context6.next = 24;
break;
case 15:
_context6.prev = 15;
case 21:
_context6.prev = 21;
_context6.t1 = _context6['catch'](0);
ctx.body = _yapi2.default.commons.resReturn(null, 402, e.message);
case 18:
case 24:
case 'end':
return _context6.stop();
}
}
}, _callee6, this, [[0, 15]]);
}, _callee6, this, [[0, 21]]);
}));
function del(_x6) {
@ -562,7 +581,9 @@ var projectController = function (_baseController) {
* @param {String} basepath 项目基本路径不能为空
* @param {String} prd_host 项目线上域名不能为空可通过配置的域名访问到mock数据
* @param {String} [desc] 项目描述
* @param {String} [env] JSON字符串,例如{"local": "http://www.api.com"}
* @param {Array} [env] 项目环境配置
* @param {String} [env[].name] 环境名称
* @param {String} [env[].host] 环境域名
* @returns {Object}
* @example ./api/project/up.json
*/

View File

@ -1,38 +1,151 @@
"use strict";
'use strict';
var _regenerator = require("babel-runtime/regenerator");
var _regenerator = require('babel-runtime/regenerator');
var _regenerator2 = _interopRequireDefault(_regenerator);
var _asyncToGenerator2 = require("babel-runtime/helpers/asyncToGenerator");
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
var _yapi = require('../yapi.js');
var _yapi2 = _interopRequireDefault(_yapi);
var _project2 = require('../models/project.js');
var _project3 = _interopRequireDefault(_project2);
var _interface = require('../models/interface.js');
var _interface2 = _interopRequireDefault(_interface);
var _mockjs = require('mockjs');
var _mockjs2 = _interopRequireDefault(_mockjs);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
module.exports = function () {
var _ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee(ctx, next) {
var hostname;
var hostname, config, projectInst, projects, matchProject, i, l, _project, project, interfaceData, interfaceInst;
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
hostname = ctx.hostname;
_yapi2.default.commons.log('mock Server running...');
hostname = ctx.protocol + "://" + ctx.hostname;
config = _yapi2.default.WEBCONFIG;
if (!next) {
_context.next = 4;
if (!(hostname === config.webhost)) {
_context.next = 8;
break;
}
_context.next = 4;
if (!next) {
_context.next = 7;
break;
}
_context.next = 7;
return next();
case 4:
case "end":
case 7:
return _context.abrupt('return', true);
case 8:
projectInst = _yapi2.default.getInst(_project3.default), projects = void 0;
_context.prev = 9;
_context.next = 12;
return projectInst.getByDomain(hostname);
case 12:
projects = _context.sent;
_context.next = 18;
break;
case 15:
_context.prev = 15;
_context.t0 = _context['catch'](9);
return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 403, _context.t0.message));
case 18:
matchProject = [];
for (i = 0, l = projects.length; i < l; i++) {
_project = projects[i];
if (ctx.path && ctx.path.indexOf(_project.basepath) === 0 && _project.basepath[_project.basepath.length - 1] === '/') {
matchProject.push(_project);
}
}
if (!(matchProject.length === 0)) {
_context.next = 22;
break;
}
return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 400, '不存在的domain'));
case 22:
if (!(matchProject.length > 1)) {
_context.next = 24;
break;
}
return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 401, '存在多个project,请检查数据库'));
case 24:
project = matchProject[0], interfaceData = void 0;
interfaceInst = _yapi2.default.getInst(_interface2.default);
_context.prev = 26;
_context.next = 29;
return interfaceInst.getByPath(project._id, ctx.path.substr(project.basepath.length));
case 29:
interfaceData = _context.sent;
if (!(!interfaceData || interfaceData.length === 0)) {
_context.next = 32;
break;
}
return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 404, '不存在的api'));
case 32:
if (!(interfaceData.length > 1)) {
_context.next = 34;
break;
}
return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 405, '存在多个api请检查数据库'));
case 34:
interfaceData = interfaceData[0];
if (!(interfaceData.res_body_type === 'json')) {
_context.next = 37;
break;
}
return _context.abrupt('return', ctx.body = _mockjs2.default.mock(_yapi2.default.commons.json_parse(interfaceData.res_body)));
case 37:
return _context.abrupt('return', ctx.body = interfaceData.res_body);
case 40:
_context.prev = 40;
_context.t1 = _context['catch'](26);
return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 409, _context.t1.message));
case 43:
case 'end':
return _context.stop();
}
}
}, _callee, undefined);
}, _callee, undefined, [[9, 15], [26, 40]]);
}));
return function (_x, _x2) {

View File

@ -48,7 +48,12 @@ var interfaceModel = function (_baseModel) {
value: function getSchema() {
return {
uid: { type: Number, required: true },
path: { type: String, required: true },
path: { type: String, required: true, validate: {
validator: function validator(v) {
return v && v[0] !== '/';
},
message: '接口路径第一位不能是/'
} },
method: { type: String, required: true },
project_id: { type: Number, required: true },
desc: String,
@ -85,6 +90,14 @@ var interfaceModel = function (_baseModel) {
_id: id
}).exec();
}
}, {
key: 'getByPath',
value: function getByPath(project_id, path) {
return this.model.find({
project_id: project_id,
path: path
}).exec();
}
}, {
key: 'checkRepeat',
value: function checkRepeat(path, method) {
@ -93,6 +106,13 @@ var interfaceModel = function (_baseModel) {
method: method
});
}
}, {
key: 'countByProjectId',
value: function countByProjectId(id) {
return this.model.count({
project_id: id
});
}
}, {
key: 'list',
value: function list(group_id) {

View File

@ -49,12 +49,17 @@ var projectModel = function (_baseModel) {
return {
uid: { type: Number, required: true },
name: { type: String, required: true },
basepath: { type: String, required: true },
basepath: { type: String, required: true, validate: {
validator: function validator(v) {
return v && v[v.length - 1] === '/';
},
message: 'basepath字符串结尾必须是/'
} },
desc: String,
group_id: { type: Number, required: true },
members: Array,
prd_host: { type: String, required: true },
env: Object,
env: [{ name: String, domain: String }],
add_time: Number,
up_time: Number
};
@ -72,6 +77,13 @@ var projectModel = function (_baseModel) {
_id: id
}).exec();
}
}, {
key: 'getByDomain',
value: function getByDomain(domain) {
return this.model.find({
prd_host: domain
}).exec();
}
}, {
key: 'checkNameRepeat',
value: function checkNameRepeat(name) {
@ -94,6 +106,13 @@ var projectModel = function (_baseModel) {
group_id: group_id
}).exec();
}
}, {
key: 'countByGroupId',
value: function countByGroupId(group_id) {
return this.model.count({
group_id: group_id
});
}
}, {
key: 'del',
value: function del(id) {
@ -112,7 +131,6 @@ var projectModel = function (_baseModel) {
}, {
key: 'addMember',
value: function addMember(id, uid) {
console.log(id, uid);
return this.model.update({
_id: id
}, {