assert_response_schema_confirm : impossible to validate integers in Headers
garz75 opened this issue · comments
Hello,
I am using committee-rails and committee to add schema validation tests for the responses of our APIs. We also use Pagy response pagination gem that adds headers to the request (total number of result pages, current pages, etc.) , so our OpenAPI definition specifies these headers as integers:
headers:
Current-Page:
schema:
type: integer
description: |
[RFC288 Pagination header](https://tools.ietf.org/html/rfc8288): Current page number
example: 2
However, when using `assert_response_schema_confirm(200) to check the JSON schema for the response, we get the error:
Invalid response for OpenAPI schema /Users/fgarzon/Dev/fft_api_doc/fft_server/openapi.yaml
- Headers: {"Content-Type"=>"application/json; charset=utf-8", "Link"=>"<http://www.example.com/api/v2/parcels?reference=162&page=1>; rel=\"first\", <http://www.example.com/api/v2/parcels?reference=162&page=1>; rel=\"last\"", "Current-Page"=>"1", "Page-Items"=>"5", "Total-Pages"=>"1", "Total-Count"=>"1", "ETag"=>"W/\"9edc3cf0bb6c09890b9df541eb9fe866\"", "Cache-Control"=>"max-age=0, private, must-revalidate", "X-Request-Id"=>"e9f565bc-f208-4c57-930e-5aa30c16b477", "X-Runtime"=>"0.003913", "Content-Length"=>"193"}
- Body: [{"id":6043,"reference":"162","type":"internal","status":"waiting","cancellable":true,"item_count":1,"description":"return 142","allow_bulk_handing":true,"to_hand_to":"Transporteur (Interne)"}]
Request:
- Path: /api/v2/parcels?reference=162
- Method: GET
- Body:
ERROR["test_0001_returns the expected parcel", #<Minitest::Reporters::Suite:0x00007fed4c77f010 @name="with reference filter">, 11.45178499999929]
test_0001_returns the expected parcel#with reference filter (11.45s)
Minitest::UnexpectedError: Committee::InvalidResponse: #/paths/~1parcels/get/responses/200/headers/Current-Page/schema expected integer, but received String: "1"
test/support/assertions.rb:22:in `assert_response_v2_api'
test/integration/parcels/index_test.rb:141:in `block (2 levels) in <class:ParcelsIndexTest>'
You can see in the verbose output above, the ActionDispatch::Response::Header object that stores the response headers stores the "integer values" as strings. But when sent on the wire, they are in integer format:
$ curl -v -u runner:<a password> -H "Accept: application/json" http://localhost:3000/api/v2/parcels
* Trying ::1:3000...
* Connected to localhost (::1) port 3000 (#0)
* Server auth using Basic with user 'runner'
> GET /api/v2/parcels HTTP/1.1
> Host: localhost:3000
> Authorization: Basic <some b64 string>
> User-Agent: curl/7.77.0
> Accept: application/json
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Link: <http://localhost:3000/api/v2/parcels?page=1>; rel="first", <http://localhost:3000/api/v2/parcels?page=1>; rel="last"
< Current-Page: 1
< Page-Items: 5
< Total-Pages: 1
< Total-Count: 1
< ETag: W/"b26995e4184fe0b06e6811d07105e9ea"
< Cache-Control: max-age=0, private, must-revalidate
< X-Request-Id: ec7cb80a-35cc-425c-9aa1-d202b3b8e09b
< X-Runtime: 0.887195
< Transfer-Encoding: chunked
<
* Connection #0 to host localhost left intact
My question is: why does the committee validation for this header fail ? Am I missing something here ? Thank you in advance
def assert_response_v2_api(code)
assert_response(code)
return unless ENV["V2_API_OPENAPI_SCHEMA_FILE"]
begin
assert_response_schema_confirm(code)
rescue Committee::InvalidResponse => exception
puts <<~INFO
Invalid response for OpenAPI schema #{ENV['V2_API_OPENAPI_SCHEMA_FILE']}
- Headers: #{response.headers}
- Body: #{response.body}
Request:
- Path: #{request.fullpath}
- Method: #{request.method}
- Body: #{request.body&.string}
INFO
raise exception
end
end
Your OpenAPI Specification defile Current-Page as integer but rails set string (which we can convert integer) so committee raising error is correct works.
But we can't use integer in header because many library expect HTTP header as string.
So committee response validation can effectively only support strings.
It's not good feature, so we need to add coerce_header
option to response validation.
I'm sorry, but until then, please use the string
Thank you for your answer. I will have a look to the source code and see if I have what it takes to add this option.
This is something where openapi_parameters could help. Here's a test that describes the behavior: https://github.com/ahx/openapi_parameters/blob/main/spec/openapi_parameters/header_spec.rb#L16-L19