Skip to content

Commit f378ed1

Browse files
author
Lukas Siemon
committed
feat: added basic swagger generation + validation test
1 parent 7ff594e commit f378ed1

10 files changed

Lines changed: 267 additions & 33 deletions

File tree

lib/api.js

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,14 @@
1-
const fs = require("fs");
2-
const path = require("path");
31
const get = require('lodash.get');
4-
const appRoot = require('app-root-path');
52
const Rollbar = require('lambda-rollbar');
63
const Limiter = require('lambda-rate-limiter');
74
const param = require("./param");
85
const response = require("./response");
6+
const swagger = require("./swagger");
7+
8+
const endpoints = {};
99

1010
const Parser = (request, params) => {
11-
fs.writeFileSync(path.join(appRoot.path, 'swagger', `${request}.json`), JSON.stringify({
12-
swagger: "2.0",
13-
paths: {
14-
[`/${request.split(" ")[1]}`]: {
15-
[request.split(" ")[0].toLowerCase()]: {
16-
parameters: params.map(p => ({
17-
name: p.name,
18-
required: p.required,
19-
type: p.constructor.name.toLowerCase(),
20-
in: p.type
21-
})),
22-
responses: {}
23-
}
24-
}
25-
}
26-
}, null, 2));
11+
endpoints[request] = params;
2712
return (event) => {
2813
let body;
2914
try {
@@ -80,6 +65,7 @@ module.exports = (options = {}) => {
8065

8166
return {
8267
wrap,
68+
generateSwagger: () => swagger(endpoints),
8369
ApiError: response.ApiError,
8470
ApiResponse: response.ApiResponse,
8571
JsonResponse: response.JsonResponse,

lib/param.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const get = require("lodash.get");
22
const response = require("./response");
33

4-
const types = {
4+
const positionMapping = {
55
query: "queryStringParameters",
66
json: "body",
77
path: "pathParameters",
@@ -10,10 +10,11 @@ const types = {
1010
};
1111

1212
class Param {
13-
constructor(name, type = 'query', required = true) {
13+
constructor(name, position = 'query', required = true) {
1414
this.name = name;
15-
this.type = type;
15+
this.position = position;
1616
this.required = required;
17+
this.type = null;
1718
}
1819

1920
feed(event) {
@@ -26,13 +27,13 @@ class Param {
2627
}
2728

2829
get() {
29-
const result = get(this.event, `${types[this.type]}.${this.name}`);
30+
const result = get(this.event, `${positionMapping[this.position]}.${this.name}`);
3031
if (result === undefined) {
3132
if (this.required) {
32-
throw response.ApiError(`Required ${this.type}-Parameter "${this.name}" missing.`, 400, 99002);
33+
throw response.ApiError(`Required ${this.position}-Parameter "${this.name}" missing.`, 400, 99002);
3334
}
3435
} else if (!this.validate(result)) {
35-
throw response.ApiError(`Invalid Value for ${this.type}-Parameter "${this.name}" provided.`, 400, 99003, {
36+
throw response.ApiError(`Invalid Value for ${this.position}-Parameter "${this.name}" provided.`, 400, 99003, {
3637
value: result
3738
});
3839
}
@@ -41,6 +42,10 @@ class Param {
4142
}
4243

4344
class Str extends Param {
45+
constructor(...args) {
46+
super(...args);
47+
this.type = "string";
48+
}
4449
validate(value) {
4550
let valid = super.validate(value);
4651
if (!(typeof value === 'string' || value instanceof String)) {

lib/swagger.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
module.exports = (endpoints) => {
2+
const data = {
3+
swagger: "2.0",
4+
produces: ["application/json"],
5+
info: {
6+
title: "Api Name",
7+
version: "0.0.1"
8+
},
9+
paths: {}
10+
};
11+
Object.keys(endpoints).forEach((request) => {
12+
const parameters = endpoints[request].filter(p => p.position !== "json").map(p => ({
13+
name: p.name,
14+
required: p.required,
15+
type: p.type,
16+
in: p.position
17+
}));
18+
19+
const jsonParams = endpoints[request].filter(p => p.position === "json");
20+
if (jsonParams.length !== 0) {
21+
parameters.push({
22+
in: "body",
23+
name: "bodyParamData",
24+
schema: {
25+
type: "object",
26+
required: jsonParams.filter(p => p.required).map(p => p.name),
27+
properties: Object.assign(...jsonParams.map(p => ({
28+
[p.name]: {
29+
type: p.type
30+
}
31+
})))
32+
}
33+
});
34+
}
35+
data.paths[`/${request.split(" ")[1]}`] = {
36+
[request.split(" ")[0].toLowerCase()]: {
37+
consumes: ["application/json"],
38+
parameters,
39+
responses: {
40+
default: {
41+
description: "Unexpected Error"
42+
}
43+
}
44+
}
45+
};
46+
});
47+
return data;
48+
};

package-lock.json

Lines changed: 75 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313
],
1414
"author": "Lukas Siemon",
1515
"devDependencies": {
16+
"app-root-path": "2.0.1",
1617
"coveralls": "3.0.0",
1718
"js-gardener": "1.11.17",
18-
"semantic-release": "12.4.1"
19+
"semantic-release": "12.4.1",
20+
"swagger-parser": "4.0.2"
1921
},
2022
"version": "0.0.0-development",
2123
"scripts": {
@@ -45,7 +47,6 @@
4547
"lib"
4648
],
4749
"dependencies": {
48-
"app-root-path": "2.0.1",
4950
"lambda-rate-limiter": "2.4.1",
5051
"lambda-rollbar": "1.8.2",
5152
"lambda-tdd": "1.11.10",

0 commit comments

Comments
 (0)