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