Coder Social home page Coder Social logo

cdimascio / express-openapi-validator Goto Github PK

View Code? Open in Web Editor NEW
862.0 18.0 202.0 9.39 MB

🦋 Auto-validates api requests, responses, and securities using ExpressJS and an OpenAPI 3.x specification

License: MIT License

TypeScript 99.38% JavaScript 0.59% Shell 0.03%
openapi3 express-middleware nodejs request-validation expressjs middleware rest-api express openapi connect-middleware

express-openapi-validator's Introduction

🦋 express-openapi-validator

docs.

example workflow All Contributors Coverage Status Codacy Badge Gitpod Ready-to-Code

An OpenApi validator for ExpressJS that automatically validates API requests and responses using an OpenAPI 3 specification.

🦋express-openapi-validator is an unopinionated library that integrates with new and existing API applications. express-openapi-validator lets you write code the way you want; it does not impose any coding convention or project layout. Simply, install the validator onto your express app, point it to your OpenAPI 3 specification, then define and implement routes the way you prefer. See an example.

Features:

  • ✔️ request validation
  • ✔️ response validation (json only)
  • 👮 security validation / custom security functions
  • 👽 3rd party / custom formats / custom data serialization-deserialization
  • 🧵 optionally auto-map OpenAPI endpoints to Express handler functions
  • ✂️ $ref support; split specs over multiple files
  • 🎈 file upload

Docs:

GitHub stars Twitter URL

NestJS Koa and Fastify now available! 🚀

Install

npm install express-openapi-validator

## latest beta
npm install [email protected]

Usage

  1. Require/import the openapi validator
const OpenApiValidator = require('express-openapi-validator');

or

import * as OpenApiValidator from 'express-openapi-validator';
  1. Install the middleware
app.use(
  OpenApiValidator.middleware({
    apiSpec: './openapi.yaml',
    validateRequests: true, // (default)
    validateResponses: true, // false by default
  }),
);
  1. Register an error handler
app.use((err, req, res, next) => {
  // format error
  res.status(err.status || 500).json({
    message: err.message,
    errors: err.errors,
  });
});

Important: Ensure express is configured with all relevant body parsers. Body parser middleware functions must be specified prior to any validated routes. See an example.

See the doc for complete documenation

deprecated legacy doc

License

MIT

Buy Me A Coffee

express-openapi-validator's People

Contributors

ahilke avatar allcontributors[bot] avatar benblack86 avatar cdimascio avatar ckeboss avatar codinggosu avatar comino avatar dependabot[bot] avatar efabris avatar foway0 avatar frankcalise avatar greenkeeper[bot] avatar hugomario avatar jacobley avatar jakubskopal avatar jordandobrev avatar jy95 avatar kikyomits avatar mdmower avatar mdwheele avatar medolino avatar ownagedj avatar pilerou avatar robertjustjones avatar rowanc1 avatar sheldhur avatar snyk-bot avatar spencerlawrencebrown avatar trebler avatar zzgab avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

express-openapi-validator's Issues

body type string is not recognized

When expecting a body parameter of type string (not a json!) - an error is returned saying the body parameter is not a string even if it is.
Bellow is a sample yaml code that shows it.
The references are for the definitions of the id param and the returned values (not relevant here).

  /users/{id}/role:
    parameters:
    - $ref: '#/components/parameters/idParam'
    put:
      tags:
        - Users
      description: Set user role
      responses:
        '204':
          $ref: '#/components/responses/NoContentResponse'
        default:
          $ref: '#/components/responses/ErrorResponse'
      requestBody:
        content:
          text/plain:
            schema:
              type: string
              enum:
                - user
                - moderator
                - admin
        description: New role
        required: true

TypeScript Type Error ES6

I have the following code (using ES6).

import * as express from "express";
import { OpenApiValidator } from "express-openapi-validator";
import { https } from "firebase-functions";
import { resolve } from "path";

const app = express();
new OpenApiValidator({
  apiSpecPath: resolve(__dirname, './openapi/specification.yml'),
}).install(app);

Typescript raises the following error

error TS7009: 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.

 new OpenApiValidator({
   apiSpecPath: resolve(__dirname, './openapi/specification.yml'),
}).install(app);

