Skip to content

Commit ee7e8fc

Browse files
Smaug123claude
andcommitted
Fix six correctness defects in Swagger 2 generation and capturing mocks
Swagger 2 parsing (SwaggerV2.fs): - Endpoint responses were fed whole Response Objects to Definition.Parse, so inline {description, schema} responses degraded to Unspecified and generated Task<unit> clients. Responses now go through Response.Parse and use its schema; $refs are handled as before. Inline endpoint schemas (responses and parameters) are also now seeded into type generation, so anonymous inline object schemas get generated types. - Response keys were unconditionally Int32.Parsed, so any spec with a "default" response aborted generation. Responses are now keyed by a ResponseKey DU (Code of int | Default), and the generator explicitly ignores Default when selecting the success response. Swagger 2 client generation (SwaggerClientGenerator.fs): - Integer formats were ignored; "format": "int64" now renders as int64 instead of narrowing 64-bit IDs to int. - The request Content-Type header was derived from Produces, and Consumes was dropped entirely. Content-Type now comes from Consumes and Produces is sent as the Accept header, both as full MIME strings (endpoint-level lists override the spec-global ones). This made the StartsWith active pattern dead, so Text.fs is deleted. - SwaggerParameter.Required was parsed and discarded, making every parameter mandatory. Query parameters without required: true are now option-typed, and None is omitted from the URL. HTTP client generation (HttpClientGenerator.fs): - Option-typed [<Query>] parameters are supported: the query string is now computed at runtime and appended (with separator) only when nonempty, so a URL with all-None query parameters stays bare. Capturing mock generation (CapturingInterfaceMockGenerator.fs): - Property getters logged nothing; they now record into Calls under a lock, like methods do. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 039eb3b commit ee7e8fc

17 files changed

Lines changed: 5432 additions & 2314 deletions

ConsumePlugin/Generated2SwaggerGitea.fs

Lines changed: 3600 additions & 1382 deletions
Large diffs are not rendered by default.

ConsumePlugin/GeneratedCapturingMock.fs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -555,8 +555,13 @@ type internal TypeWithPropertiesMock =
555555
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0))
556556
this.Mem1 (arg_0_0)
557557

558-
member this.Prop1 = this.Prop1 ()
559-
member this.Prop2 = this.Prop2 ()
558+
member this.Prop1 =
559+
lock this.Calls.Prop1 (fun _ -> this.Calls.Prop1.Add ())
560+
this.Prop1 ()
561+
562+
member this.Prop2 =
563+
lock this.Calls.Prop2 (fun _ -> this.Calls.Prop2.Add ())
564+
this.Prop2 ()
560565

561566
interface System.IDisposable with
562567
member this.Dispose () : unit = this.Dispose ()

ConsumePlugin/GeneratedRestClient.fs

Lines changed: 140 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -427,21 +427,29 @@ module PureGymApi =
427427
async {
428428
let! ct = Async.CancellationToken
429429

430+
let queryString =
431+
[
432+
Some ("fromDate=" + ((fromDate.ToString "yyyy-MM-dd") |> System.Uri.EscapeDataString))
433+
Some ("toDate=" + ((toDate.ToString "yyyy-MM-dd") |> System.Uri.EscapeDataString))
434+
]
435+
|> List.choose (fun queryParam -> queryParam)
436+
|> String.concat "&"
437+
430438
let uri =
431439
System.Uri (
432440
(match client.BaseAddress with
433441
| null -> System.Uri "https://whatnot.com/"
434442
| v -> v),
435443
System.Uri (
436444
("/v2/gymSessions/member"
437-
+ (if "/v2/gymSessions/member".IndexOf (char 63) >= 0 then
438-
"&"
445+
+ (if queryString = "" then
446+
""
439447
else
440-
"?")
441-
+ "fromDate="
442-
+ ((fromDate.ToString "yyyy-MM-dd") |> System.Uri.EscapeDataString)
443-
+ "&toDate="
444-
+ ((toDate.ToString "yyyy-MM-dd") |> System.Uri.EscapeDataString)),
448+
((if "/v2/gymSessions/member".IndexOf (char 63) >= 0 then
449+
"&"
450+
else
451+
"?")
452+
+ queryString))),
445453
System.UriKind.Relative
446454
)
447455
)
@@ -478,21 +486,29 @@ module PureGymApi =
478486
async {
479487
let! ct = Async.CancellationToken
480488

489+
let queryString =
490+
[
491+
Some ("fromDate=" + ((fromDate.ToString "yyyy-MM-dd") |> System.Uri.EscapeDataString))
492+
Some ("toDate=" + ((toDate.ToString "yyyy-MM-dd") |> System.Uri.EscapeDataString))
493+
]
494+
|> List.choose (fun queryParam -> queryParam)
495+
|> String.concat "&"
496+
481497
let uri =
482498
System.Uri (
483499
(match client.BaseAddress with
484500
| null -> System.Uri "https://whatnot.com/"
485501
| v -> v),
486502
System.Uri (
487503
("/v2/gymSessions/member?foo=1"
488-
+ (if "/v2/gymSessions/member?foo=1".IndexOf (char 63) >= 0 then
489-
"&"
504+
+ (if queryString = "" then
505+
""
490506
else
491-
"?")
492-
+ "fromDate="
493-
+ ((fromDate.ToString "yyyy-MM-dd") |> System.Uri.EscapeDataString)
494-
+ "&toDate="
495-
+ ((toDate.ToString "yyyy-MM-dd") |> System.Uri.EscapeDataString)),
507+
((if "/v2/gymSessions/member?foo=1".IndexOf (char 63) >= 0 then
508+
"&"
509+
else
510+
"?")
511+
+ queryString))),
496512
System.UriKind.Relative
497513
)
498514
)
@@ -1967,6 +1983,116 @@ open System.Net
19671983
open System.Net.Http
19681984
open RestEase
19691985

