interagent / committee Goto Github PK
View Code? Open in Web Editor NEWA collection of Rack middleware to support JSON Schema.
License: MIT License
A collection of Rack middleware to support JSON Schema.
License: MIT License
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.
Could you add description of coerce_form_params
option to README.md? Sorry, I'm not a native English speaker so it's difficult for me.
(P.S. This option seems to be working well for my project.)
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 loadhttp://localhost:9000/apps/123456/reports
. No 'Access-Control-Allow- Origin' header is present on the requested resource. Originhttp://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.
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.
ParamsValidator
and ResponseValidator
contain sections of nearly identical code. Thoughts on pulling validations out into a Validation
module that both classes share?
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
I want to skip committee validation by passing a env option or something.
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,
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.
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.
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.
Looks like @brandur may have forgotten to push the tag?
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.
The current behavior that how StringParamsCoercer coerces string to boolean is:
committee/lib/committee/string_params_coercer.rb
Lines 39 to 42 in a99f1b4
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.
Hey guys ,
just wondering if this supports swagger json schema ?
In fact i'm thinking of a workflow where i'd first design my API with the swagger editor then extract the schema and push a mock server based on that on heroku and focus on the front end, with something like middleman...
cc @mattolson
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?
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:
error_schema
param that is expected to contain the schema for all non-2xx responsesanyOf
in my schema to say all links can return a successful representation or an error representationI think the third is an interesting long-term option but I'll probably start by trying out the first.
Thoughts?
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?
If Content-Type: application/json
is not specified on an incoming request, committee.params
will end up as a weird hash with one really long key that looks like the incoming JSON. We should probably fix this to be empty, or at the very least, not look so weird.
/cc @deafbybeheading
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?
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.
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.
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.
As commented on
https://github.com/interagent/committee/blob/master/lib/committee/request_unpacker.rb#L81-L87
No support for request body which is Array/Int/String (not Hash) and raise error Invalid JSON input. Require object with parameters as keys.
Want to support these not Hash request body
I've got an API call that returns status 204 (no content), and ResponseValidation raisesCommittee:InvalidResponse
The culprit is:
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.
Currently, Committee in line:
is verifying is request ContentType is same as the one declared in ScemaencType
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?
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?
I'm sorry I bother you again. Could you also describe coerce_path_params
option in README?
Related to #114 .
I checked the options and the difference between implementation and documentation is only this option.
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.
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)
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
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
On line 10 of router.rb the matching should be path =~ Regexp.new("\A#{pattern}\z")
or something similar. Declaring a JSON Schema entry pointing to /
matches everything unless its placed at the very end of the JSON file.
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?
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! 🍻
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?
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:
committee/lib/committee/schema_validator/open_api_3.rb
Lines 28 to 39 in fe8570a
This is the same for HyperSchema too:
committee/lib/committee/schema_validator/hyper_schema.rb
Lines 31 to 40 in fe8570a
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?
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.\"}"
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.
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.
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
.
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?
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.
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:
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.
Does committee gem have plans to support OpenAPI 3.0?
I would be happy if you would consider it.
Ran into an issue with rack-test where it is setting Content-Type: application/x-www-form-urlencoded
on non-GET
requests. This makes RequestValidation
blow up here.
Should request validation ignore Content-Type
on requests where it doesn't make sense?
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:
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.
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.
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.
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
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?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.