It seems like the type definitions may not be correct, looking at index.d.ts file

export interface OpenApiValidatorOpts {
    apiSpecPath: string;
}
export declare function OpenApiValidator(options: OpenApiValidatorOpts): void;

response validation allows schema to pass that has some differences

The following was posted by @LadIQe from #88. Copying details here

when I change response schema in OpenAPI documentation to test, if response validation works, and I execute it in swagger ui, I get no error. I looked into console, if something is there, but console/terminal is clear

As you can see on image below, my response schema is little bit different to test if validation works. But there is no error

Here is code in my app.js

const express = require('express')
const swaggerUi = require('swagger-ui-express')
const cookieParser = require('cookie-parser')
const bodyParser = require('body-parser')
const OpenApiValidator = require('express-openapi-validator').OpenApiValidator
const documentation = require('./components/documentation')
const app = express()


app.use(bodyParser.json())
app.use(bodyParser.text())
app.use(bodyParser.urlencoded())
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser())

app.use('/', swaggerUi.serve, swaggerUi.setup(documentation))

new OpenApiValidator({
  apiSpec: documentation,
  validateResponses: true,
  securityHandlers: {
    bearerAuth: (req, scopes, schema) => {
      console.log(req, scopes, schema)
    }
  }
}).install(app)


app.use((err, req, res, next) => {
  // format error
  console.error(err, err.stack);
  if (!err.status && !err.errors) {
    res.status(500).json({
      errors: [
        {
          message: err.message,
        },
      ],
    })
  } else {
    res.status(err.status).json({
      message: err.message,
      errors: err.errors,
    })
  }
})

module.exports = app

You Can Haz Coffee?

Carmine, I went to buy you some coffees… but I was denied 😭

coffee

Carmine, this mission critical issue needs your urgent attention ❌ ☕️➡️ ☕️ ✅

Missing list of additional properties, when additionalProperties error is thrown

When additionalProperties validation fails, following error is thrown:

{
   stack: 'Error: request.body should NOT have additional properties\n  at Object.POST-/api/....\n',
   message: 'request.body should NOT have additional properties',
   toJSON:[
      Function:toJSON
   ],
   status: 400,
   errors: [
      {
         path:'.body',
         message:'should NOT have additional properties',
         errorCode:'additionalProperties.openapi.validation'
      }
   ],
   name: 'Error',
   toString: [
      Function:toString
   ]
}

Is there any chance to add a list of additional properties to error message. It would be really helpfull to know, which properties should be removed from payload.

