Code Monkey home page Code Monkey logo

osprey-method-handler's Introduction

Osprey Method Handler

NPM version NPM Downloads Build status Test coverage Greenkeeper badge

Middleware for validating requests and responses based on a RAML method object.

Installation

npm install osprey-method-handler --save

Features

  • Supports RAML 0.8 and RAML 1.0
  • Header validation (ignores undocumented headers)
  • Query validation (ignores undocumented parameters)
  • Request body validation
    • JSON schemas
    • XML schemas
    • URL-encoded formParameters (ignores undocumented parameters)
    • Multipart form data formParameters (ignores undocumented parameters)
    • Discards unknown bodies
  • Accept content type negotiation (based on defined success response bodies)
  • Automatically parsed request bodies
    • JSON (req.body)
    • URL-encoded (req.body)
    • XML (req.xml)
    • Form Data (req.form using Busboy, but you need to pipe the request into it - req.pipe(req.form))

Please note: Due to the build time of libxmljs, it does not come bundled. If you need XML validation, please install libxmljs as a dependency of your own project.

Usage

const express = require('express')
const handler = require('osprey-method-handler')
const utils = require('./utils')

const app = express()

// webapi-parser.Operation
const methodObj = utils.getMethodObj()
const options = {}

app.post(
  '/users',
  handler(methodObj, '/users', 'POST', options),
  function (req, res) {
    res.send('success')
  }
)

Accepts webapi-parser Operation object as first argument, path string as second argument, method name as third and options object as final argument.

Options

  • ajv Custom Ajv instance to be used to validate query strings, request headers and request bodied (url-encoded, form-data, json)
  • discardUnknownBodies Discard undefined request streams (default: true)
  • discardUnknownQueryParameters Discard undefined query parameters (default: true)
  • discardUnknownHeaders Discard undefined header parameters (always includes known headers) (default: true)
  • parseBodiesOnWildcard Toggle parsing bodies on wildcard body support (default: false)
  • reviver The reviver passed to JSON.parse for JSON endpoints
  • limit The maximum bytes for XML, JSON and URL-encoded endpoints (default: '100kb')
  • parameterLimit The maximum number of URL-encoded parameters (default: 1000)
  • busboyLimits The multipart limits defined by Busboy

Adding JSON schemas

If you are using external JSON schemas with $ref, you can add them to the module before you compile the middleware. Use handler.addJsonSchema(schema, key) to compile automatically when used.

handler.addJsonSchema() accepts a third (optional) options argument. Supported options are:

  • ajv Custom Ajv instance. E.g. handler.addJsonSchema(schema, key, {ajv: myAjvInstance}). The provided ajv instance can later be passed as an option to the handler to perform validation.

Validation Errors

The library intercepts incoming requests and does validation. It will respond with 400, 406 or 415 error instances from http-errors. Validation errors are attached to 400 instances and noted using ramlValidation = true and requestErrors = [] (an array of errors that were found, compatible with request-error-handler).

See the code for a complete list of errors formats.

Please note: XML validation does not have a way to get the keyword, dataPath, data or schema. Instead, it has a meta object that contains information from libxmljs (domain, code, level, column, line).

To render the error messages for your application, look into error handling for Express, Connect, Router or any other middleware error handler. If you want a pre-built error handler, try using request-error-handler, which provides a pre-defined error formatter.

License

MIT license

osprey-method-handler's People

Contributors

blakeembrey avatar boyko avatar brevity avatar cmd-johnson avatar forsakenharmony avatar greenkeeper[bot] avatar greenkeeperio-bot avatar jstoiko avatar postatum avatar ronalddddd avatar svc-scm avatar

Stargazers

 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  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

osprey-method-handler's Issues

UnsupportedMediaTypeError handling

UnsupportedMediaTypeError: No body sent with request for PUT /api/something with content-type "undefined"

Seems that there is no way to handle such error ?

err object appears to be empty for this case.

Please advise

Thanks

ospreyMethodHandler does not handle request.queryString

RAML 1.0 and AML-AMF WebApi allow query string parameters to be defined as either queryParameters xor queryString.

RAML 1.0 defines queryParameters as a properties declaration list and queryString as a type or type expression.
https://nicedoc.io/raml-org/raml-spec/blob/master/versions/raml-10/raml-10.md#query-strings-and-query-parameters

AML AMF WebApi models a request with properties queryParameters: Parameter[] and queryString: Shape.
https://github.com/aml-org/amf/blob/develop/documentation/model.md#request

webapi-parser.Operation.Request has properties queryParameters: Parameter[] and queryString: Shape.
https://github.com/raml-org/webapi-parser/blob/494156d904f813cc5edfa6215b0a265e7589d9c5/js/module/typings/amf-client-js.d.ts#L1333-L1343

ospreyMethodHandler does not handle method.request.queryString.
This can cause all query string parameters to be discarded if the original RAML used the queryString node.

