Conversation
Smaug123
force-pushed
the
openapi-3
branch
2 times, most recently
from
July 11, 2026 13:56
688da70 to
e3cc53c
Compare
The HTTP client generator had no case for an option-typed [<Query>] parameter, so it fell through to the scalar path and emitted `param.ToString()`. For `Some 3` that yields `page=Some%283%29`, and for `None` it throws a NullReferenceException, since F#'s None is null at runtime. An option-typed query parameter now contributes zero or one key=value pair, via Option.map/Option.toList, so None is omitted from the URL and an all-None query leaves the URL bare. Query strings made only of required parameters are byte-identical to before, so no existing generated client changes. This is the client-side half of #546, without that PR's change to SwaggerClientGenerator (which additionally made unannotated Swagger 2 query parameters optional, and was rejected for the churn). Nothing currently generates optional query parameters; this makes it possible for them to be generated correctly when they are. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: GPT-5.6 Sol Ultra
The petstore spec's `limit` on GET /pets is `required: false`, so the generator plans it as `int option` — but nothing exercised ListPets at runtime, so the broken encoding it previously produced (`limit=Some%2825%29`, and a NullReferenceException on None) went unnoticed. Regenerating on top of the option-aware query encoding fixes the emitted client; this pins the behaviour with a test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts: # CHANGELOG.md # ConsumePlugin/GeneratedRestClient.fs # ConsumePlugin/RestApiExample.fs # WoofWare.Myriad.Plugins.Test/TestHttpClient/TestOptionalQueryParam.fs # WoofWare.Myriad.Plugins/HttpClientGenerator.fs
The OpenAPI 3.0 planner ignored `security` and `components.securitySchemes` entirely, so a document which required authentication silently generated a client which sent none. Each security scheme an operation requires now becomes an abstract property on the generated interface, and hence a `unit -> string` argument of `make` which is called afresh on every request needing that credential. Each operation sends exactly the credentials its own requirement asks for: `security: []` sends none and doesn't even ask for them, and a requirement naming several schemes sends all of them. Where an operation offers alternatives, the first satisfiable one is applied, and which one that is is visible in the generated source; the new `SecuritySchemes` Myriad parameter restricts the choice. An operation with no satisfiable requirement is now a build failure rather than a silently unauthenticated client. Supported schemes are the header-carried ones: `apiKey` in a header, `http` of any scheme, and `oauth2`/`openIdConnect`, for which the caller supplies the `Authorization` header value. No token flow is performed. Expressing this needed a way to set a header on only some of an interface's members, so this also adds `[<HeaderFromProperty(header, propertyName)>]` to the `HttpClient` generator: the named property still becomes a `unit -> _` argument of `make`, but only the members which name it call it. `[<RestEase.Header>]` on a property continues to apply to every member. The property may be named by a literal or by `nameof Unchecked.defaultof<IMyApi>.TheProperty`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two bugs found by a Codex review of 5703dd1, both of which would have produced a broken client from a valid document. An interface property whose name lowercases to `client` collided with the HttpClient argument the generator adds to `make`, so a security scheme named "client" produced `let make (client : unit -> string) (client : HttpClient)`, which doesn't compile. The HttpClient generator now names its own argument around the properties, as it already did for the `queryString` binding. Two schemes in one requirement could demand the same header — an `http` scheme alongside an `oauth2` one, say, both of which carry `Authorization`. Each is individually representable, so we selected the requirement and then emitted two `Headers.Add ("Authorization", _)` calls, which throws on every request. Such an alternative is now unsatisfiable, so a later alternative can be chosen instead, or the build fails. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Taking the first satisfiable alternative meant that a document offering
several — as real specs commonly do — silently chose an authentication method
on the caller's behalf. Gitea's Swagger spec is the motivating example: it
offers seven alternatives on every endpoint, four of which we can carry, so
"first wins" would conscript every consumer into HTTP Basic.
A document lists its alternatives in no particular order, so document order is
not a preference. Exactly one alternative must now be satisfiable; several is
an AmbiguousSecurity diagnostic naming the candidates, and the caller says
which they want with the SecuritySchemes parameter. This matches the Swagger
2.0 generator.
The empty requirement {} counts as a candidate like any other: an operation
offering both "no credentials" and a real scheme is a genuine choice, and
sending nothing is exactly the silently-unauthenticated client this all exists
to prevent. Setting SecuritySchemes empty takes that alternative wherever the
document offers it.
Alternatives naming the same schemes are deduplicated first, since a repeated
alternative is one choice rather than two.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First commit is pure slop (GPT-5.6 Sol Ultra)