Information about additional properties is available in validator.errors array, generated by ajv validator (

const errors = [...(validator.errors || [])];
), but gets lost while creating customized error by calling ajvErrorsToValidatorError util function (
export function ajvErrorsToValidatorError(status, errors) {
).

Avj validation errors:

[
   {
      keyword: 'additionalProperties',
      dataPath: '.body',
      schemaPath: '#/components/schemas/CreateItem/additionalProperties',
      params: {
         additionalProperty: 'invalidProperty'
      },
      message: 'should NOT have additional properties'
   }
]

Customized error object provided by ajvErrorsToValidatorError:

{
   status:400,
   errors:[
      {
         path:'.body',
         message:'should NOT have additional properties',
         errorCode:'additionalProperties.openapi.validation'
      }
   ]
}

enum validation error should include the list of allowed enum values

it will be more helpful if the following validation error contains the list of allowed enum values

{ 
  message: '.response.role should be equal to one of the allowed values',
  errors: [{
    path: '.response.role',
    message: 'should be equal to one of the allowed values',
    errorCode: 'enum.openapi.validation' 
  }]
}

Single item in array type query parameter is not converted to array

Hi, I have the following query parameter

- in: query
  name: publication_time
  required: true
  style: form
  explode: true
    schema:
      type: array
      minItems: 1
      items:
        type: string

When I pass muliple values like ?publication_time=someDay&publication_time=otherDay it's fine but when I pass a single value ?publication_time=someDay, I get the error

{ errors:
   [ { path: '.query.publication_time',
       message: 'should be array',
       errorCode: 'type.openapi.validation' } ] }

Am I doing something wrong? Is there another way to pass an array with a single parameter using style=form and explode=true ?

Thanks

Errors for unknown format

An error is thrown when there is a custom format on a property. e.g. if the api spec has something like:

properties:
  phoneNumber:
    type: string
    example: +15017122661
    format: phone-number

This will result in an error like

Error: unknown format "phone-number" is used in schema at path "#/properties/body/properties/phoneNumber"

The OpenAPI spec is pretty flexible on formats so I think this should be allowed. E.g. this page says (https://swagger.io/specification/):

Primitives have an optional modifier property: format. OAS uses several known formats to define in fine detail the data type being used. However, to support documentation needs, the format property is an open string-valued property, and can have any value. Formats such as "email", "uuid", and so on, MAY be used even though undefined by this specification. Types that are not accompanied by a format property follow the type definition in the JSON Schema. Tools that do not recognize a specific format MAY default back to the type alone, as if the format is not specified.

Global apiKey query param not detected

When using a top level defined apiKey as query parameter, the apiKey is not recognized in requests.

$ curl localhost:8000/v1/check?apiKey=testtest

{"message":"query parameter 'apiKey' required","errors":[{"path":"/v1/check","message":"query parameter 'apiKey' required"}]}

Reson is that we are looking in the headers, not in the query param ;)

            else if (scheme.in === 'query') {
                if (!req.headers[scheme.name]) {
                    throw Error(`query parameter '${scheme.name}' required`);
                }
            }

Will send a PR

Type Coercion

What's The Issue?

The validator is mutating request body payloads.

We think we'd like to be able to configure the validator to do validation only.

Where?

See here: specifically, coerceTypes: true

    const aoav = new middlewares.RequestValidator(this.context.apiDoc, {
      coerceTypes: true,
      removeAdditional: true,
      useDefaults: true,
    });

With coerceTypes: true — the hardcoded value — we see a property being sent in the request body being transformed from the boolean literal true to the string literal "true".

"majorReferenceWork": true . // before validation

"majorReferenceWork": "true" // after validation

When I change the module so that coerceTypes: false then the boolean property remains a boolean literal. This is our desired behaviour.

How To Reproduce?

I can, and will, add a reproducible test case… but I wanted to have a quick discussion about this behaviour before doing that because you might tell me I'm doing something dumb 😄

Fix?

I don't think the current behaviour is wrong and coerceTypes defaulting to true is fine: but, it'd be nice if we could turn this off via a configuration parameter.

Totally open to other suggestions.

description and summary fields in path item object result in an error

According to https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#fixed-fields-7 it is possible to have description and summary (among other fields) in the path item. e.g.:

[...]
paths:
  /features:
    description: Feature Toggles List
    summary: This is an example summary
    get:
[...]

Unfortunately, when trying to parse such an API specification, it fails with the following error:

/Users/user/NodeJS/project/node_modules/express-openapi-validator/dist/openapi.spec.loader.js:44
                            schema.parameters = Array.from(schemaParameters);
                                              ^

TypeError: Cannot create property 'parameters' on string 'Single Feature'
    at Object.visitApi (/Users/user/NodeJS/project/node_modules/express-openapi-validator/dist/openapi.spec.loader.js:44:47)
    at OpenAPIFramework.initialize (/Users/user/NodeJS/project/node_modules/express-openapi-validator/dist/framework/index.js:59:21)
    at OpenApiSpecLoader.discoverRoutes (/Users/user/NodeJS/project/node_modules/express-openapi-validator/dist/openapi.spec.loader.js:31:19)
    at OpenApiSpecLoader.load (/Users/user/NodeJS/project/node_modules/express-openapi-validator/dist/openapi.spec.loader.js:16:29)
    at new OpenApiContext (/Users/user/NodeJS/project/node_modules/express-openapi-validator/dist/openapi.context.js:11:69)
    at new OpenApiValidator (/Users/user/NodeJS/project/node_modules/express-openapi-validator/dist/index.js:15:32)
    at ExpressServer.setupMiddleware (/Users/user/NodeJS/project/build/expressServer.js:40:9)
    at new ExpressServer (/Users/user/NodeJS/project/build/expressServer.js:19:14)
    at Object.<anonymous> (/Users/user/NodeJS/project/build/server.js:46:23)
    at Module._compile (internal/modules/cjs/loader.js:778:30)

Around that line of code you can see:

                            if (method === 'parameters') {
                                continue;
                            }

Which should maybe be transformed into:

                            if (['parameters', 'summary', 'description'].includes(method)) {
                                continue;
                            }

Which I have test locally and it works

Can't use multiple Media Types in combination with "multipart/form-data" in `requestBody.content`

I am trying to create a route schema, which supports two requestBody contents (application/json and multipart/form-data). When I send application/json request, unsupported media type error is returned. multipart/form-data works ok.

I think the problem is in isMultipart(req) function, which does not predict that other content types might be present in schema configuration. (

)

I think that req.headers['content-type'] should also be checked together with isMultipart(req).

Maybe this simple solution would solve this problem :)