1986+
/// Module for constructing a REST client.
1987+
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
1988+
module ApiWithOptionalQuery =
1989+
/// Create a REST client.
1990+
let make (client : System.Net.Http.HttpClient) : IApiWithOptionalQuery =
1991+
{ new IApiWithOptionalQuery with
1992+
member _.GetWithMixedQuery
1993+
(page : int option, limit : int, search : string option, ct : CancellationToken option)
1994+
=
1995+
async {
1996+
let! ct = Async.CancellationToken
1997+
1998+
let queryString =
1999+
[
2000+
page
2001+
|> Option.map (fun queryParam ->
2002+
"page=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString)
2003+
)
2004+
2005+
Some ("limit=" + ((limit.ToString ()) |> System.Uri.EscapeDataString))
2006+
search
2007+
|> Option.map (fun queryParam ->
2008+
"search=" + ((queryParam.ToString ()) |> System.Uri.EscapeDataString)
2009+
)
2010+
]
2011+
|> List.choose (fun queryParam -> queryParam)
2012+
|> String.concat "&"
2013+
2014+
let uri =
2015+
System.Uri (
2016+
(match client.BaseAddress with
2017+
| null -> System.Uri "https://whatnot.com/"
2018+
| v -> v),
2019+
System.Uri (
2020+
("endpoint"
2021+
+ (if queryString = "" then
2022+
""
2023+
else
2024+
((if "endpoint".IndexOf (char 63) >= 0 then "&" else "?") + queryString))),
2025+
System.UriKind.Relative
2026+
)
2027+
)
2028+
2029+
use httpMessage =
2030+
new System.Net.Http.HttpRequestMessage (
2031+
Method = System.Net.Http.HttpMethod.Get,
2032+
RequestUri = uri
2033+
)
2034+
2035+
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
2036+
let response = response.EnsureSuccessStatusCode ()
2037+
use response = response
2038+
let! responseString = response.Content.ReadAsStringAsync ct |> Async.AwaitTask
2039+
return responseString
2040+
}
2041+
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
2042+
2043+
member _.GetWithAllOptionalQuery (since : DateOnly option, ct : CancellationToken option) =
2044+
async {
2045+
let! ct = Async.CancellationToken
2046+
2047+
let queryString =
2048+
[
2049+
since
2050+
|> Option.map (fun queryParam ->
2051+
"since=" + ((queryParam.ToString "yyyy-MM-dd") |> System.Uri.EscapeDataString)
2052+
)
2053+
]
2054+
|> List.choose (fun queryParam -> queryParam)
2055+
|> String.concat "&"
2056+
2057+
let uri =
2058+
System.Uri (
2059+
(match client.BaseAddress with
2060+
| null -> System.Uri "https://whatnot.com/"
2061+
| v -> v),
2062+
System.Uri (
2063+
("endpoint"
2064+
+ (if queryString = "" then
2065+
""
2066+
else
2067+
((if "endpoint".IndexOf (char 63) >= 0 then "&" else "?") + queryString))),
2068+
System.UriKind.Relative
2069+
)
2070+
)
2071+
2072+
use httpMessage =
2073+
new System.Net.Http.HttpRequestMessage (
2074+
Method = System.Net.Http.HttpMethod.Get,
2075+
RequestUri = uri
2076+
)
2077+
2078+
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
2079+
let response = response.EnsureSuccessStatusCode ()
2080+
use response = response
2081+
let! responseString = response.Content.ReadAsStringAsync ct |> Async.AwaitTask
2082+
return responseString
2083+
}
2084+
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
2085+
}
2086+
namespace PureGym
2087+
2088+
open System
2089+
open System.Threading
2090+
open System.Threading.Tasks
2091+
open System.IO
2092+
open System.Net
2093+
open System.Net.Http
2094+
open RestEase
2095+
19702096
/// Module for constructing a REST client.
19712097
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix) ; RequireQualifiedAccess>]
19722098
module ClientWithStringBody =

0 commit comments

Comments
 (0)