Skip to content

Commit

Permalink
refactor: combine asyncapi validation with request body (#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
magicmatatjahu authored Mar 29, 2022
1 parent 7588481 commit 1c0f6d0
Show file tree
Hide file tree
Showing 20 changed files with 503 additions and 404 deletions.
67 changes: 43 additions & 24 deletions openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,23 @@ paths:
tags:
- generate
- generator
- template
externalDocs:
name: Website for the AsyncAPI Generator
url: https://www.asyncapi.com/tools/generator
name: Github Repository for the AsyncAPI Generator
url: https://github.com/asyncapi/generator
requestBody:
description: Template details to be generated.
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Template'
$ref: '#/components/schemas/GenerateRequest'
responses:
'200':
description: Template successfully generated.
content:
application/zip:
schema:
type: string
format: binary
$ref: '#/components/schemas/GenerateResponse'
'400':
description: Failed to generate the given template due to invalid AsyncAPI document.
content:
Expand All @@ -67,13 +65,17 @@ paths:
operationId: validate
tags:
- validate
- validator
externalDocs:
name: Github Repository for the AsyncAPI Parser
url: https://github.com/asyncapi/parser-js
requestBody:
description: Validate the given AsyncAPI document with the AsyncAPI parser.
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ValidateDocument'
$ref: '#/components/schemas/ValidateRequest'
responses:
'204':
description: The given AsyncAPI document is valid.
Expand Down Expand Up @@ -102,6 +104,10 @@ paths:
operationId: convert
tags:
- convert
- converter
externalDocs:
name: Github Repository for the AsyncAPI Converter
url: https://github.com/asyncapi/converter-js
requestBody:
description: Parameters to convert the spec.
required: true
Expand Down Expand Up @@ -138,14 +144,35 @@ paths:
components:
schemas:
AsyncAPIDocument:
description: AsyncAPI document in JSON or YAML
description: AsyncAPI document in JSON or YAML.
oneOf:
- type: string # can be in YAML format
- $ref: https://raw.githubusercontent.com/asyncapi/spec-json-schemas/master/schemas/2.0.0.json
- $ref: https://raw.githubusercontent.com/asyncapi/spec-json-schemas/master/schemas/2.1.0.json
- $ref: https://raw.githubusercontent.com/asyncapi/spec-json-schemas/master/schemas/2.2.0.json
- $ref: https://raw.githubusercontent.com/asyncapi/spec-json-schemas/master/schemas/2.3.0.json
Template:
AsyncAPIDocuments:
type: array
description: AsyncAPI documents in JSON or YAML.
minItems: 1
items:
$ref: '#/components/schemas/AsyncAPIDocument'
SpecVersions:
type: string
description: Valid specification versions for the AsyncAPI document.
enum:
- '1.0.0'
- '1.1.0'
- '1.2.0'
- '2.0.0-rc1'
- '2.0.0-rc2'
- '2.0.0'
- '2.1.0'
- '2.2.0'
- '2.3.0'
- 'latest'

GenerateRequest:
type: object
required:
- asyncapi
Expand Down Expand Up @@ -175,13 +202,18 @@ components:
which is usually located in the template's repository.
This field is optional but may be required for some templates.
additionalProperties: true
ValidateDocument:
GenerateResponse:
type: string
format: binary

ValidateRequest:
type: object
required:
- asyncapi
properties:
asyncapi:
$ref: '#/components/schemas/AsyncAPIDocument'

ConvertRequest:
type: object
required:
Expand All @@ -198,25 +230,12 @@ components:
- 'yaml'
- 'yml'
- 'json'
SpecVersions:
type: string
description: Valid spec versions for the AsyncAPI document.
enum:
- '1.0.0'
- '1.1.0'
- '1.2.0'
- '2.0.0-rc1'
- '2.0.0-rc2'
- '2.0.0'
- '2.1.0'
- '2.2.0'
- '2.3.0'
- 'latest'
ConvertResponse:
type: object
properties:
converted:
$ref: '#/components/schemas/AsyncAPIDocument'

Problem:
type: object
properties:
Expand Down
25 changes: 25 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"@asyncapi/specs": "^2.13.1",
"@asyncapi/ts-nats-template": "^0.5.15",
"ajv": "^8.8.2",
"ajv-formats": "^2.1.1",
"archiver": "^5.3.0",
"body-parser": "^1.19.0",
"compression": "^1.7.4",
Expand Down
34 changes: 15 additions & 19 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import helmet from 'helmet';

import { Controller } from './interfaces';

import { requestBodyValidationMiddleware } from './middlewares/request-body-validation.middleware';
import { problemMiddleware } from './middlewares/problem.middleware';

import { logger } from './utils/logger';
Expand All @@ -18,19 +17,21 @@ export class App {
private port: string | number;
private env: string;

constructor(controller: Controller[]) {
constructor(
private readonly controllers: Controller[]
) {
this.app = express();
this.port = process.env.PORT || 80;
this.env = process.env.NODE_ENV || 'development';
}

public async init() {
// initialize core middlewares
this.initializeMiddlewares();
// initialize validation middlewares
this.initializeValidation();
// initialize all controllers
this.initializeControllers(controller);
await this.initializeMiddlewares();
// initialize controllers
await this.initializeControllers();
// initialize error handling
this.initializeErrorHandling();
await this.initializeErrorHandling();
}

public listen() {
Expand All @@ -46,7 +47,7 @@ export class App {
return this.app;
}

private initializeMiddlewares() {
private async initializeMiddlewares() {
const requestBodyLimit = config.get<string>('request.body.limit');

this.app.use(cors({ origin: config.get('cors.origin'), credentials: config.get('cors.credentials') }));
Expand All @@ -67,18 +68,13 @@ export class App {
}));
}

private initializeValidation() {
this.app.use(requestBodyValidationMiddleware);
}

private initializeControllers(controller: Controller[]) {
controller.forEach(controller => {
// in the `openapi.yaml` we have prefix `v1` for all paths
this.app.use(`/${API_VERSION}/`, controller.boot());
});
private async initializeControllers() {
for (const controller of this.controllers) {
this.app.use(`/${API_VERSION}/`, await controller.boot());
}
}

private initializeErrorHandling() {
private async initializeErrorHandling() {
this.app.use(problemMiddleware);
}
}
12 changes: 8 additions & 4 deletions src/controllers/convert.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { NextFunction, Request, Response, Router } from 'express';

import { Controller, AsyncAPIDocument, SpecsEnum } from '../interfaces';

import { documentValidationMiddleware } from '../middlewares/document-validation.middleware';
import { validationMiddleware } from '../middlewares/validation.middleware';

import { ConvertService } from '../services/convert.service';

Expand Down Expand Up @@ -55,12 +55,16 @@ export class ConvertController implements Controller {
}
}

public boot(): Router {
public async boot(): Promise<Router> {
const router = Router();

router.post(
`${this.basepath}`,
documentValidationMiddleware,
this.basepath,
await validationMiddleware({
path: this.basepath,
method: 'post',
documents: ['asyncapi'],
}),
this.convert.bind(this)
);

Expand Down
10 changes: 7 additions & 3 deletions src/controllers/generate.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Ajv from 'ajv';

import { Controller } from '../interfaces';

import { documentValidationMiddleware } from '../middlewares/document-validation.middleware';
import { validationMiddleware } from '../middlewares/validation.middleware';

import { ArchiverService } from '../services/archiver.service';
import { GeneratorService } from '../services/generator.service';
Expand Down Expand Up @@ -137,7 +137,7 @@ export class GenerateController implements Controller {
};
}

public boot(): Router {
public async boot(): Promise<Router> {
this.ajv = new Ajv({
inlineRefs: true,
allErrors: true,
Expand All @@ -148,7 +148,11 @@ export class GenerateController implements Controller {

router.post(
`${this.basepath}`,
documentValidationMiddleware,
await validationMiddleware({
path: this.basepath,
method: 'post',
documents: ['asyncapi'],
}),
this.generate.bind(this)
);

Expand Down
15 changes: 10 additions & 5 deletions src/controllers/tests/convert.controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ channels: {}

describe('ConvertController', () => {
describe('[POST] /convert', () => {
it('should throw error with invalid version', () => {
it('should throw error with invalid version', async () => {
const app = new App([new ConvertController()]);
await app.init();

return request(app.getServer())
.post('/v1/convert')
Expand Down Expand Up @@ -59,8 +60,9 @@ describe('ConvertController', () => {
});
});

it('should throw error that the converter cannot convert to a lower version', () => {
it('should throw error that the converter cannot convert to a lower version', async () => {
const app = new App([new ConvertController()]);
await app.init();

return request(app.getServer())
.post('/v1/convert')
Expand All @@ -76,8 +78,9 @@ describe('ConvertController', () => {
});
});

it('should pass when converting to 2.3.0 version', () => {
it('should pass when converting to 2.3.0 version', async () => {
const app = new App([new ConvertController()]);
await app.init();

return request(app.getServer())
.post('/v1/convert')
Expand All @@ -97,8 +100,9 @@ describe('ConvertController', () => {
});
});

it('should pass when converting to latest version', () => {
it('should pass when converting to latest version', async () => {
const app = new App([new ConvertController()]);
await app.init();

return request(app.getServer())
.post('/v1/convert')
Expand All @@ -117,8 +121,9 @@ describe('ConvertController', () => {
});
});

it('should correctly convert JSON to YAML', () => {
it('should correctly convert JSON to YAML', async () => {
const app = new App([new ConvertController()]);
await app.init();

return request(app.getServer())
.post('/v1/convert')
Expand Down
Loading

0 comments on commit 1c0f6d0

Please sign in to comment.