if (hasRequest && method.request.queryParameters.length > 0) {
middleware.push(queryHandler(method.request.queryParameters, options))
} else if (options.discardUnknownQueryParameters) {
debug(
'%s %s: Discarding all query parameters: ' +
'Define "queryParameters" to receive parameters',
methodName,
path
)
middleware.push(ospreyFastQuery)
}
return compose(middleware)
}

acceptHandler: (TypeError: Cannot convert undefined or null to object)

While updating dependencies I ran into an issue going from version 0.4.1 --> 0.5.0.

It looks like in the latest version in the acceptHandler it requires that responses contain a body. Where as previous versions did not require a body, is this an intended change?

Object.keys(responses || {})
    .filter(function (code) {
      return code >= 200 && code < 300
    })
    .forEach(function (code) {
      var response = responses[code]
      var body = response ? response.body : {}

      Object.keys(body).forEach(function (type) {
        accepts[type] = true
      })
    })

Root Cause
This line in particular is assuming if there is a response that there is a body nested within that response, and if there is not a body in the response, the body variable is set to null or undefined

var body = response ? response.body : {}

and then the body gets here and then fails

Object.keys(body).forEach(function (type) {

Problem

/Users/jlofton/Desktop/goBalto/bloodhound/node_modules/osprey-method-handler/osprey-method-handler.js:167
      Object.keys(body).forEach(function (type) {
             ^

TypeError: Cannot convert undefined or null to object
    at Function.keys (<anonymous>)
    at /Users/jlofton/Desktop/goBalto/bloodhound/node_modules/osprey-method-handler/osprey-method-handler.js:167:14
    at Array.forEach (<anonymous>)
    at acceptsHandler (/Users/jlofton/Desktop/goBalto/bloodhound/node_modules/osprey-method-handler/osprey-method-handler.js:163:6)
    at ospreyMethodHandler (/Users/jlofton/Desktop/goBalto/bloodhound/node_modules/osprey-method-handler/osprey-method-handler.js:127:21)
    at /Users/jlofton/Desktop/goBalto/bloodhound/node_modules/osprey/lib/server.js:30:12
    at /Users/jlofton/Desktop/goBalto/bloodhound/node_modules/osprey-resources/osprey-resources.js:58:20
    at Array.forEach (<anonymous>)

Suggested Fix
The previous version of this line works

var body = response && response.body || {}

Again not sure if this is an intended change or not, thanks!

Implement logging with `debug`

Some things don't need to be logged out as publicly, such as "parameters missing", but others like choosing to discard the body should be logged loudly when debugging.

Better validation errors

The current errors only provide an error message and status code. It needs to provide the array of errors that occurred and all other information in a standardised format for error output on the server.

An in-range update of ajv is breaking the build 🚨

The dependency ajv was updated from 6.11.0 to 6.12.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

ajv is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • ❌ continuous-integration/travis-ci/push: The Travis CI build failed (Details).

Release Notes for v6.12.0

Improved hostname validation (@sambauers, #1143)
Option keywords to add custom keywords (@franciscomorais, #1137)
Types fixes (@boenrobot, @MattiAstedrone)
Docs:

Commits

The new version differs by 33 commits.

  • 03d0012 6.12.0
  • 1021a00 Merge branch 'RadiationSickness-patch-1'
  • 0163e5c docs: error logging code sample
  • 52adde5 Merge branch 'patch-1' of git://github.com/RadiationSickness/ajv into RadiationSickness-patch-1
  • 8fd1e44 Merge branch 'franciscomorais-feature/keywords-options'
  • e5bed30 test: update option keywords test
  • c90c189 Merge branch 'feature/keywords-options' of git://github.com/franciscomorais/ajv into franciscomorais-feature/keywords-options
  • 38191c2 Update readme with keywords option
  • f94db48 Update options validation spec
  • 367527c Merge branch 'master' into patch-1
  • c1c0ba7 Merge pull request #1091 from thetric/typescript-usage-note
  • 75aa5fd Merge pull request #1143 from sambauers/master
  • 120748c Only use regex for hostname checks.
  • 384eec4 Merge branch 'master' into master
  • 4d9dd8c docs: link to $data reference proposal, closes #51

There are 33 commits in total.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Unexpected error if schema field of request body declaration refers to schema declared in root section

In cases where the schema field of a request body declaration for application/json type refers to a named schema declared in the root section of the RAML content as in the following example, I have observed that an unexpected error is thrown when creating the ospreyMethodHandler for the associated RAML.

Example RAML snippet

schemas:
  - newBooking: !include schemas/createEventBooking.json
/createEventBooking:
  post:
    body:
      application/json:
        schema: newBooking

Problem
This results in the following unexpected error when attempting to create the associated ospreyMethodHandler.

Error: Unable to compile JSON schema for post /pps/v3/core/createEventBooking: Unexpected token e in JSON at position 1

Root Cause
Here is the offending code I found in the jsonBodyHandler() function that causes this error.

  var schema = body && (body.properties || body.type) || undefined
  var isRAMLType = schema ? schema.constructor === {}.constructor : false

  // This is most likely a JSON schema
  if (!schema) {
    schema = body.schema

The body.schema in the example RAML shown above is "newBooking" while the actual JSON schema content is in body.schemaContent. The value "newBooking" assigned to the schema variable is then passed as input to jsonBodyValidationHandler() which then attempts to perform JSON.parse() on this value resulting in the observed error. In cases where the schema field in the RAML definition of a request/response body for a given media type is an inline JSON schema or refers to an external schema via an include statement, the logic above works fine because the schema content in these cases is populated in both body.schema and body.schemaContent by the raml-1-parser that is being used to parse the RAML.

Suggested Fix
Change the assignment statement from schema = body.schema to schema = body.schemaContent || body.schema

Response validation

Validate responses match the RAML schemas for methods.

  • Status code
  • Response body
  • Response headers

BadRequestError : Request failed to validate against RAML definition

When I started the server :

header problem 1

When I tried a request , with the content of validation, if it could help

header problem 3

Here is all my raml files :

Api.raml

title: My api 
baseUri: htttp://admin.secret.eu/{version}
version: v1
mediaType: application/json


uses:
    Answers:     libraries/answers.raml
    Requests:    libraries/requests.raml

/webhook:
   /registeredUser:
        post:
          description: Register a new call log for a registered user
          headers:
            Content-Type:
              enum: ["application/json"]
              required: true
          body:
            application/json:
                  type: Requests.RegisteredUserCallRequest
          responses:
              200:
                  body:
                      application/json:
                          type:   Answers.APIAnswer
              400:
                  body:
                      application/json:
                          type:   Answers.APIAnswer

requests.raml

#%RAML 1.0 Library
types:
   RegisteredUserCallRequest:
        properties:
          phoneNumberUsed:
              type:   string
              description:    The phone number used to call us
              example:    "+55151151515"
              maxLength: 20
              required: true
          dateTime:
	      type:   datetime
              description:    A datetime with timezone
              example:    2016-02-28T16:41:41.090Z
              format: rfc3339  # the default, so no need to specify
              required: true
          userId:
              required: true
              type:   integer
              description: The customer Id from another Bepark database
              example:    12357
          userName:
              type:   string
              description:    The name and first name of the caller
              example:    temporary account (partner)
              required: true
              maxLength: 100
          IvrNumber:
              description:    Interactive voice response number
              type:   number
              example:    444521414545
              required:   false
          IvrRef:
              description:    Interactive voice response reference
              type:   string
              example:    "44645486546546845486"
              required:   false
              maxLength: 25

answers.raml

#%RAML 1.0 Library
types:
    APIAnswer:
        properties:
            message:    string
            status:     integer

PS: Sorry for the red color for date : Linguist doesn't seem to like RAML 1.0 : https://help.github.com/articles/creating-and-highlighting-code-blocks/

TypeError: Cannot read property 'constructor' of undefined at jsonBodyHandler osprey-method-handler.js:347:26

Hello,
I'm facing an issue with osprey-mock-service and I tracked it down to this library.
When I'm loading a a RAML (0.8) with only an example in the body property:

put:
    is: [userSecured]

    description: |
        Update member's contact information

    body:
        application/json:
            example: !include ../examples-fixtures/request/200-put-account-contact-information.json

I'm having an error: TypeError: Cannot read property 'constructor' of undefined at jsonBodyHandler osprey-method-handler.js:347:26

And this seems legit regarding this so called line:

var schema = body && (body.properties || body.type || body.schema) || undefined
  var isRAMLType = schema.constructor === {}.constructor

Ive looked back at the RAML 1.0 spec and type OR schema seems to be mandatory but it's not in 0.8.

Is this parser only compatible with RAML 1.0 and I'm missing a conf in the parent lib in order to use a 0.8 compatible parser or is this an error in this parser ?

Thanks !

An in-range update of debug is breaking the build 🚨

Version 3.2.0 of debug was just published.

Branch Build failing 🚨
Dependency debug
Current Version 3.1.0
Type dependency

This version is covered by your current version range and after updating it in your project the build failed.

debug is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • ❌ continuous-integration/travis-ci/push: The Travis CI build failed (Details).

Release Notes 3.2.0

A long-awaited release to debug is available now: 3.2.0.

Due to the delay in release and the number of changes made (including bumping dependencies in order to mitigate vulnerabilities), it is highly recommended maintainers update to the latest package version and test thoroughly.


Minor Changes

Patches

Credits

Huge thanks to @DanielRuf, @EirikBirkeland, @KyleStay, @Qix-, @abenhamdine, @alexey-pelykh, @DiegoRBaquero, @febbraro, @kwolfy, and @TooTallNate for their help!

Commits

The new version differs by 25 commits.

There are 25 commits in total.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

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.