Giter VIP home page Giter VIP logo

committee's People

Contributors

adamaiken89 avatar adelcambre avatar brandur avatar dane avatar danp avatar datbth avatar dependabot[bot] avatar geemus avatar hokuma avatar juice10 avatar kehra avatar maurobellati avatar meganemura avatar michaelsauter avatar mmcgrana avatar mt-kelvintaywl avatar nicolasiensen avatar nullnull avatar ohbarye avatar olleolleolle avatar ota42y avatar r7kamura avatar ravbaker avatar ricardochimal avatar ronen avatar scottatron avatar swalkinshaw avatar tzmfreedom avatar ydah avatar yhirano55 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

committee's Issues

GET request when using no Committee::Middleware::RequestValidation

I have a simple rails index action say: GET#host.com/v1/plans. When RequestValidation middlewhere in place, I get an error if I don't define a "schema" property:

NoMethodError (undefined method `properties' for nil:NilClass):

If I do define a schema.. i don't know what schema to define as technically I'm just making a GET request with no actual parameters or data required.

How do I handle this situation where I want to leave the RequestValidation middlewhere in but I have a simple get request with no actual schema.

Handle options requests in order to avoid CORS errors

I am currently working on a Node application that is consuming an API I built into a Rails application. I have configured my Rails app to allow POST (also, PUT and DELETE) requests by handling OPTIONS requests that precede them.

Here is the console error I see in Chrome when making the same request against the mock API provided when running committee.

OPTIONS http://localhost:9000/apps/123456/reports
XMLHttpRequest cannot load http://localhost:9000/apps/123456/reports. No 'Access-Control-Allow- Origin' header is present on the requested resource. Origin http://localhost:8080 is therefore not allowed access. The response had HTTP status code 404.

I may find the time to figure this out myself, but I am sure I am not the only person that has run into this issue.

Pluggable error responses?

Would there be interest in having pluggable error responses? Right now we're using Committee on an API adhering to JSON API, which specifies it's own error format. I can add this functionality, just want to be sure it's something y'all would be interested in.

Creating a Validation module

ParamsValidator and ResponseValidator contain sections of nearly identical code. Thoughts on pulling validations out into a Validation module that both classes share?

No support for explode field in array query parameters

For example, an optional query parameter of a string value, allowing multiple values by repeating the query parameter:

/path:
  get:
    parameters:
      - name: id
        in: query
        description: ID of the object to fetch
        schema:
          type: array
          items:
            type: integer
        explode: false

so this will be interpreted as /path?id=1,2,3, but the committee middleware will give a 400 response with this body:

"{\"type\":\"bad_request\",\"message\":\"#/paths/~1path/get/parameters/2/schema expected array, but received String: 635\"}"

This is the specification of OpenAPI.
https://swagger.io/docs/specification/serialization/#query
https://spec.openapis.org/oas/v3.0.2#fixed-fields-9

Allow skipping committee validation

Summary

I want to skip committee validation by passing a env option or something.

Why

Sometime, we want to parse errors of raised by committee so that we can translate other language (ex: Japanese or Chinese) or we can log according to type of error.

And when we create parsing module , we have to except that internal errors of the parsing module may happen.

To catch errors happened in the layer of middleware(is committee, in this context), it is sufficient to arrange a dedicated module above committee in middleware stack.

However, what should we do when we want to ignore internal errors of the parsing module and return to application process, or when catch committee-raised-error just to log and return to application process?
(Just calling @app.call(env) causes committee’s error again!)

I wish we can skip committee’s validation when we use @app.call(env) in a specific way,

How

For example, I think it’s good if we set env[‘skip_committee_validation’] true, committee just call @app.call(env).
Specifically, in lib/committee/middleware/base.rb,

def call(env)
  request = Rack::Request.new(env)

-if @router.includes_request?(request)
+if @router.includes_request?(request) && !env['skip_committee_validation']  # check env option here
    handle(request)
  else
    @app.call(request.env)
   end
end

If you agree with this, I will create a pull request.
Thank you for reading.

Feature Request: handle InvalidResponse Error but not change the original response

Especially in the production environment, we sometimes want to enable the Committee::ResponseValidation and just notify an alert to Slack or Sentry etc, but still return the original response.
As far as I understand, the middleware makes the response as status:500 by default, and it can be customized but I don't find the way to just respond with the original.

schema should follow properties (not definitions) to find schemata

Things other than sub-schema could be in definitions (ie shared property definitions to DRY up stuff like created_at/uuid/updated_at for instance). We expect, however, that everything linked to from the top level properties (via JSON pointers) will be sub-schema.

To facilitate this we will probably need to replace (or at least add in parallel) a more sophisticated dereference and then change things like [] and each on schema to follow dereferenced properties.

Since I've tackled this a couple times before (in prmd/heroics), I figure I'm probably best equipped to handle this quickly/effectively. So hopefully will fix tomorrow or so, but wanted to record details for reference/posterity.

Allow generation of array examples

prmd can generate examples for Array types by adding the example of the items within the array. I would love if committee-stub could do this too.

If someone could point me in the right direction I'd love to try and address this.

Suggestion: behavior of StringParamsCoercer for boolean

The current behavior that how StringParamsCoercer coerces string to boolean is:

when "boolean"
coerced[k] = true if original_val == "true"
coerced[k] = false if original_val == "false"
end

so, the s value is regarded as boolean, it coerces (or doesn't coerce) query such as follows.

?s=true #=> true
?s=false #=> false
?s=1 #=> "1"
?s= #=> ""

After the value passed through coercer, it is sometimes boolean but sometimes not. So application code needs more validation code and it often becomes a bit complicated.

As far as I know, there is no rule that how the form-urlencoded param should be coerced to boolean value,
but in my experience, s= is often regarded as s: false, and s=1 as s: true. (Of course it's debatable. )

So, here is my suggestion: if the string value is empty or "false", it is coerced to false. else, it is coerced to true.

?s=1 #=> true
?s=asdf #=> true
?s= #=> false

Any thoughts? Thanks.

OpenApi 2.0 "Committee: no name section in link data" when parameter is using a reference

I'm trying to load specs located here. I'm working from a local version and I had to remove a couple unsupported "format" tags. But once I do that, I get an ArgumentError for Committee: no name section in link data. Digging in it's failing in the ParameterSchemaBuilder because it's checking

"parameters": [
  {
    "$ref": "#/parameters/authorization"
  }
]

and not seeing a name key for check_required_fields!.
Looking at the code there's no place before that point that would fill the reference, so I don't know if it should pass the check or if there should be some translation before that point. Or maybe I misunderstood how 2.0 is allowed to use references?

RequestValidation middleware and error responses

Using the RequestValidation middleware with raise: true works fine for successful responses but breaks down a bit for errors. For example, say I want to return this from my app's GET /apps endpoint:

404 Not Found
{
  "id": "not_found",
  "message": "app not found"
}

It fails validation since my schema says GET /apps will return something that looks like an app.

I initially see a few options for this:

  • add a way to skip validation of non-2xx responses (and maybe make it the default?)
  • add an error_schema param that is expected to contain the schema for all non-2xx responses
  • use anyOf in my schema to say all links can return a successful representation or an error representation

I think the third is an interesting long-term option but I'll probably start by trying out the first.

Thoughts?

string pattern not supported in openapi 3

I am attempting to use Committee::Middleware::RequestValidation to validate against an OpenApi v3 schema:

openapi: 3.0.0
paths:

  /api/v1/events/{id}/bookable_spaces:
    get:
      description: get bookable spaces for an event
      parameters:
      - name: start_time
        in: query
        description: starting time for space availability check
        required: true
        schema:
          type: string
          pattern: '[0-9]{1,2}:[0-9]{2}'
      - name: end_time
        in: query
        description: ending time for space availability check
        required: true
        schema:
          type: string
          pattern: '[0-9]{1,2}:[0-9]{2}'

Unfortunately the pattern option does not appear to be honored. Is this a known issue or am I missing something?

Query parameters are not supported

Consider the following link to search for a car based on color and number of doors:

links: [
    {
        "description": "Find",
        "href": "/cars?color={(%23%2Fdefinitions%2Fcars%2Fdefinitions%2Fcolor)}&door={(%23%2Fdefinitions%2Fcars%2Fdefinitions%2Fdoor)}",
        "method": "GET",
        "rel": "self",
        "title": "search"
    }
]

If I use committees test method assert_schema_conform, it raises an error:

Failure/Error: assert_schema_conform
     Committee::InvalidResponse:
       `GET /cars` undefined in schema.

Is there perhaps a better way of doing this?

How can I use a hyperschema that references external schemas?

Hello, I started this question as a comment at brandur/json_schema#22, but it's perhaps more appropriate here.

I'd like to break my API hyperschema into a separate files for better modularity and easier management; and in fact I may want to refer to schemas that are defined externally, but I'm not certain how to do that with Committee:Middleware::RequestValidation.

For example, the hyperschema might include something like:

"links": [
    {
      "description": "Create a widget",
      "href": "/widgets",
      "method": "POST",
      "rel": "create",
      "title": "Create Widget",
      "schema": { "$ref": "file://schemas/widget-create-request.schema.json" },
      "targetSchema": { "$ref": "file://schemas/widget-create-response.schema.json" }
    },
    ...
  ]

The request and response schemas might themselves refer to a URI for an externally-defined widget schema, e.g. something like:

{
    "type": "object",
    "properties": {
         "metadata": { "type": "object" }
         "widget": { "$ref": "http://widget-host.com/schemas/widget.schema.json" }
    },
    "required": ["widget"]
}

In the discussion at brandur/json_schema#22 it seems that one must set things up to use "id" rather than $ref, and must pre-load the external schemas into a JsonSchema::DocumentStore which is then used to expand references on a JsonSchema object.

I can probably figure out the use of "id" in my schemas, but how can I use JsonSchema::DocumentStore when configuring the middleware -- there's no documented parameter for it at:

 use Committee::Middleware::RequestValidation, schema: JSON.parse(File.read(...))

Thanks for any advice!

PS. Lacking anything else, I'll probably do a preprocessing step on my own to load the schema and recursively expand $ref's, before passing it to use Committee::Middleware::RequestValidation. Not the most elegant thing in the world, but should work.

No support for custom attributes in openapi 2

I have an openapi file like

/path:
    x-some-extensions:
      doc:
        ......
      slo:
        .....
    get:
      summary: Get All ,....
      parameters:
        - $ref: "#/parameters/..."

I get an exception:

undefined method `[]' for nil:NilClass (NoMethodError)
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/committee-3.0.1/lib/committee/drivers/open_api_2.rb:262:in `find_best_fit_response'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/committee-3.0.1/lib/committee/drivers/open_api_2.rb:350:in `block (2 levels) in parse_routes!'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/committee-3.0.1/lib/committee/drivers/open_api_2.rb:327:in `each'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/committee-3.0.1/lib/committee/drivers/open_api_2.rb:327:in `block in parse_routes!'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/committee-3.0.1/lib/committee/drivers/open_api_2.rb:322:in `each'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/committee-3.0.1/lib/committee/drivers/open_api_2.rb:322:in `parse_routes!'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/committee-3.0.1/lib/committee/drivers/open_api_2.rb:65:in `parse'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/committee-3.0.1/lib/committee/drivers.rb:61:in `load_from_data'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/committee-3.0.1/lib/committee/drivers.rb:29:in `load_from_yaml'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/committee-3.0.1/lib/committee/drivers.rb:40:in `load_from_file'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/committee-3.0.1/lib/committee/middleware/base.rb:28:in `get_schema'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/committee-3.0.1/lib/committee/middleware/base.rb:9:in `initialize'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/committee-3.0.1/lib/committee/middleware/response_validation.rb:6:in `initialize'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/stack.rb:37:in `new'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/stack.rb:37:in `build'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/stack.rb:101:in `block in build'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/stack.rb:101:in `each'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/stack.rb:101:in `inject'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/stack.rb:101:in `build'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/railties-5.2.3/lib/rails/engine.rb:510:in `block in app'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/railties-5.2.3/lib/rails/engine.rb:506:in `synchronize'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/railties-5.2.3/lib/rails/engine.rb:506:in `app'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/railties-5.2.3/lib/rails/application/finisher.rb:47:in `block in <module:Finisher>'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/railties-5.2.3/lib/rails/initializable.rb:32:in `instance_exec'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/railties-5.2.3/lib/rails/initializable.rb:32:in `run'
/Users/jordi/.rvm/gems/ruby-2.6.0/gems/railties-5.2.3/lib/rails/initializable.rb:61:in `block in run_initializers'
/Users/jordi/.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:228:in `block in tsort_each'
/Users/jordi/.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
/Users/jordi/.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:431:in `each_strongly_connected_component_from'
/Users/jordi/.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:349:in `block in each_strongly_connected_component'
/Users/jordi/.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:347:in `each'
/Users/jordi/.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:347:in `call'
/Users/jordi/.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:347:in `each_strongly_connected_component'
/Users/jordi/.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:226:in `tsort_each'
/Users/jordi/.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/tsort.rb:205:in `tsort_each'

I believe the problem is link_data["responses"]["200"] where link_data is my x-some-extensions as there are no responses inside that block, that's nil and blows up.

Can this be an alternative to Rails's Strong Parameters?

Hi, I'm using Rails (5). I want to validate request, but also want to pick only defined keys by using json schema.

For example:

the json schema defines a key as required and b key as optional.
the http request params is { a: 1, b: 2, c: 3 }
=> I'm happy if the params (which can be used in controller) is { a: 1, b: 2 }.
Then I don't need to use Strong Parameters of Rails.

If not, I may have to implement same validation logic as json schema to controllers using Strong Parameters.
Does committee have such a feature?
If not, do you think the feature is useful and can be implemented?

Thank you.

Status 204 (No Content) raises Committee::InvalidResponse

I've got an API call that returns status 204 (no content), and ResponseValidation raisesCommittee:InvalidResponse

The culprit is:

data = MultiJson.decode(full_body)

        data = MultiJson.decode(full_body)

With no content, full_body is an empty string and so MultiJson.decode(full_body) raisesMultiJson::LoadError.

I've made a quick patch to address this, by skipping validation if status is 204. I put it in a separate PR, since I could imagine you might want to address this in some other way. In particular, it could perhaps be more robust to allow targetSchema to specify no content somehow (via "type": "null" ?), and then explicitly validate that there is no content.

Possibility of skipping validation of request ContentType

Currently, Committee in line:

check_content_type!(request, data)
is verifying is request ContentType is same as the one declared in Scema encType field. By default JSONSchema uses application/json and this validator prevents POST/PUT requests with ContentType application/x-www-form-urlencoded. But Rack is constructed the way that it is handling both the same way and parsing input params regardless of type of content.

App I'm working on requires to allow for both content types, so this behavior of Rack/Sinatra is good for my case. But when I added RequestValidation from Committee it refuses requests with different ContentType than application/json.

So I believe it would be good to allow skipping this check_content_type! method execution by setting some option when configuring this middleware (Committee::Middleware:: RequestValidation).

Do you see it possible?

Request mime type validation a bit too strict. Should allow `charset`

Hey Folks,

I was poking around the request validation code a couple weeks ago and made a little TODO in my notebook to look back at this mime type validation line when I had the time. Well, today I had the time.

A little backstory:
Committee uses rack for request validation of the mime type. Currently rack will compare a check for application/json with "application/json", and "application/*" or "*" and all will return true. This is fine and awesome. The type and subtype should match when we're validating the the Content-Type is what the schema defines.

The problem:
The issue here is that there are additional parameters that can be passed along with the Content-Type. Specifically the error case that I have is when specifying the charset for an "application/json" request. This mean is that if I make a request with "application/json; charset=utf8" and I have the request validation middleware running, all my requests will fail.

I think this is too strict.

"application/json" & "application/json; charset=utf8" are inherently the same type/subtype. The parameter is this case is there to help inform the host of encoding but does not change the Content-Type the host expects.

Generally I would have just sent up a PR with a change stripping the parameters from the Content-Type header, but I wanted to chat about if we should be doing that in committee or in rack... or if my opinion is wrong. Thoughts?

Rails modifies path_info which confuses committee

When customising Rails' exceptions response middleware (exceptions_app), it rewrites path_info. This fails the schema assertions because committee won't find the original path when it looks at path_info. assert_schema_conform instead looks for /500 or /<error_code> paths in the schema document.

Not sure if this is a problem for committee or for rails, but it makes writing accurate schema doc difficult. If this was to be addressed here then you could find the original path before rewrite in the ORIGINAL_FULLPATH header instead.

Warning GET method with request body.

See: #210

It's our own rule, so the new users are difficult to understand.
So I think we should provide disable/warning option and default disable to avoid using GET request body.
(I'll implement 3.1.0)

committee-stub and custom formats

I have a JSON schema with a custom format.

I registered this format with in my tests, to not get a JsonSchema::AggregateError

JsonSchema.configure do |c|
  c.register_format 'ISO 639-2', ->(data) { data =~ /\A[a-z]{3}\z/ }
end

This is of course not considered when running committee-stub.
So I get the error message "ISO 639-2" is not a valid format, must be one of date, date-time, email, hostname, ipv4, ipv6, regex, uri, uuid. (JsonSchema::AggregateError)

How can I register this format also when using committee-stub?

One idea could be to add a --require config/initializers/json_schema option to committee-stub

Freezes (100% CPU) inspecting a Middleware

Ever since adding committee to our Rails app (then Rails 3, now Rails 4) we have been having a very annoying issue: if we have a typo or other mistake during development where we refer to a non-existent method or variable, the application becomes unresponsive and goes to 100% CPU, requiring a ctrl C and sometimes a kill -9.

Our config/application.rb has the following:

config.middleware.use ::Committee::Middleware::RequestValidation,
      :schema => JSON.parse(File.read(schema_path)),
      :prefix => "/api/v1"

and I confirmed the issue is related to Committee by taking out this line, and the problem going away.

I'm not sure exactly how the call stack gets there, but somewhere in Rack or Rails as part of dealing with a NoMethodError, it ends up calling .inspect on the instance of RequestValidation. (Edit - it is probably the view that presents contents of request, env etc. for debugging errors in dev, or something like NewRelic while in production) This, in turn calls .inspect on the instance variables including @Schema and @router. These 2 in particular are problems because they contain JsonSchema::Schema objects. I actually tracked down the problem to coming from json_schema itself, in that the JsonSchema::Schema#inspect is incredibly verbose, and in any non-trivial schemas it appears to lock-up my system. I think this has something to do with the recursive nature of schemas that reference each other.

I have a repo here that demonstrates the issue: https://github.com/mcclymont/rails4-routing-example. I used the heroku schema as it is public. It is considerably larger than the schema we are using for our internal project.

I'm not sure if json_schema is maintained by the same team as committee. If so, maybe we can fix how json_schema is inspected, if there is a problem. Otherwise committee could implement its own #inspect and not inspect the JsonSchema stuff

Pull 1.7.0 release

Since the latest release of committee is 1.6.5, could the 1.7.0 release be removed from rubygems (or 1.7.1 pushed out?). I think things are out of order because of #66. /cc @brandur

Add support for 'multipart/form-data' file upload

I'm attempting to describe file upload, according to swagger docs for file-upload we should define the file as type string with the format of binary.

so my openapi for this request looks like:

      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                contractId:
                  type: string
                  example: 270A2087-6335-455E-B32D-350C00FFEEB7
                organisationId:
                  description: Your ID for this participant
                  example: AAA123
                  type: string
                resourceId:
                  type: string
                  example: 49E2797A-A62E-4042-9587-2CC0A1DBC679
                file:
                  type: string
                  format: binary

However by the time this gets to the committee middleware rack has exploded the file to a hash

file: {
  :filename=>"i_am_a_file.csv", 
  :type=>"text/plain", 
  :name=>"file", 
  :tempfile=>#<Tempfile:/tmp/RackMultipart20200306-13-1rx39tl.csv>, 
  :head=>"Content-Disposition: form-data; name=\"file\"; filename=\"i_am_a_file.csv\"\r\nContent-Type: text/plain\r\nContent-Length: 81\r\n"
}

so we end up with an error like:

#/paths/~1api~1v1~1telemetry_data_files/post/requestBody/content/multipart~1form-data/schema/properties/file expected string, but received Hash:

I was looking at test/request_unpacker_test.rb but I do not see how to handle this situation. What am I missing?

Using `additionalProperties` in schema validation

Hey everyone - I'm a little new to OpenAPI and using the committee gem (so I might be doing something wrong here!), but in any case I wanted to file an issue for some behavior that I'm seeing that doesn't quite align with what I was expecting. 🙈

I'm using the committee test helper assert_schema_conform to validate responses in my tests and I'm using additionalProperties: false in my schema to indicate that the object should not have any additional fields.

What I'm expecting is that when a response comes back and it includes properties that are not explicitly defined in the schema to error. What I'm seeing is that the assertion passes.

I put up some example code that demonstrates this here: https://github.com/liamgriffiths/committee-demo

I haven't begun to start investigating this any deeper just yet, but wanted to just make sure that this was not just me making a goof somewhere.

I also think this is likely not an issue that is directly related to committee and something in the underlying json_schema library. But because it was surfacing for me in committee I opened this one here for now.

Thanks in advance if anyone can help! 🍻

Rack Param and RequestValidator

We use PRMD to generate our json schema and documentation so the schema has specificity on the type of the request parameters, and furthermore we want to validate the type. However Rack:Utils.parse_nested_query makes all request parameters "string" type. This means that if our schema has specified an integer type and even if the rspec test specifies an integer it will still get passed through by Rack as a string and then committee will throw a RequestValidation error:

#rspec
patch "/test_endpoint", test_param: 451

>> #/test_endpoint: failed schema #/definitions/test_endpoint/links/6/schema/properties/test_param: For 'properties/test_param', "451" is not an integer.

This seems like a general issue in using request validation with Rack/rspec. What am I missing here?

Support for non-JSON response validation

I have an OpenAPI 3 spec that for one of the responses return a HTTP 302 response, for example:

# snippet
paths:
    /faq/{id}:
    get:
      description: |
        fetch a FAQ page (HTTP 302 redirect to our external CMS for FAQ page)
      responses:
        '302':
          description: Response of a Connect redirect
          headers:
            Location:
              schema:
                type: string
               description: Redirection URL
           content:
             text/plain:
               schema:
                 type: string

and since OpenAPI3's response_validate handler will attempt to always parse response body to JSON:

def response_validate(status, headers, response, test_method = false)
full_body = +""
response.each do |chunk|
full_body << chunk
end
data = full_body.empty? ? {} : JSON.parse(full_body)
strict = test_method
Committee::SchemaValidator::OpenAPI3::ResponseValidator.
new(@operation_object, validator_option).
call(status, headers, data, strict)
end

This is the same for HyperSchema too:

def response_validate(status, headers, response, _test_method = false)
return unless link_exist?
full_body = +""
response.each do |chunk|
full_body << chunk
end
data = full_body.empty? ? {} : JSON.parse(full_body)
Committee::SchemaValidator::HyperSchema::ResponseValidator.new(link, validate_success_only: validator_option.validate_success_only).call(status, headers, data)
end

I ended up having to set validate_success_only to true, but that meant I turned off validation for all non HTTP 2XX responses including client errors (HTTP 4XX) :(

Would be nice for the response_validate to attempt to only parse as JSON based on the Content-Type response header?

Support path component from OAS 3 'servers'

For example my spec.json has a section like this:

  "servers": [
    {
      "url": "https://dor-services-{env}.stanford.edu/{version}",
      "description": "Production service",
      "variables": {
        "env": {
          "default": "prod"
        },
        "version": {
          "default": "v1"
        }
      }
    }
]

so my paths section has keys like this: "/objects/{id}" and those are on the server at /v1/objects/{id}. Currently with this config, the committee middleware will give a 404 response with this body:

"{\"id\":\"not_found\",\"message\":\"That request method and path combination isn't defined.\"}"

Unknown param does not trigger error

Given the request validation middleware is enabled

use(
  Committee::Middleware::RequestValidation,
  schema_path: '...',
  strict: true,
  raise: true
)

And a route with one defined param:

/myroute:
  post:
    parameters:
      - in: "body"
        name: "only_param"
        required: true

When I make an invalid request:

curl -X POST -d only_param="a" invalid_param="b"

No error is raised. The readme example shows that an error should be raised or returned, depending on the configuration.

OpenAPI 2.0: All parameter types are heaped into single bucket during request validation

Currently when unpacking a request Committee heaps all parameters from a request no matter their type, form, body, query, or URL, into a single bucket and then performs validation against them.

This doesn't work too badly, but we should really be respecting the in value of an OpenAPI definition (e.g. in: query) so that if a parameter is meant to be in the query, a form parameter of the same name will not suffice.

string with format: date not working

Hi,

I'm trying to validate requests using request validation middleware. In one of my API, I'm using following rule for one of my query params in API.

{
            "name" : "from_date",
            "in" : "query",
            "schema" : {
              "type" : "string",
              "format" : "date",
              "example" : "2017-09-24"
            }
 }

As per, this rule request should fail if passed value is not a valid date but it's not failing if I pass from_date=abc.

If I update format to date-time and then if I pass from_date=abc then it's giving me error as expected.

Request should fail if format is date and I pass from_date=abc.

Validation of GET params

If I have a GET endpoint that takes a parameter of type integer, the validation fails, since the parameter is actually of type string. For POST endpoints, this problem does not exist since in the JSON payload, I can explicitly pass an integer. For GET, that's not possible. Is that true or am I missing something really obvious?

I had a look through the request validation code to see how it works but there's no immediate solution to the problem that comes to my mind. Any ideas? I guess somehow committee should allow a string that is only numbers as an integer?

Unknown custom data types

The following is fine with prmd:

"actor": {
      "description": "description",
      "format": "object",
      "type": [
        "api_user"
      ]
    }

where apI_user is another type of schema object defined elsewhere. However, in committee, it doesn't seem to be able to pick these up, instead yielding:

#/definitions/thing/definitions/actor: Unknown types: api_user.

Possibly overly-strict content-type validation?

Hey, I ran into an edge case on content-type validation (I think). In particular, though we don't really use it, there are cases where 204 makes sense (and where it doesn't really make sense to say content-type json). Does that makes sense? The code in question is here:

def check_content_type!(headers)

I'd be happy to work up a patch, but just wanted to make sure I wasn't missing something before I went too far down that path.

committee stub should support adhoc style response example

Current committee stub can only generate response like
resource: {'field': value}
or resources: [{'field': value}]

Sometimes rpc like url has adhoc response format,

eg: POST /books/actions/read-one-book
returns { 'how_many_books_left': 100 }

need solve the following issues:

  • where to put response schema (not request schema) into links description?
  • implement stub response generation
  • fix document generation

Cannot assert on actual headers: Rack mutates header key

Given an OpenApi3 swagger yaml definition for a header:

x-Role: &Role
  in: "header"
  name: "Role"
  required: true
  schema:
    type: "string"
    enum: ["A", "B"]

And given a valid request:

curl ... -H "Role: A"

Committee, when raising an error, raises the following error for this request:

Committee::InvalidRequest:
       #/paths/... missing required parameters: Role

This is because Rack mutates all http headers, and Role becomes HTTP_ROLE.

This would seem unrelated to this gem, except that it is designed as Rack middleware, so it seems odd that it wouldn't work with rack conventions.

I'm not too familiar with the gem yet, but a first idea for a solution might be to cast all swagger-defined headers into HTTP_x formats before passing to validation.

Matching paths with parameters does not recognize due to failing to split on extension `.`

Foremost, thanks for the great Gem.

I am applying this Gem retroactively to a project to add an OAS3 specification to its API. The API in question explicitly requires the response format as part of the URL, instead of a MIME type. I believe Committee cannot recognize this at the moment, thus I'm leaving an issue here. I'm happy to help fix, but given that is my first issue, I wanted to reach out first.

Here's the issue: for my project, if I want to update an object called a Fribble, with the ID parameter 123, I would call:

PUT /v1/fribble/123.json

... to invoke the API. In my OAS3 document, it looks like this:

paths:
  /v1/fribble/{id}.json:
    put:
      # and so on

Expected behavior: path matches, and my request/response is validated by Committee.
Actual behavior: path does not match, and nothing is validated.

Upon investigation, I noticed that OpenAPIParser::PathItemFinder splits path names on the / character when trying to infer path parameters in matching_paths_with_params.
Doing so leaves my actual parameter -- 123 -- mixed in with .json, which does not match the parameter type of integer (at least, I am assuming this is why it does not match), and thus, I assume that the request remains unmatched.

I locally can "fix" the problem by changing the split('/') method to instead split on forward slashes or periods: split(/[\/\.]/), however I feel that that may have adverse effects as well if paths had periods in them (which is totally valid).

I could attempt to fix this by only splitting on the . when it is at the end of the request path (e.g. there is no trailing / afterward).

If I am merely "holding it wrong", I sincerely apologize for raising the issue; I do understand that the API spec I am trying to model is quite odd in its interpretation, but that is precisely why I want to use this tool to improve it :)

Thanks in advance for your time.

Feature request: check response headers

I want to assert whether a response header matches OpenAPI definition.

There is check_header option already, but it seems to check only request headers. And there is no way to check response headers.

Example

Given following schema,

openapi: 3.0.0
info:
  title: Sample API
  version: 0.1.0

paths:
  /auth/sign_in:
    post:
      operationId: SignIn
      summary: Sign in
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                password:
                  type: string
      responses:
        '200':
          description: A User auth object.
          content:
            application/json:
              schema:
                type: object
                properties:
                  email:
                    type: string
                  name:
                    type: string
          headers:
            access-token:
              schema:
                type: string

the following test is expected to fail because the server responses with wrong header key.

class ResponseHeaderTest < Test::Unit::TestCase
  include Committee::Test::Methods
  include Rack::Test::Methods

  def app
    Sinatra.new do
      post "/auth/sign_in" do
        content_type :json
        headers['access-tokem'] = 'token' # header key typo
        JSON.generate(email: '[email protected]', name: 'Some User Name')
      end
    end
  end

  def test_response_header_conforms
    post "/auth/sign_in", JSON.generate(email: '[email protected]', password: 'somepassword')
    assert_response_schema_confirm # assertion should fail
  end
end

Add support for multiple versions to middleware

I love the idea of having middleware in place to check request and response data, but it doesn't appear that they support multiple versions. The middleware take a schema option, but if you have multiple versions this schema won't be known ahead of time and you have to choose one. (I started adding directories to represent versions to docs/schema -- is this proper?) What do y'all think about this?

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.