if (isMultipart(req) && isValidContentType(req)) {
      mult.any().......
}

In case of invalidContentType, unsupported media type error will be thrown later in code flow.

do not validate request if path does not exist in openapi spec

I am serving frontend and restful APIs within a same app. I want to validate only my restful APIs which have a openapi spec, however, my frontend pages are throwing not found errors because these paths do not exist in the specification.

Is there a way to limit validation to a certain path, for example, /api/? Or even disable not found errors for paths not found in openapi spec?

Use of undefined path resources or methods hang when processing securities #90

Suppose we define a GET method on the resource /api/users.
If we try to access GET /api/users2 - we never get a reply instead of 404 (resource not found).
If we try to access POST /api/users - we never get a reply instead of 405 (method not allowed).

Some people might want to allow a pass through if resource is not found or method not defined. Maybe an option should be available to allow it (defaults to off) - but the process should not hang.

Response Validation Issue - "Cannot read property 'then' of undefined in modded.mung"

Hi,

It looks like response validation was just added a few days ago, so this could be a known issue or not. So far I really appreciate how straight-forward and friendly this library is. Thank you!

Now to the issue:

I have a simple example app using OpenApiValidator to validate requests and responses.

I am sending the request

http://localhost:3000/v1/progress?type=test

When I have the validateResponses flag set to false, my response is returned correctly (although not validated of course). However when I set validateResponses to true I get:

