|
| 1 | +## Async Example |
| 2 | +This includes three parts: |
| 3 | +* the caller, which is a middleware for the [OpenAPI Factory library](https://www.npmjs.com/package/openapi-factory) |
| 4 | +* an async wrapper, which is a custom class to contain helpers for validation. |
| 5 | +* a pre-step is to call `compileValidator` during the build step and save the `compiledSpecValidation.json`, so that it will run faster on production execution. |
| 6 | + |
| 7 | +```js |
| 8 | +// OpenAPI Factory wrapper |
| 9 | +let api = new Api({ |
| 10 | + async requestMiddleware(request, context) { |
| 11 | + modelValidator.startValidation(request); |
| 12 | + if (request.httpMethod !== 'GET') { |
| 13 | + await modelValidator.ensureValidation(); |
| 14 | + } |
| 15 | + return request; |
| 16 | + }, |
| 17 | + async responseMiddleware(request, response) { |
| 18 | + try { |
| 19 | + await modelValidator.ensureValidation(); |
| 20 | + } catch (error) { |
| 21 | + throw error; |
| 22 | + } |
| 23 | + return response; |
| 24 | + }, |
| 25 | + errorMiddleware(request, error) { |
| 26 | + if (error.code === 'InvalidInputRequest') { |
| 27 | + return { statusCode: 400, body: { errorCode: 'InvalidRequest', errorId: request.requestContext.requestId, title: error.message.title } } |
| 28 | + } |
| 29 | + |
| 30 | + return { statusCode: 500, body: { title: 'Unexpected error', errorId: request.requestContext.requestId } }; |
| 31 | + } |
| 32 | +}); |
| 33 | +``` |
| 34 | + |
| 35 | +```js |
| 36 | +class ModelValidator { |
| 37 | + constructor() { |
| 38 | + this.validator = null; |
| 39 | + this.validationAsync = null; |
| 40 | + } |
| 41 | + |
| 42 | + getOpenApiValidationProvider(spec) { |
| 43 | + const path = require('path'); |
| 44 | + const { OpenApiValidator } = require('openapi-data-validator'); |
| 45 | + const compiledFilePath = path.join(__dirname, 'compiledSpecValidation.json'); |
| 46 | + return new OpenApiValidator({ apiSpec: spec, compiledFilePath: compiledFilePath, validateRequests: { allowUnknownQueryParameters: false } }); |
| 47 | + } |
| 48 | + |
| 49 | + async compileValidator() { |
| 50 | + const spec = import('./openapi.js').then(doc => doc.default); |
| 51 | + const openApiValidator = this.getOpenApiValidationProvider(spec); |
| 52 | + await openApiValidator.compileValidator(); |
| 53 | + } |
| 54 | + |
| 55 | + getValidator() { |
| 56 | + if (this.validator) { |
| 57 | + return this.validator; |
| 58 | + } |
| 59 | + |
| 60 | + const openApiValidator = this.getOpenApiValidationProvider(); |
| 61 | + return this.validator = openApiValidator.loadValidator(); |
| 62 | + } |
| 63 | + |
| 64 | + startValidation(request) { |
| 65 | + const newRequest = { |
| 66 | + method: request.httpMethod, |
| 67 | + headers: request.headers, |
| 68 | + query: request.queryStringParameters, |
| 69 | + body: request.body, |
| 70 | + path: request.pathParameters, |
| 71 | + route: request.route |
| 72 | + }; |
| 73 | + |
| 74 | + this.validationAsync = this.getValidator().then(validator => validator(newRequest)); |
| 75 | + // Ensure validation may never be called, and in those cases, we want to avoid an uncaught exception |
| 76 | + this.validationAsync.catch(() => {}); |
| 77 | + } |
| 78 | + |
| 79 | + async ensureValidation() { |
| 80 | + try { |
| 81 | + await this.validationAsync; |
| 82 | + } catch (error) { |
| 83 | + const wrapped = Error.create({ title: `InvalidRequest: ${error.message}.` }); |
| 84 | + wrapped.code = 'InvalidInputRequest'; |
| 85 | + throw wrapped; |
| 86 | + } |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +module.exports = new ModelValidator(); |
| 91 | +``` |
0 commit comments