Skip to content

Commit 863a062

Browse files
committed
Added OpenAPI definition and Swagger UI
1 parent ba7c078 commit 863a062

File tree

10 files changed

+292
-5
lines changed

10 files changed

+292
-5
lines changed

package.json

+5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"scripts": {
99
"prebuild": "rm -rf ./build",
1010
"build": "tsc",
11+
"postbuild": "mkdir -p build/api/schemas && find src/ -type f -name '*.yaml' -exec cp '{}' build/api/schemas/ ';'",
1112
"start": "node build/main.js",
1213
"lint": "tslint './{src,test}/**/*.ts'",
1314
"lint:fix": "yarn lint --fix",
@@ -26,6 +27,8 @@
2627
"multer": "1.4.2",
2728
"pg": "8.2.1",
2829
"reflect-metadata": "0.1.13",
30+
"swagger-jsdoc": "4.0.0",
31+
"swagger-ui-express": "4.1.4",
2932
"uuid": "8.0.0",
3033
"winston": "3.2.1"
3134
},
@@ -36,6 +39,8 @@
3639
"@types/mongodb": "3.5.18",
3740
"@types/multer": "1.4.3",
3841
"@types/nock": "11.1.0",
42+
"@types/swagger-jsdoc": "3.0.2",
43+
"@types/swagger-ui-express": "4.1.2",
3944
"@types/uuid": "7.0.3",
4045
"@types/winston": "2.4.4",
4146
"casual": "1.6.2",
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,56 @@
11
import {BaseHttpController, controller, httpGet} from "inversify-express-utils";
2+
import * as swaggerUi from "swagger-ui-express";
23

4+
import {getSwaggerSpecification} from "../../../infrastructure/utils/swagger-specification";
35
import {HealthService} from "../../../services/health-service/health-service";
46

7+
import {HttpMethodSync} from "./types";
8+
59
@controller("/Application")
610
export class ApplicationController extends BaseHttpController {
711
constructor(private readonly healthService: HealthService) {
812
super();
913
}
1014

15+
/**
16+
* @swagger
17+
* /Application/Health:
18+
* get:
19+
* tags:
20+
* - Application
21+
* summary: "Application Health"
22+
* description: "Returns general information regarding application health"
23+
* operationId: "applicationHealth"
24+
* responses:
25+
* 200:
26+
* description: "Health details retrieved"
27+
* content:
28+
* application/json:
29+
* schema:
30+
* $ref: '#/components/schemas/ApplicationHealthDto'
31+
*/
1132
@httpGet("/Health")
12-
public async getStatus() {
33+
public async getHealth() {
1334
return this.healthService.getHealth();
1435
}
36+
37+
/**
38+
* @swagger
39+
* /Application/Docs:
40+
* get:
41+
* tags:
42+
* - Application
43+
* summary: "Application Swagger Documentation"
44+
* description: "Returns Swagger UI"
45+
* operationId: "applicationDocs"
46+
* responses:
47+
* 200:
48+
* description: "Swagger UI"
49+
*/
50+
@httpGet("/Docs")
51+
public async getApiDocumentation() {
52+
const swaggerSpecification = await getSwaggerSpecification();
53+
const setup = swaggerUi.setup(swaggerSpecification, {explorer: true}) as HttpMethodSync;
54+
setup(this.httpContext.request, this.httpContext.response);
55+
}
1556
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
components:
2+
schemas:
3+
ApplicationHealthDto:
4+
type: object
5+
properties:
6+
node:
7+
type: string
8+
example: "12.11.0"
9+
version:
10+
type: string
11+
example: "1.2.0"
12+
name:
13+
type: string
14+
example: "node-onion-scaffold"
15+
environment:
16+
type: object
17+
properties:
18+
NODE_ENV:
19+
type: string
20+
example: "local"
21+
PORT:
22+
type: string
23+
example: "4000"
24+
memory:
25+
type: object
26+
properties:
27+
rss:
28+
type: string
29+
example: "10 MB"
30+
heapTotal:
31+
type: string
32+
example: "5 MB"
33+
heapUsed:
34+
type: string
35+
example: "19.1 MB"
36+
external:
37+
type: string
38+
example: "22.2 MB"
39+
storage:
40+
type: object
41+
properties:
42+
mongodb:
43+
type: object
44+
properties:
45+
status:
46+
type: string
47+
example: "ok"
48+
details:
49+
type: string;
50+
postgres:
51+
type: object
52+
properties:
53+
status:
54+
type: string
55+
example: "error"
56+
details:
57+
type: string;
58+
example: "DatabaseConnectionError"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import {Request, Response} from "express";
2+
3+
export type HttpMethodSync = (req: Request, res: Response) => Response;

src/api/middlewares/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from "./error-handler";
22
export * from "./correlation-id";
3+
export * from "./swagger-ui-server-middleware";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import * as swaggerUi from "swagger-ui-express";
2+
3+
export const SwaggerUiServeMiddleware = swaggerUi.serve;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import * as swaggerJSDoc from "swagger-jsdoc";
2+
3+
import {getPackageJson} from "../config";
4+
5+
const getOptions = () => {
6+
const packageJsonDetails = getPackageJson();
7+
const version = packageJsonDetails.version.split("#")[0];
8+
9+
return {
10+
definition: {
11+
openapi: "3.0.2",
12+
info: {
13+
version,
14+
title: packageJsonDetails.name,
15+
},
16+
schemas: {},
17+
},
18+
apis: ["**/api/controllers/**/*/*.ts", "**/api/controllers/**/*/*.js", "**/api/**/*/*.yaml"],
19+
};
20+
};
21+
22+
/**
23+
* @description
24+
* Use closure principle here in order to reduce Swagger specification build time
25+
* It takes ages and depends on amount of methods in /api/http
26+
*/
27+
let swaggerJsDocObject: Record<string, any> | undefined;
28+
29+
export const getSwaggerSpecification = (): Promise<Record<string, any>> => {
30+
if (swaggerJsDocObject != null) {
31+
return Promise.resolve(swaggerJsDocObject);
32+
}
33+
34+
return new Promise((resolve, reject) => {
35+
try {
36+
swaggerJsDocObject = swaggerJSDoc(getOptions());
37+
resolve(swaggerJsDocObject);
38+
} catch (e) {
39+
reject(e);
40+
}
41+
});
42+
};

src/main.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {InversifyExpressServer} from "inversify-express-utils";
99

1010
import {container, getPort, Logger, setProcessListeners} from "./infrastructure";
1111
import "./infrastructure/config/config";
12-
import {CorrelationId, ErrorHandler} from "./api";
12+
import {CorrelationId, ErrorHandler, SwaggerUiServeMiddleware} from "./api";
1313

1414
setProcessListeners();
1515

@@ -23,6 +23,7 @@ new InversifyExpressServer(container)
2323
app.use(json());
2424
app.use(compression());
2525
app.use(CorrelationId);
26+
app.use("/Application/Docs", SwaggerUiServeMiddleware);
2627
})
2728
.setErrorConfig((app: Application) => {
2829
app.use(ErrorHandler);

tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"compilerOptions": {
33
"module": "commonjs",
44
"declaration": true,
5-
"removeComments": true,
5+
"removeComments": false,
66
"emitDecoratorMetadata": true,
77
"experimentalDecorators": true,
88
"target": "es2017",

0 commit comments

Comments
 (0)