TypeError: Cannot read property 'then' of undefined
    at ServerResponse.json_async_hook (node_modules/express-openapi-validator/dist/middlewares/modded.express.mung.js:73:21)
    at app.ts:24:7
    at Layer.handle [as handle_request] (node_modules/express/lib/router/layer.js:95:5)
    at next (node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (node_modules/express/lib/router/layer.js:95:5)
    at node_modules/express/lib/router/index.js:281:22
    at Function.process_params (node_modules/express/lib/router/index.js:335:12)
    at next (node_modules/express/lib/router/index.js:275:10)
    at node_modules/express-openapi-validator/dist/middlewares/modded.express.mung.js:94:17

Line 24 in my app.ts is pretty straightforward:

23 app.get('/v1/progress', function(req, res, next) {
24   res.json({id: 1, name: 'test'});
25 });

So I am trying to figure out if I mis-configured the project or if its existing issue.
I would really appreciate any feedback on how I can get this to work!

app.ts

const app = express();
app.use(express.json());
new OpenApiValidator({
  apiSpec: './workflow-tracker-openapi.yml',
  validateRequests: true,
  validateResponses: true,
}).install(app);

app.get('/v1/progress', function(req, res, next) {
  res.json({id: 1, name: 'test'});
});

const server = app.listen(3000);

yml spec

info:
  title: Example Service API
  version: '1.0'
servers:
  - url: http://localhost:3000/v1

paths:
  /progress:
    get:
      description: Get the progress of an event
      parameters:
        - name: type
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Progress'
          
components:
  schemas:
    Progress:
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string
      required:
        - id
        - name

I really appreciate that you've made this library available and will keep digging through the source to see if I can fix it myself, but if you have any idea what might be wrong in the meantime, please let me know.

Thank you!

Stop using openapi-* dependencies

Why?

openapi-request-coercer - Ajv can do it
openapi-default-setter - Ajv can do it
openapi-request-validator - it's wrapper over Ajv that can't correctly resolve $ref. But Ajv no have troubles with resolving $ref

Action required: Greenkeeper could not be activated 🚨

🚨 You need to enable Continuous Integration on Greenkeeper branches of this repository. 🚨

To enable Greenkeeper, you need to make sure that a commit status is reported on all branches. This is required by Greenkeeper because it uses your CI build statuses to figure out when to notify you about breaking changes.

Since we didn’t receive a CI status on the greenkeeper/initial branch, it’s possible that you don’t have CI set up yet.
We recommend using:

If you have already set up a CI for this repository, you might need to check how it’s configured. Make sure it is set to run on all new branches. If you don’t want it to run on absolutely every branch, you can whitelist branches starting with greenkeeper/.

Once you have installed and configured CI on this repository correctly, you’ll need to re-trigger Greenkeeper’s initial pull request. To do this, please click the 'fix repo' button on account.greenkeeper.io.

Plain JS object as apiSpec in constructor

Hi. Can you add support plain JS object as apiSpec in constructor?

It would be useful if you use jsdoc annotations for writing swagger\openapi spec or if you split yor spec on small simpled parts (js or json) and build big yaml when app starts.

Error in the construction of routes

Hello, when using the library I found that adding the library in a project a little more advanced than the basic example for all the requests showed me an error not found, the .yaml file that I use will generate it with editor.swagger.io, the routes when I define them I place / at the beginning as in the examples that I found since I am testing openapi and I have no experience with it, and I am testing what is the difference with respect to documentation with apidoc and I found it interesting about the validation from the own documentation. Anyway, I drifted away from the topic, try moving :
new OpenApiValidator ({ apiSpecPath: spec, }). install (app)

since I assumed that it is a middleware and in effect with that I got to show the path that serves static files that I use to serve the documentation generated with apidoc, inspecting the variables I realized that the library start of each route places // instead of / and that makes the routes are not achieved, the solution I got was to replace the line 43 const openApiRoute = `$ {bp} $ {path}`; of the file dis / openapi.spec.loader.js
as it is a temporary solution I write to you to verify, I get lost in the logic of typescript. In my project I use a dynamic load of urls, I do not know if that is the cause of the error. Thank you and apologize if you do not understand well I do not speak English and use the translator

using enum in schema leads to unexpected results

Hi

With the following schema:

    EnumBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              enum:
                - foo
              required:
                - foo
              properties:
                foo:
                  type: string

A call with body set to {foo: 'bar', bogus: 'baz'} is rejected (which is expected), but a call with body set to {foo: 'bar'} is also rejected which is not expected.

Is this a bug or did I misunderstood OpenApi specification ?

If needed I can provide a patch so that express-openapi-validator's tests show this behavior.

All the best

Unknown format "decimal" is used in schema

Whenever I try to validate a request against an openapi.yaml file that contains a type: number with format: decimal I receive the following error:

{
    "errors": [
        {
            "message": "unknown format \"decimal\" is used in schema at path \"#/properties/amount\""
        }
    ]
}

Additional properties are incorrectly removed (removeAdditional)

I'm in the process of upgrading to 1.4.0 from 0.53.3 and many of our tests are failing. The following schema/body combination used to fail validation, which is the correct behaviour:

Request body schema:

{
    "type": "object",
    "additionalProperties": false,
    "required": ["data"],
    "properties": {
        "data": {
            "type": "string"
        }
    }
}

Request body (this should fail):

{
  "data": "foo",
  "not-allowed-property": "bar"
}

The addition of the "removeAdditional" property is causing the request body to be mutated prior to validation so the above example now appears to be valid, however this is what is actually being validated:

{
  "data": "foo"
}

It would be nice to allow this to be configured, or even better, allow a raw options object to be passed through to the internal AJV instance. Is this something you would consider?

How trim value in validation

Please add support for how to trim value while validation.If I submit field with spaces it validates it which should not be.

Creating multiple app instances causes spec read to be empty

While writing unit tests for an express app, I kept seeing the error version missing from OpenAPI specification when creating multiple Express app instances within one Jest test file.

After some debugging, it looks like the root cause is loadSpecFile not throwing an error when performing require(absolutePath). This returns an object just containing __proto__, which lets it past all the null checks until it hits the version missing error.

How to reproduce

Just creating multiple app instances in index.js didn't seem to cause the bug. It may have something to do with how Jest sets up its tests. Using jest --runInBand to run the tests in series doesn't fix this.

Cannot read security of undefined

Hi,

Im trying to make it work, but Im getting this error

UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'security' of undefined
starter-node-documentation       |     at /usr/app/node_modules/express-openapi-validator/dist/middlewares/openapi.security.js:16:47
starter-node-documentation       |     at Layer.handle [as handle_request] (/usr/app/node_modules/express/lib/router/layer.js:95:5)
starter-node-documentation       |     at trim_prefix (/usr/app/node_modules/express/lib/router/index.js:317:13)
starter-node-documentation       |     at /usr/app/node_modules/express/lib/router/index.js:284:7
starter-node-documentation       |     at Function.process_params (/usr/app/node_modules/express/lib/router/index.js:335:12)
starter-node-documentation       |     at next (/usr/app/node_modules/express/lib/router/index.js:275:10)
starter-node-documentation       |     at /usr/app/node_modules/express-openapi-validator/dist/middlewares/openapi.multipart.js:37:13
starter-node-documentation       |     at Layer.handle [as handle_request] (/usr/app/node_modules/express/lib/router/layer.js:95:5)
starter-node-documentation       |     at trim_prefix (/usr/app/node_modules/express/lib/router/index.js:317:13)
starter-node-documentation       |     at /usr/app/node_modules/express/lib/router/index.js:284:7

Im using node, docker, express etc.

Here is my code:

// some code above
const documentation = require('./components/documentation')
// some code below

new OpenApiValidator({
  apiSpec: documentation,
  validateResponses: true
}).install(app)

documentation is JSON object. According to error, which is pointing on row 16, it looks like problem is here:
const securities = req.openapi.schema.security || context.apiDoc.security;

I tried to add security[] to my documentation, but it doesnt work, so I assume problem is req.openapi.schema.scurity. To makes it clear, my app has 2 backends, one is for app, which is used by FE (there are all routes like get/post/...), second one is for OpenAPI documentation (we are using swagger-ui-express, nothing for production, thats why validator is here) which is using first one, where are all routes.

My questions is: its something with validator or where validator is using (BE for OpenAPI - no production)

Thank you :)

