Add Sinatra integration (OpenapiFirst::Sinatra) - #483
Conversation
640794f to
de8bce8
Compare
There was a problem hiding this comment.
Nicely done — reads clean and is unusually well-tested and documented for an experimental extension. Inline notes below; two more worth flagging beyond those:
1 (design) — routing is delegated to Sinatra/Mustermann, but validation uses the OAD template. The two matchers can diverge at the edges (trailing slash, dot-in-segment, encoding, greediness): a request Mustermann matches is validated against the template it was defined with, using the params Mustermann extracted — not openapi_first's own path matching. Fine for the covered cases; worth a docs note that the two routers' path semantics should be kept aligned. (Mustermann itself is healthy — 4.0.0, Apr 2026 — so this is about semantic divergence, not dependency risk.)
5 (minor) — build_operation_index is first-wins on duplicate operationIds (index[operation_id] ||= …): a duplicate is silently dropped. Invalid OAD, but a warn/raise would beat silent.
🤖 Generated with Claude Code
| # The parsed request body | ||
| # @return [Sinatra::IndifferentHash] | ||
| def parsed_body | ||
| ::Sinatra::IndifferentHash[openapi_request.parsed_body] |
There was a problem hiding this comment.
parsed_body assumes an object body: Sinatra::IndifferentHash[openapi_request.parsed_body] raises for a top-level JSON array/scalar body (and for a bodyless request, where parsed_body is nil). Consider guarding for non-Hash bodies, or documenting it as object-only and pointing to openapi_request.parsed_body for arrays/scalars.
🤖 Generated with Claude Code
|
|
||
| def validate(request, route_params:) | ||
| parsed_request, error = parse_request(request, route_params:) | ||
| def validate(request, path_params:) |
There was a problem hiding this comment.
Naming flag: route_params: → path_params: is clearer (they are path params). If Request#validate / parse_request count as public / manual-use API, this is a breaking keyword rename — worth a CHANGELOG line; ignore if they're internal.
🤖 Generated with Claude Code
| ``` | ||
|
|
||
| The HTTP method and path for each route come from the operationId. | ||
| Request validation is called automatically for these operations |
There was a problem hiding this comment.
Formatting nits: add a blank line before ## 3.4.3, give this line a trailing period, and drop the trailing whitespace on the closing ``` fence a few lines up. (README also has trailing whitespace on the blank line inside the create_pet example, ~L442.)
🤖 Generated with Claude Code
|
Reviewed as a downstream consumer of the gem — really solid, well-documented, and thoroughly tested. Three points worth raising (all advisory): Classic (top-level) app auto-registration is untestedThe file ends with Falsy
|
|
@jzobel Is that you? Please mark LLM generated communication as such so people can tell if these opinions are coming from a real engineer. About the feature gap: You should still be able to configure the error response format globally. Do you think we need an additional way to configure that? |
|
Sorry for the sloppyness, I updated "my" comments.
Absolutely right, Claude and I got that wrong. Sorry for the noise! |
Resolve the path for an operation by operationId, filling in path parameters. Extracted from the Sinatra integration, where it backs the operation_url helper. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A Sinatra extension to define routes by referencing OpenAPI operations,
so URLs and HTTP methods live only in the description:
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
end
The HTTP method and path for each route come from the operationId.
Request validation is called automatically for these operations.
A Sinatra extension to define routes by referencing OpenAPI operations, so URLs and HTTP methods live only in the API description:
The HTTP method and path for each route come from the operationId. Request validation is called automatically for these operations.
Why?
Related to #365