Как изменить обязательные поля для POST и PUT в Swashbuckle? - PullRequest
0 голосов
/ 27 марта 2019

Я отвечаю за ведение документации API компании.Наш API написан на ASP.NET.Недавно я перешел на использование Swashbuckle 5.6.0, который работает хорошо.

Проблема, с которой я столкнулся, заключается в следующем:

Мы разделяем наши модели данных на данные Post и получаем данные, например WebAccountGetData.cs и WebAccountPostData.cs.Данные Post могут использоваться при создании (POST) и обновлении (PUT).

Большинство, если не все, поля в классах данных Post обнуляются, когда вызывается метод API, хранимый процесс возвращает сообщения об ошибках, описывающие, какие поля отсутствуют / обязательны для заполнения.API не обрабатывает обязательные поля.

Использование пустых полей означает, что Swashbuckle не добавит флаг Required в документацию.Но мы хотели бы показать, является ли поле обязательным или нет, основываясь на используемом методе Http (Post / Put).

required example
Ключ API является обязательным параметром, так какне обнуляется.

Мне известно, что я могу использовать атрибут [Required] из пространства имен System.ComponentModel.DataAnnotations, но при этом флаг Required будет применяться как к методам POST, так и к PUT,который мы не хотим.

В идеале я хотел бы использовать собственный атрибут, в котором я могу указать, требуется ли поле в методе Post или Put.

public class ApiRequiredAttribute : Attribute
{
  public bool RequiredInPost
  {
    get;
    set;
  } = false;

  public bool RequiredInPut
  {
    get;
    set;
  } = false;
}

И затем используйте его так:

[ApiRequired(RequiredInPost = true)]
public int? ApprovalStatusId
{
  get;
  set;
}

Есть ли способ использовать пользовательские IDocumentFilter, IOperationFilter или ISchemaFilter для применения изменений (например, переключениетребуемый флаг) к свойствам схемы поля модели?Или в Swashbuckle невозможно ссылаться на атрибуты в модели?

1 Ответ

0 голосов
/ 29 марта 2019

Мне удалось найти решение!

Я создал IOperationFilter, который создает новые схемы для методов POST и PUT на основе свойств с моим настраиваемым атрибутом ApiRequired (см. Оригинальный вопрос).

internal class ApplyRequiredAttributeFilter : IOperationFilter
{
  public void Apply( Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription )
  {
    HttpParameterBinding[] parameterBindings = apiDescription.ActionDescriptor.ActionBinding.ParameterBindings;

    foreach ( HttpParameterBinding binding in parameterBindings ) {

      PropertyInfo[] properties = binding.Descriptor.ParameterType.GetProperties();

      // If the type is not an object and has no properties, ignore it.
      if ( properties.Length == 0 ) {
        continue;
      }

      Parameter modelParamater = operation.parameters.Last();
      if ( modelParamater == null ) {
        continue;
      }

      string schemaPath = modelParamater.schema?.@ref;
      string schemaName = schemaPath?.Split( '/' ).Last();
      if ( schemaName == null ) {
        continue;
      }

      Schema oldSchema = schemaRegistry.Definitions[ schemaName ];

      // Copy the existing schema.
      Schema newSchema = new Schema
      {
        description = oldSchema.description,
        properties = new Dictionary<string, Schema>( oldSchema.properties ),
        required = oldSchema.required != null ? new List<string>( oldSchema.required ) : new List<string>(),
        @type = oldSchema.type,
        vendorExtensions = new Dictionary<string, object>( oldSchema.vendorExtensions )
      };

      // Find model properties with the custom attribute.
      foreach ( PropertyInfo property in properties ) {
        ApiRequiredAttribute attribute = property.GetCustomAttribute<ApiRequiredAttribute>();

        if ( attribute != null ) {

          // If the model property is required in POST/PUT and current HTTP method is POST/PUT
          // Add the property to the new schema's required flags.
          if ( attribute.RequiredInPut && apiDescription.HttpMethod.Method.Equals( "PUT" ) ||
               attribute.RequiredInPost && apiDescription.HttpMethod.Method.Equals( "POST" ) ) {

            newSchema.required.Add( property.Name );

            string newSchemaName = $"{schemaName}:{apiDescription.HttpMethod.Method}";

            if ( !schemaRegistry.Definitions.ContainsKey( newSchemaName ) ) {
              schemaRegistry.Definitions.Add( newSchemaName, newSchema );
            }

            // Change the current model schema reference to the new schema with the addition required flags.
            modelParamater.schema.@ref = $"{schemaPath}:{apiDescription.HttpMethod.Method}";
          }
        }
      }
    }
  }
}

Затем я добавляю фильтр в мой вызов EnableSwagger.

GlobalConfiguration.Configuration
                   .EnableSwagger("docs/swagger/", c =>
                                    {
                                      // Other initialization code... 
                                      c.OperationFilter<ApplyRequiredAttributeFilter>();
                                    });

Атрибуты используются так:

[ApiRequired( RequiredInPost = true, RequiredInPut = true)]
public bool? Active
{
  get;
  set;
}

[ApiRequired( RequiredInPost = true )]
public string UserName
{
  get;
  set;
}

Наконец, на документах требуемые флаги выглядят следующим образом. Параметры метода POST находятся слева, а параметры метода PUT - справа:

enter image description here enter image description here

...