mulesoft-labs / osprey-method-handler

Middleware for validating requests and responses based on a RAML method object
Other
16 stars 16 forks source link

BadRequestError : Request failed to validate against RAML definition #21

Closed jy95 closed 7 years ago

jy95 commented 7 years ago

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/

jy95 commented 7 years ago

A more clear display for error : error

jy95 commented 7 years ago

The fix I found (cannot make a pull request or commit here) :

function headerHandler (headerParameters, path, method, options) {
  // FIX FOR RAML 1.0 : headerParameters is an array like [ "0" : {key: "Content-type", ...} ]
    var headerParametersObjForRaml1 = {}
    headerParameters.forEach(function(parameter){
        if (parameter.hasOwnProperty("key")) {
            headerParametersObjForRaml1[parameter.key] = parameter
        }
    })
  var headers = (options.RAMLVersion == 'RAML10') ? extend(DEFAULT_REQUEST_HEADER_PARAMS,lowercaseKeys(headerParametersObjForRaml1)) :  extend(DEFAULT_REQUEST_HEADER_PARAMS, lowercaseKeys(headerParameters))
  var sanitize = ramlSanitize(headers)
  var validate = ramlValidate(headers, options.RAMLVersion)

  return function ospreyMethodHeader (req, res, next) {
    var headers = sanitize(lowercaseKeys(req.headers))
    var result = validate(headers)

    if (!result.valid) {
      return next(createValidationError(formatRamlErrors(result.errors, 'header')))
    }

    // Unsets invalid headers. Does not touch `rawHeaders`.
    req.headers = options.discardUnknownHeaders === false ? extend(req.headers, headers) : headers

    return next()
  }
}

Now I must fix issue with bodyHandler ... the raml 1.0 types is like the headParameters issue

jy95 commented 7 years ago

bodyHandler : normally finished

function bodyHandler (bodies, path, method, options) {
  var bodyMap = {}
    var bodiesTypes = {}
    bodies.forEach(function(body){
        if (body.hasOwnProperty("key")) {
            bodiesTypes[body.key] = body
        }
    })
    var universalBodies = (options.RAMLVersion == "RAML10") ? bodiesTypes : bodies;
  var types = (options.RAMLVersion == "RAML10") ? Object.keys(bodiesTypes) : Object.keys(bodies)
  types.forEach(function (type) {
    var handlers = BODY_HANDLERS
      .filter(function (handler) {
        return is.is(handler[0], type)
      })

    // Do not parse on wildcards.
    if (handlers.length > 1 && !options.parseBodiesOnWildcard) {
      return
    }

    // Attach existing handlers.
    handlers.forEach(function (handler) {
      var properType = handler[0]
      var fn = handler[1]

      bodyMap[properType] = fn(universalBodies[type], path, method, options)
    })
  })
jy95 commented 7 years ago

And finally :

function jsonBodyValidationHandler (schema, path, method, options) {
  var jsonSchemaCompatibility = require('json-schema-compatibility')
  var validate
    if (schema.constructor === [].constructor){
        // array of properties
        //console.log(schema)
        var schemaObject = {}
        schema.forEach(function(property){
            if (property.hasOwnProperty("key")) {
                // remove the unuseful properties that can make ramlValidation become crazy
                delete property.examples
                delete property.typePropertyKind
                schemaObject[property.key] = property
            }
        })
        schema = schemaObject
        //console.log(schemaObject)
    }

    var isRAMLType = schema.constructor === {}.constructor
  // RAML data types
  if (isRAMLType) {
    validate = ramlValidate(schema, options.RAMLVersion)

  // JSON schema
  } else {
    try {

      schema = JSON.parse(schema);

      // Convert draft-03 schema to 04.
      if (JSON_SCHEMA_03.test(schema.$schema)) {
        schema = jsonSchemaCompatibility.v4(schema)
        schema.$schema = 'http://json-schema.org/draft-04/schema'
      }
        console.log(schema);
      validate = ajv.compile(schema)
    } catch (err) {
      err.message = 'Unable to compile JSON schema for ' + method + ' ' + path + ': ' + err.message
      throw err
    }
  }

The fix on my fork : https://github.com/jy95/osprey-method-handler.

sichvoge commented 7 years ago

Did you consider adding a PR for that? You only need to use your fork and send a PR from that.

jy95 commented 7 years ago

I tried to make a pull request directly with Intellij Idea (but I got error 403) . That is why I forked the project. I will do the PR with github right now. Intellij Idea has removed the indentation so a lot of lines are modified XD

jstoiko commented 7 years ago

Let's discuss this here: https://github.com/mulesoft/osprey/issues/133#issuecomment-283840943