Unhandled async exceptions in validator middleware(s)

Issue #90 made me wonder a little how come I didn't get any reply from the package when there was an exception thrown during the (security) validations. Express.js does catch every exception and calls next with the exception error. Why didn't my error handler got called with the exception?
The only cases Express.js doesn't catch - are exceptions thrown in an async operation. I went and check the code of this package and indeed the middlewares used here are async. Express.js cannot handle async exceptions as it doesn't have the context.
More about express error handling can be found here: error handling
So what happens when an unhandled async exception is thrown during a middleware? Two things:

  1. The client doesn't get a reply and hangs until a timeout is reached.
  2. Node.js itself catches the unhandled async exception (node-1904). However, this "catch" is deprecated and in future versions will be removed, meaning the process will exit.
    Since we want to use the validator in production - we cannot let it hang the response to the client or make the process exit. We have to catch every exception - even if it's caused by an unknown bug. We have to be on the safe side, just in case.

So what do we need to do? Easy, just wrap every middleware we return (security, validation and so on) with a Promise.resolve().then(() => try {...original code...} catch (next))
A nicer way is to have a function defined in one place that wraps all the middlewares we return.
More about this solution can be found here: async error handling

I tried this solution on the previous version with the hang - and it worked! I got an error in my error handler and I could return a server error to my client.
I believe we should use this wrapper function to make our middlewares safe as we want to use the validation in production environments. It's alway better to return 500 server error than to not return at all and let node terminate/handle it for us.

I would do the PR myself, but again - I am not a TypeScript person, so I do not know how to add the wrapper function to the utils file and make it export. So I guess someone else can do it - if you decide this is required.

Parameters using $ref are not validated

