Swashbuckle.aspnetcore: OpenAPI NonBodyParameter replacement?

Created on 7 May 2019  路  7Comments  路  Source: domaindrivendev/Swashbuckle.AspNetCore

I upgraded to Swashbuckle v5, and was trying to update a project that uses the Microsoft.AspNetCore.Mvc.Versioning. It uses an operation filter like such:

 public void Apply(Operation operation, OperationFilterContext context)
        {
            var apiDescription = context.ApiDescription;

            operation.Deprecated = apiDescription.IsDeprecated();

            if (operation.Parameters == null)
            {
                return;
            }

            // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/412
            // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/pull/413
            foreach (var parameter in operation.Parameters.OfType<NonBodyParameter>())
            {
                var description = apiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name);

                if (parameter.Description == null)
                {
                    parameter.Description = description.ModelMetadata?.Description;
                }

                if (parameter.Default == null)
                {
                    parameter.Default = description.DefaultValue;
                }

                parameter.Required |= description.IsRequired;
            }
        }

With SwaggerDocument no longer used in v5, I couldn't find a NonBodyParameter equivalent in OpenAPI model.

Can anyone tell me the appropriate class to use for that in OpenAPI?

Most helpful comment

Yup, it did work w/o the OfType. However, the OpenAPI doesn't allow you to set a default value. I think the MS API Version maintainer will have to setup the API versions as a OpenAPI options list value, and then pick the default. I punted on this for now, and just went with version-in-url pattern.

How did you change your code with RequestBody?

All 7 comments

In OpenAPI v3, body parameters are split out into a separate property called RequestBody. So, I think you may be able to remove OfType filter entirely as all values in the collection are "non-body"

Yup, it did work w/o the OfType. However, the OpenAPI doesn't allow you to set a default value. I think the MS API Version maintainer will have to setup the API versions as a OpenAPI options list value, and then pick the default. I punted on this for now, and just went with version-in-url pattern.

Yup, it did work w/o the OfType. However, the OpenAPI doesn't allow you to set a default value. I think the MS API Version maintainer will have to setup the API versions as a OpenAPI options list value, and then pick the default. I punted on this for now, and just went with version-in-url pattern.

How did you change your code with RequestBody?

For my side i applied the following changes, since the OpenApiParameter has been made as public class since then

public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
    if (operation.Parameters == null)
    {
        return;
    }

    // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/412
    // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/pull/413
    foreach (var parameter in operation.Parameters)
    {
        var description = context.ApiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name);
        var routeInfo = description.RouteInfo;

        if (string.IsNullOrEmpty(parameter.Name))
        {
            parameter.Name = description.ModelMetadata?.Name;
        }

        if (parameter.Description == null)
        {
            parameter.Description = description.ModelMetadata?.Description;
        }

        if (routeInfo == null)
        {
            continue;
        }

        parameter.Required |= !routeInfo.IsOptional;
    }

    // Overwrite description for shared response code
    operation.Responses["400"].Description = "Invalid query parameter(s). Read the response description";
    operation.Responses["401"].Description = "Authorization has been denied for this request";
}
  // Overwrite description for shared response code
  operation.Responses["400"].Description = "Invalid query parameter(s). Read the response description";
  operation.Responses["401"].Description = "Authorization has been denied for this request";

I found that for a successful response, the "operation.Responses" dictionary only contains an item for "200".
So I think a slightly more defensive code is needed, like this:

            // Overwrite description for common response codes
            var statusBadRequest = StatusCodes.Status400BadRequest.ToString(CultureInfo.InvariantCulture);
            if (operation.Responses.ContainsKey(statusBadRequest))
            {
                operation.Responses[statusBadRequest].Description = "Invalid query parameter(s). Read the response description";
            }

            var statusUnauthorized = StatusCodes.Status401Unauthorized.ToString(CultureInfo.InvariantCulture);
            if (operation.Responses.ContainsKey(statusUnauthorized))
            {
                operation.Responses[statusUnauthorized].Description = "Authorization has been denied for this request";
            }

So not cool that you decided to break everything

Was this page helpful?
0 / 5 - 0 ratings

Related issues

voroninp picture voroninp  路  3Comments

voroninp picture voroninp  路  3Comments

m-demydiuk picture m-demydiuk  路  3Comments

vanillajonathan picture vanillajonathan  路  3Comments

TimmyGilissen picture TimmyGilissen  路  3Comments