1 |
|
2 | const _ = require('lodash');
|
3 | const jsonfile = require('jsonfile');
|
4 | const shell = require('shelljs');
|
5 | const ip = require('ip');
|
6 | const fs = require('fs');
|
7 |
|
8 | const debug = require('debug')('motif:swagger');
|
9 |
|
10 | class Swagger {
|
11 |
|
12 | constructor( context ) {
|
13 |
|
14 | this._context = context;
|
15 | this._config = context.config.get("swagger");
|
16 | }
|
17 |
|
18 | isMultipartData( params ) {
|
19 | let isMultipartData = false;
|
20 | _.forEach(params, (param) => {
|
21 | if (param.type === 'file') {
|
22 | isMultipartData = true;
|
23 | }
|
24 | });
|
25 | return;
|
26 | }
|
27 |
|
28 | paramInfo( param, typeIn ) {
|
29 |
|
30 | const paramInfo = {
|
31 | "name": param.name,
|
32 | "in": typeIn,
|
33 | "description": param.description || 'No description',
|
34 | "required": param.optional === true ? false : true,
|
35 | "type": param.type || "string"
|
36 |
|
37 | };
|
38 |
|
39 | if ( _.isArray(param.enum) ) {
|
40 | paramInfo.enum = param.enum;
|
41 | }
|
42 |
|
43 | return paramInfo;
|
44 | }
|
45 |
|
46 | pathInfo( route, info, isAdmin = false ) {
|
47 |
|
48 | const responseType = "application/json";
|
49 | const requestType = this.isMultipartData( route.params || [] )
|
50 | ? "multipart/form-data"
|
51 | : "application/x-www-form-urlencoded";
|
52 |
|
53 | const parameters = (route.params || []).map((param) => {
|
54 |
|
55 | const paramsTypeIn = ((route, param) => {
|
56 |
|
57 | if (route.path.indexOf(':' + param.name) !== -1) {
|
58 | return 'path';
|
59 | }
|
60 |
|
61 | if (route.method === 'put' || route.method === 'post') {
|
62 | return 'formData';
|
63 | }
|
64 |
|
65 | return 'query';
|
66 | })(route, param);
|
67 |
|
68 | debug( "paramsTypeIn", route.path, param.name, paramsTypeIn );
|
69 |
|
70 | return this.paramInfo(param, paramsTypeIn)
|
71 | });
|
72 |
|
73 | const tags = route.tags || [route.group];
|
74 | const isAdminAPI = tags.indexOf("admin") !== -1 || (route.permissions && route.permissions.indexOf("admin") !== -1);
|
75 |
|
76 | if (!isAdmin && isAdminAPI) {
|
77 | return null;
|
78 | }
|
79 | else if (isAdmin && !isAdminAPI) {
|
80 | return null;
|
81 | }
|
82 |
|
83 | const pathInfo = {
|
84 | "tags": tags,
|
85 | "summary": route.summary || '',
|
86 | "description": route.description || 'No description',
|
87 | "produces": [responseType],
|
88 | "consumes": [requestType],
|
89 | "parameters": parameters,
|
90 | "responses": {
|
91 | "200": {
|
92 | "description": "A JSON result",
|
93 | "content": {
|
94 | "application/json": {
|
95 | "schema": {
|
96 | "$ref": "#/definitions/Result"
|
97 | }
|
98 | }
|
99 | }
|
100 | }
|
101 | }
|
102 | };
|
103 |
|
104 | if ( route.permissions ) {
|
105 | pathInfo['security'] = [
|
106 | {"APIKeyHeader": []}
|
107 | ];
|
108 | }
|
109 |
|
110 | info[route.method] = pathInfo;
|
111 |
|
112 | return info;
|
113 | }
|
114 |
|
115 | buildPaths( routes, isAdmin = false ) {
|
116 | const routePaths = {};
|
117 |
|
118 | _.forEach(routes, (route) => {
|
119 |
|
120 |
|
121 | const routePath = (( routePath, params ) => {
|
122 |
|
123 | _.forEach(params, (param) => {
|
124 | routePath = routePath.replace(':' + param.name, '{' + param.name + '}')
|
125 | })
|
126 |
|
127 | return routePath;
|
128 | })( route.routePath, route.params );
|
129 |
|
130 | debug( "routePath", routePath );
|
131 |
|
132 | let pathInfo = this.pathInfo(route, routePaths[routePath] || {}, isAdmin);
|
133 | if (pathInfo) {
|
134 | routePaths[routePath] = pathInfo;
|
135 | }
|
136 | });
|
137 |
|
138 | return routePaths;
|
139 | }
|
140 |
|
141 | buildJSON( routes, isAdmin = false ) {
|
142 |
|
143 | const routePaths = this.buildPaths( routes, isAdmin );
|
144 | const host = this._config.host ? this._config.host : ip.address() + ":" + this._context.port;
|
145 |
|
146 | const json = {
|
147 | "swagger": "2.0",
|
148 | "info": {
|
149 | "title": this._config.title || "Motif API",
|
150 | "description": "Auto created swagger api document by motif",
|
151 | "version": this._config.version || "0.0.0"
|
152 | },
|
153 | "securityDefinitions": {
|
154 | "APIKeyHeader": {
|
155 | "type": "apiKey",
|
156 | "in": "header",
|
157 | "name": "x-access-token"
|
158 | }
|
159 | },
|
160 | "definitions": {
|
161 | "Result": {
|
162 | "type": "object",
|
163 | "properties": {
|
164 | "error": {
|
165 | "type": "string"
|
166 | },
|
167 | "status": {
|
168 | "type": "string",
|
169 | },
|
170 | "data": {
|
171 | "type": "object"
|
172 | }
|
173 | }
|
174 | }
|
175 | },
|
176 | "host": host,
|
177 | "basePath": "/",
|
178 | "schemes": [
|
179 | "http",
|
180 | "https"
|
181 | ],
|
182 | "paths": routePaths
|
183 | };
|
184 |
|
185 | return json;
|
186 | }
|
187 |
|
188 | jsonWriteAsync( path, json ) {
|
189 | return new Promise((resolve, reject) => {
|
190 | jsonfile.writeFile(path, json, function (err) {
|
191 | if (err) {
|
192 | console.error(`json ${path} create fail !!`);
|
193 | return reject(err)
|
194 | }
|
195 |
|
196 | resolve();
|
197 | });
|
198 | });
|
199 | }
|
200 | }
|
201 |
|
202 | module.exports = Swagger;
|