Given a path such as:

  /pets/{id}:
    get:
      description: Returns a user based on a single ID, if the user does not have access to the pet
      operationId: find pet by id
      parameters:
        - $ref: '#/components/parameters/id'
      responses:
        '200':
          description: pet response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

And a component:

components:
  parameters:
    id:
      name: id
      in: path
      description: ID of pet to fetch
      required: true
      schema:
        type: integer
        format: int64

The parameter isn't validated.

I'm not sure if that is a design decision or something that will be supported in future? Thanks

Response validation

Thanks for this useful lib.
I have small question - is it possible to validate response? I've tried to return payload not matching oas spec schema and seems like there is no error.

path value starts with a dot

In some of your examples, the path attribute is prefixed with a dot, for example:

"path": ".params.id", "path": ".query.limit",

This looks odd - is it a bug?

tests fail intermittently with 400

When I'm running tests where I'm spinning up new instances of express servers between suites, I'm getting intermittent 400 errors for the tests that deal with a particular POST endpoint (requestBody validation). The failure happens about once every couple of tries.

When I mock the validator or comment it out, all the tests pass consistently.

I'm not absolutely sure, but my hunch is that the test is running while the app is still in the "installation" phase. Is there a possibility of adding a callback or letting install() return a promise?

for reference, the tests that are failing are these:

    it('should create todo', async done => {
      const insertedTodo = todoCollection[0];
      await TodoModel.create(insertedTodo);
      request(expressMongoServer.app)
        .post('/v1/todo')
        .send(insertedTodo)
        .expect('Content-type', /json/)
        .end((err, res) => {
          expect(res.status).toEqual(201);
          const todoRes = res.body;
          expect(todoRes._id).toBeTruthy();
          expect(todoRes).toEqual(
            expect.objectContaining({ description: insertedTodo.description, category: insertedTodo.category })
          );
          done();
        });
    });
  });

and

   it('should create todo', async done => {
      const insertedTodo = todoCollection[0];
      mockRepoDependency({ createTodo: (todo: typeof insertedTodo) => Promise.resolve(todo) });

      const MockExpressServer = await import('./helpers/express-server-mock');
      const expressServer = new MockExpressServer.default();

      await expressServer.start();
      request(expressServer.app)
        .post('/v1/todo')
        .send(insertedTodo)
        .expect('Content-type', /json/)
        .end((err, res) => {
          expect(res.status).toEqual(201);
          const todoRes = res.body;
          expect(todoRes).toEqual(
            expect.objectContaining({ description: insertedTodo.description, category: insertedTodo.category })
          );
          done();
        });
      expressServer.stop();
    });

Validator does not work with express router

I am not sure if this is a feature request or a bug, but the validator does not validate requests and responses to/from express routers.

When I originally set up my app, all of my routes lived in the app.ts file and were being validated correctly.

app.ts

const app = express();
app.use(bodyParser.json());
app.use(express.json());

new OpenApiValidator({
  apiSpec: './workflow-tracker-openapi.yml',
  validateRequests: true,
  validateResponses: true,
}).install(app);

// Validates correctly! :)
app.get('/v1/progress/:workflowType', function(req, res, next) {
  res.json([{id: 1, name: 'test'}]);
});

however I am going to have a lot of routes + middlewares and want to use express routers to split them up. So I split my routes to use a router and the validator stopped working:

app.ts

const app = express();
app.use(bodyParser.json());
app.use(express.json());
app.use('/v1', progressRouter);

new OpenApiValidator({
  apiSpec: './workflow-tracker-openapi.yml',
  validateRequests: true,
  validateResponses: true,
}).install(app);

api/progress.ts

const router = express.Router();

// No longer validated :(
router.get('/progress/:workflowType', function(req, res, next) {
  res.json([{id: 1, name: 'test'}]);
});

export { router as progressRouter };

Furthermore I tried to install the routers to the OpenApiValidator but it only accepts Applications.

Am I missed a configuration step or are routers not supported currently? If they are not, is there timeline for when they would be supported?

Is there another workaround for this?

thank you!

Validation for security

Validate if the security defined in the api spec exists in the api call.
If doesn't exist should return 401.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.