interagent / committee

A collection of Rack middleware to support JSON Schema.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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