Swashbuckle.AspNetCore icon indicating copy to clipboard operation
Swashbuckle.AspNetCore copied to clipboard

SwaggerGen not handling `application/json; charset=utf-8` properly

Open ancailliau opened this issue 2 years ago • 1 comments

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.

ancailliau avatar Oct 31 '22 15:10 ancailliau

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
                );
        }
    }
}

domaindrivendev avatar Nov 15 '22 23:11 domaindrivendev

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.

github-actions[bot] avatar Apr 15 '24 02:04 github-actions[bot]