Skip to content

Commit 01ac4be

Browse files
committed
fix(response): use the proper serializer
1 parent 7f431e7 commit 01ac4be

7 files changed

Lines changed: 94 additions & 97 deletions

File tree

src/OpenAPI.WebApiGenerator/ApiGenerator.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,12 +195,13 @@ private static void GenerateCode(SourceProductionContext context, (
195195
return new ResponseContentGenerator(
196196
responseStatusCodePattern,
197197
responseBodyGenerators,
198-
responseHeaderGenerators,
199-
httpResponseExtensionsGenerator);
198+
responseHeaderGenerators);
200199
}).ToList();
201200

202201
var responseGenerator = new ResponseGenerator(
203-
responseBodyGenerators, httpResponseExtensionsGenerator);
202+
responseBodyGenerators,
203+
httpResponseExtensionsGenerator,
204+
openApiVersion);
204205
var responseSourceCode =
205206
responseGenerator.GenerateResponseClass(
206207
operationNamespace,

src/OpenAPI.WebApiGenerator/CodeGeneration/HttpRequestExtensionsGenerator.cs

Lines changed: 12 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.IO;
33
using Microsoft.OpenApi;
4+
using OpenAPI.WebApiGenerator.OpenApi;
45

56
namespace OpenAPI.WebApiGenerator.CodeGeneration;
67

@@ -10,46 +11,21 @@ internal sealed class HttpRequestExtensionsGenerator(
1011
{
1112
private const string HttpRequestExtensionsClassName = "HttpRequestExtensions";
1213

13-
private readonly string _openApiVersion = openApiVersion switch
14-
{
15-
OpenApiSpecVersion.OpenApi2_0 => "2.0",
16-
OpenApiSpecVersion.OpenApi3_0 => "3.0",
17-
OpenApiSpecVersion.OpenApi3_1 => "3.1",
18-
_ => throw new NotSupportedException($"OpenAPI version {Enum.GetName(typeof(OpenApiSpecVersion), openApiVersion)} not supported")
19-
};
14+
private readonly string _openApiVersion = openApiVersion.GetParameterVersion();
2015

2116
internal string CreateBindParameterInvocation(
2217
string requestVariableName,
2318
string bindingTypeName,
24-
IOpenApiParameter parameter)
25-
{
26-
using var textWriter = new StringWriter();
27-
var jsonWriter = new OpenApiJsonWriter(textWriter, new OpenApiJsonWriterSettings()
28-
{
29-
InlineLocalReferences = true
30-
});
31-
Action<IOpenApiWriter> serialize = openApiVersion switch
32-
{
33-
OpenApiSpecVersion.OpenApi3_1 => parameter.SerializeAsV31,
34-
OpenApiSpecVersion.OpenApi3_0 => parameter.SerializeAsV3,
35-
OpenApiSpecVersion.OpenApi2_0 => parameter.SerializeAsV2,
36-
_ => throw new NotSupportedException(
37-
$"OpenAPI version {Enum.GetName(typeof(OpenApiSpecVersion), openApiVersion)} not supported")
38-
};
39-
serialize(jsonWriter);
40-
textWriter.Flush();
41-
42-
return
43-
$""""
44-
{@namespace}.{HttpRequestExtensionsClassName}.Bind<{bindingTypeName}>(
45-
{requestVariableName},
46-
"{_openApiVersion}",
47-
"""
48-
{textWriter.GetStringBuilder()}
49-
""")
50-
"""";
51-
}
52-
19+
IOpenApiParameter parameter) =>
20+
$""""
21+
{@namespace}.{HttpRequestExtensionsClassName}.Bind<{bindingTypeName}>(
22+
{requestVariableName},
23+
"{_openApiVersion}",
24+
"""
25+
{parameter.Serialize(openApiVersion)}
26+
""")
27+
"""";
28+
5329
internal string CreateBindBodyInvocation(
5430
string requestVariableName,
5531
string bindingTypeName)

src/OpenAPI.WebApiGenerator/CodeGeneration/HttpResponseExtensionsGenerator.cs

Lines changed: 26 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
using System;
2-
using System.IO;
3-
using Microsoft.OpenApi;
4-
using OpenAPI.WebApiGenerator.Extensions;
1+
using Microsoft.OpenApi;
2+
using OpenAPI.WebApiGenerator.OpenApi;
53

64
namespace OpenAPI.WebApiGenerator.CodeGeneration;
75

@@ -11,47 +9,25 @@ internal sealed class HttpResponseExtensionsGenerator(
119
{
1210
private const string HttpResponseExtensionsClassName = "HttpResponseExtensions";
1311
public string Namespace => @namespace;
14-
12+
1513
internal string GetResponseHeaderSpecificationAsJson(
1614
IOpenApiHeader header,
17-
string name)
18-
{
19-
using var textWriter = new StringWriter();
20-
var jsonWriter = new OpenApiJsonWriter(textWriter, new OpenApiJsonWriterSettings
21-
{
22-
InlineLocalReferences = true
23-
});
24-
Action<IOpenApiWriter> serialize = openApiVersion switch
25-
{
26-
OpenApiSpecVersion.OpenApi3_1 => header.SerializeAsV31,
27-
OpenApiSpecVersion.OpenApi3_0 => header.SerializeAsV3,
28-
OpenApiSpecVersion.OpenApi2_0 => header.SerializeAsV2,
29-
_ => throw new NotSupportedException(
30-
$"OpenAPI version {Enum.GetName(typeof(OpenApiSpecVersion), openApiVersion)} not supported")
31-
};
32-
serialize(jsonWriter);
33-
textWriter.Flush();
34-
15+
string name) =>
3516
// Response header specification is a subset of the parameter specification, so we add the missing properties to be able to use the parameter value parser
36-
return
37-
$$"""
38-
{
39-
"name": "{{name}}",
40-
"in": "header",
41-
{{textWriter.GetStringBuilder().ToString().TrimStart('{').TrimStart()}}
42-
""";
43-
}
44-
45-
internal string CreateWriteBodyInvocation(
17+
$$"""
18+
{
19+
"name": "{{name}}",
20+
"in": "header",
21+
{{header.Serialize(openApiVersion).ToString().TrimStart('{').TrimStart()}}
22+
""";
23+
24+
internal static string CreateWriteBodyInvocation(
4625
string responseVariableName,
47-
string contentVariableName)
48-
{
49-
return
50-
$"""
51-
{responseVariableName}.WriteResponseBody({contentVariableName})
52-
""";
53-
}
54-
26+
string contentVariableName) =>
27+
$"""
28+
{responseVariableName}.WriteResponseBody({contentVariableName})
29+
""";
30+
5531
internal SourceCode GenerateHttpResponseExtensionsClass() =>
5632
new($"{HttpResponseExtensionsClassName}.g.cs",
5733
$$$""""
@@ -62,17 +38,18 @@ internal SourceCode GenerateHttpResponseExtensionsClass() =>
6238
using Corvus.Json;
6339
using Microsoft.AspNetCore.Http;
6440
using Microsoft.Extensions.Primitives;
65-
using OpenAPI.ParameterStyleParsers.OpenApi20;
66-
using OpenAPI.ParameterStyleParsers.OpenApi20.ParameterParsers;
41+
using OpenAPI.ParameterStyleParsers;
6742
using JsonObject = System.Text.Json.Nodes.JsonObject;
6843
6944
namespace {{{@namespace}}};
7045
7146
internal static class {{{HttpResponseExtensionsClassName}}}
7247
{
73-
private static readonly ConcurrentDictionary<Parameter, ParameterValueParser> ParserCache = new();
74-
75-
internal static void WriteResponseHeader<TValue>(this HttpResponse response,
48+
private static readonly ConcurrentDictionary<IParameter, IParameterValueParser> ParserCache = new();
49+
private static IParameterValueParser GetParser(IParameter parameter) => ParserCache.GetOrAdd(parameter, _ => parameter.CreateParameterValueParser());
50+
51+
internal static void WriteResponseHeader<TValue>(this HttpResponse response,
52+
string openApiVersion,
7653
string headerSpecificationAsJson,
7754
string name,
7855
TValue value,
@@ -86,7 +63,7 @@ internal static void WriteResponseHeader<TValue>(this HttpResponse response,
8663
8764
Validate(value);
8865
89-
var parameter = Parameter.FromOpenApi20ParameterSpecification(headerSpecificationAsJson);
66+
var parameter = ParameterFactory.OpenApi(openApiVersion, headerSpecificationAsJson);
9067
var serializedValue = Serialize(parameter, name, value);
9168
response.Headers[name] = serializedValue;
9269
}
@@ -100,10 +77,10 @@ internal static void WriteResponseBody<TValue>(this HttpResponse response, TValu
10077
value.WriteTo(jsonWriter);
10178
}
10279
103-
private static string? Serialize<TValue>(Parameter parameter, string name, TValue jsonValue)
80+
private static string? Serialize<TValue>(IParameter parameter, string name, TValue jsonValue)
10481
where TValue : struct, IJsonValue
10582
{
106-
var parser = ParserCache.GetOrAdd(parameter, ParameterValueParser.Create);
83+
var parser = GetParser(parameter);
10784
var value = jsonValue.Serialize();
10885
10986
return parser.Serialize(JsonNode.Parse(value));

src/OpenAPI.WebApiGenerator/CodeGeneration/ResponseContentGenerator.cs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,12 @@ internal sealed class ResponseContentGenerator
1010
{
1111
private readonly List<ResponseBodyContentGenerator> _contentGenerators = [];
1212
private readonly List<ResponseHeaderGenerator> _headerGenerators = [];
13-
private readonly HttpResponseExtensionsGenerator _httpResponseExtensionsGenerator;
1413
private readonly string _responseClassName;
1514
private readonly string _responseStatusCodePattern;
1615

1716
private ResponseContentGenerator(
18-
string responseStatusCodePattern,
19-
HttpResponseExtensionsGenerator httpResponseExtensionsGenerator)
17+
string responseStatusCodePattern)
2018
{
21-
_httpResponseExtensionsGenerator = httpResponseExtensionsGenerator;
2219
var classNamePrefix = Enum.TryParse<HttpStatusCode>(responseStatusCodePattern, out var statusCode)
2320
? statusCode.ToString()
2421
: responseStatusCodePattern.First() switch
@@ -39,8 +36,7 @@ var chr when char.IsDigit(chr) => "X",
3936
public ResponseContentGenerator(
4037
string responseStatusCodePattern,
4138
List<ResponseBodyContentGenerator> contentGenerators,
42-
List<ResponseHeaderGenerator> headerGenerators,
43-
HttpResponseExtensionsGenerator httpResponseExtensionsGenerator) : this(responseStatusCodePattern, httpResponseExtensionsGenerator)
39+
List<ResponseHeaderGenerator> headerGenerators) : this(responseStatusCodePattern)
4440
{
4541
_contentGenerators = contentGenerators;
4642
_headerGenerators = headerGenerators;
@@ -99,7 +95,7 @@ internal override void WriteTo(HttpResponse {{responseVariableName}})
9995
{{{_contentGenerators.AggregateToString(generator =>
10096
$"""
10197
case true when {generator.ContentPropertyName} is not null:
102-
{_httpResponseExtensionsGenerator.CreateWriteBodyInvocation(
98+
{HttpResponseExtensionsGenerator.CreateWriteBodyInvocation(
10399
responseVariableName,
104100
$"{generator.ContentPropertyName}.Value")};
105101
break;

src/OpenAPI.WebApiGenerator/CodeGeneration/ResponseGenerator.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
using System.Collections.Generic;
22
using System.Linq;
3+
using Microsoft.OpenApi;
34
using OpenAPI.WebApiGenerator.Extensions;
5+
using OpenAPI.WebApiGenerator.OpenApi;
46

57
namespace OpenAPI.WebApiGenerator.CodeGeneration;
68

7-
internal sealed class ResponseGenerator(List<ResponseContentGenerator> responseBodyGenerators, HttpResponseExtensionsGenerator httpResponseExtensionsGenerator)
9+
internal sealed class ResponseGenerator(
10+
List<ResponseContentGenerator> responseBodyGenerators,
11+
HttpResponseExtensionsGenerator httpResponseExtensionsGenerator,
12+
OpenApiSpecVersion openApiSpecVersion)
813
{
914
public SourceCode GenerateResponseClass(string @namespace, string path)
1015
{
@@ -18,7 +23,9 @@ public SourceCode GenerateResponseClass(string @namespace, string path)
1823
namespace {{@namespace}};
1924
2025
internal abstract partial class Response
21-
{{{Enumerable.Range(1, 5).AggregateToString(i =>
26+
{
27+
private const string OpenApiVersion = "{{openApiSpecVersion.GetParameterVersion()}}";
28+
{{Enumerable.Range(1, 5).AggregateToString(i =>
2229
$$"""
2330
protected int Validate{{i}}xxStatusCode(int code)
2431
=> (code >= {{i}}00 && code <= {{i}}99) ? code : throw new InvalidOperationException($"Expected {{i}}xx status code, got {code}");

src/OpenAPI.WebApiGenerator/CodeGeneration/ResponseHeaderGenerator.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ internal string GenerateWriteDirective(string responseVariableName)
3131
return
3232
$""""
3333
{responseVariableName}.WriteResponseHeader(
34+
OpenApiVersion,
3435
"""
3536
{headerSpecificationAsJson.Indent(4).TrimStart()}
3637
""",
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
using System.IO;
3+
using System.Text;
4+
using Microsoft.OpenApi;
5+
6+
namespace OpenAPI.WebApiGenerator.OpenApi;
7+
8+
internal static class OpenApiVersionExtensions
9+
{
10+
internal static string GetParameterVersion(this OpenApiSpecVersion version) => version switch
11+
{
12+
OpenApiSpecVersion.OpenApi2_0 => "2.0",
13+
OpenApiSpecVersion.OpenApi3_0 => "3.0",
14+
OpenApiSpecVersion.OpenApi3_1 => "3.1",
15+
_ => throw new NotSupportedException($"OpenAPI version {Enum.GetName(typeof(OpenApiSpecVersion), version)} not supported")
16+
};
17+
18+
internal static Action<IOpenApiWriter> GetSerializer(this IOpenApiSerializable parameter, OpenApiSpecVersion version) => version switch
19+
{
20+
OpenApiSpecVersion.OpenApi3_1 => parameter.SerializeAsV31,
21+
OpenApiSpecVersion.OpenApi3_0 => parameter.SerializeAsV3,
22+
OpenApiSpecVersion.OpenApi2_0 => parameter.SerializeAsV2,
23+
_ => throw new NotSupportedException(
24+
$"OpenAPI version {Enum.GetName(typeof(OpenApiSpecVersion), version)} not supported")
25+
};
26+
27+
internal static StringBuilder Serialize(this IOpenApiSerializable serializable, OpenApiSpecVersion version)
28+
{
29+
using var textWriter = new StringWriter();
30+
var jsonWriter = new OpenApiJsonWriter(textWriter, new OpenApiJsonWriterSettings
31+
{
32+
InlineLocalReferences = true
33+
});
34+
var serialize = serializable.GetSerializer(version);
35+
serialize(jsonWriter);
36+
textWriter.Flush();
37+
return textWriter.GetStringBuilder();
38+
}
39+
}

0 commit comments

Comments
 (0)