Swashbuckle.AspNetCore
Swashbuckle.AspNetCore copied to clipboard
SwaggerGen not handling `application/json; charset=utf-8` properly
I'm using version 6.4.0 from Nuget.
The generated swagger.json
file exposes responses with application/json
although the application returns application/json; charset=utf-8
. This cause strict clients to reject the response as the specification does not match the returned value. See https://github.com/OpenAPITools/openapi-generator/issues/13467#issuecomment-1297215358 for example.
For example, my API generates the following
{
"openapi": "3.0.1",
"info": {
"title": "DocIntel API",
"description": "API for DocIntel",
"version": "v2.2"
},
"paths": {
"/API/Authentication/Login": {
"post": {
"tags": [
"Authentication"
],
"operationId": "LoginAuthentication",
"requestBody": {
"content": {
"application/json-patch+json": {
"schema": {
"$ref": "#/components/schemas/LoginInformation"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginInformation"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/LoginInformation"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/LoginInformation"
}
}
}
},
"responses": {
"200": {
"description": "Success",
"content": {
"text/plain": {
"schema": {
"$ref": "#/components/schemas/LoginResult"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginResult"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/LoginResult"
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"text/plain": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
}
}
},
...
And the endpoint returns
< HTTP/1.1 200 OK
< Content-Length: 2800
< Content-Type: application/json; charset=utf-8
< Date: Mon, 31 Oct 2022 09:33:50 GMT
< Server: Kestrel
Adding an annotation [Produces("application/json; charset=utf-8")]
to the method produces the expected specification but prevent the application to work, as it will refuse to serve a response with No output formatter was found for content types 'application/json; charset=utf-8, application/json; charset=utf-8' to write the response.
error.
{
"openapi": "3.0.1",
"info": {
"title": "DocIntel API",
"description": "API for DocIntel",
"version": "v2.2"
},
"paths": {
"/API/Authentication/Login": {
"post": {
"tags": [
"Authentication"
],
"operationId": "LoginAuthentication",
"requestBody": {
"content": {
"application/json-patch+json": {
"schema": {
"$ref": "#/components/schemas/LoginInformation"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginInformation"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/LoginInformation"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/LoginInformation"
}
}
}
},
"responses": {
"200": {
"description": "Success",
"content": {
"application/json; charset=utf-8": {
"schema": {
"$ref": "#/components/schemas/LoginResult"
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"application/json; charset=utf-8": {
"schema": {
"$ref": "#/components/schemas/ProblemDetails"
}
}
}
}
}
}
},
...
The auto-generated file should include the charset by default, or offer an option to do so.
Hmmm - I'm not convinced the client is behaving appropriately in this case TBH. But, if you want a quick fix, I think you could make the generated response media types more explicit by applying a simple operation filter:
// Startup.cs
builder.Services.AddSwaggerGen(c =>
{
...
c.OperationFilter<AddMediaTypeEncoding>();
});
// AddMediaTypeEncoding.cs
internal class AddMediaTypeEncoding : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
foreach (var response in operation.Responses.Values)
{
response.Content = response.Content
.ToDictionary(
entry => $"{entry.Key}; charset=utf-8",
entry => entry.Value
);
}
}
}
This issue is stale because it has been open for 60 days with no activity. It will be automatically closed in 14 days if no further updates are made.