Skip to content

Version 4.0.0 - #502

Merged
ahx merged 1 commit into
mainfrom
v4
Sep 17, 2026
Merged

ahx merged 1 commit into
mainfrom
v4

Conversation

@ahx

@ahx ahx commented Sep 17, 2026

Copy link
Copy Markdown
Owner

This release has no stricter or less strict request validation. It changes mostly internal stuff and adds a Sinatra integration. It's a major version, but it should be safe to upgrade.

Breaking changes

  • Uploaded files are no longer read during request validation. Before, the whole content of every multipart/form-data part that was sent as a file was read into memory, which allowed a single large upload to any documented multipart route to exhaust the memory of the server process. Such a field is now passed through as Rack parsed it ({ filename:, type:, name:, tempfile:, head: }), which is the same shape that Sinatra and Hanami hand to your application. Use parsed_body['file'][:tempfile] to read or stream the file.
    • The content of these fields is not validated anymore, so minLength, maxLength or pattern on a field that was sent as a file are ignored.
    • An after_request_body_property_validation hook sees an empty String instead of the file.
    • Fields that were not sent as a file, and fields with a JSON contentType in the encoding map, are read and validated as before.
  • The openapi_parameters gem was merged into openapi_first and is not a dependency anymore. Parameter parsing now lives in openapi_first itself. If you registered a parser for parameters that use a content field, use OpenapiFirst::ParameterContentParsers.register instead of OpenapiParameters::ContentParsers.register.
  • Changed: OpenapiFirst::ResponseHeader (returned by Response#headers, renamed from OpenapiFirst::Header) exposes parameter, an OpenapiFirst::Parameter, instead of node.
  • Changed: OpenapiFirst::Request#parameters returns the parameters that are defined for a request as OpenapiFirst::Parameter objects, which expose name, location, schema, required?, deprecated?, style, explode? and media_type.

Removed deprecations

  • Removed: OpenapiFirst::Configuration#request_validation_raise_error and #response_validation_raise_error (both reader and writer), deprecated since 3.0.0. Pass raise_error: to middlewares instead.
  • Removed: OpenapiFirst::Test::Configuration#coverage_formatter, #coverage_formatter=, #coverage_formatter_options and #coverage_formatter_options=, deprecated since 3.4.0. Use #coverage_reporter / #coverage_reporter_options instead.
  • Removed: OpenapiFirst::Test::Coverage::TerminalFormatter, deprecated since 3.4.0. Use OpenapiFirst::Test::Coverage::TerminalReporter instead.
  • Removed: The formatter: keyword of OpenapiFirst::Test.report_coverage, deprecated since 3.4.0. Use reporter: instead.
  • Removed: OpenapiFirst::Test::Coverage::TerminalReporter#format, deprecated since 3.4.0. Use #report instead.

Added

  • Added: API coverage now reports skipped requests and responses.

  • Added: OpenAPI 3.2 documents are accepted, but not fully supported yet. They are handled using the OpenAPI 3.1 rules, so features introduced in 3.2 may be ignored. Loading such a document prints a warning. Operations defined under additionalOperations are routed. See #469.

  • Added: Show all covered endpoints in HTML coverage reporter and filter covered/uncovered endpoints.

  • Added: Sinatra integration (OpenapiFirst::Sinatra)
    A Sinatra extension to define routes by referencing OpenAPI operations:

      require 'openapi_first/sinatra'
    
      class PetsApi < Sinatra::Base
        register OpenapiFirst::Sinatra
        openapi 'openapi.yaml'
    
        operation :index_pets do |params|
          json index_pets(params[:filter])
        end
    
        operation :create_pet do
          pet = create_pet(parsed_body)
          headers['Location'] = operation_url(:show_pet, petId: pet.id)
          status :created
          json pet
        end
    
        operation :show_pet do |params|
          json show_pet(params[:petId])
        end
      end

    The HTTP method and path for each route come from the operationId.
    Request validation is called automatically for these operations.

Fixed

  • Fixed: Validating against a schema from a referenced file raised ArgumentError in OpenAPI 3.0 documents when a top-level key of that file collides with a JSON Schema keyword, such as $ref: 'parameters.yaml#/id'. The containing file is no longer parsed as a schema itself, so such keys work like any other now. See #348.
  • Fixed: $refs nested inside the schema of a parameter or a response header are resolved now, so these values are unpacked and converted as described. Before, only a $ref at the top level of the schema was resolved. See deepObject paramters with array values do not support nested $refs #450.
  • Fixed: The JSON schema of a parameter that uses a content field with a $ref'd schema is resolved now.
  • Fixed: Loading a document no longer raises NoMethodError when a parameter has neither schema nor content.
  • Fixed: Repeated values for a query parameter that describes an object or uses content (?filter=a&filter=b) raised a NoMethodError or TypeError. The values are validated against the schema now, which returns an :invalid_query failure.
  • Fixed: A parameter with style: matrix raised a NoMethodError if its value did not contain the parameter name, or contained it more than once. Such values are parsed like their explode counterpart now.
  • Fixed: A parameter with style: matrix, or a path parameter that describes an object, raised an ArgumentError if its value had an invalid %-encoding. Such values are validated against the schema now.
  • Fixed: A path, header or cookie parameter that uses a content field with a value that could not be parsed as that media type (e.g. 007 as application/json) was converted using the parameter's schema type anyway, which could make an invalid value pass schema validation (e.g. as the integer 7). Such values are left as they are now, so schema validation rejects them as before.
  • Fixed: Reduced memory retained by a loaded Definition. Response headers with a schema no longer keep the whole raw document node alive, and a couple of build-time-only hashes were replaced with more compact structures.

@ahx
ahx merged commit 70ea695 into main Sep 17, 2026
32 checks passed
@ahx
ahx deleted the v4 branch September 17, 2026 14:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant