Using ServiceStack's Swagger Plugin, how to im

2020-06-23 05:57发布

I am implementing Swagger API documentation using ServiceStack's new Swagger plugin and am trying to determine how to use the "container" data type. I need to display a string field that has a list of predetermined values and other parameters that are lists of sub-objects.

Unless I am missing something I believe swagger can only take a text field that you input the JSON for you list of sub-objects. I believe this code should do the trick.

[ApiMember(Name = "Connections", Description = "insert JSON sample here", ParameterType = "body", DataType = "container", IsRequired = false, Verb = "Post")]

What I do not know ( and am hoping someone out there can help me) is if it is possible to have a string field that is from a preset list of values. In Swagger this code snippet illustrates how to do this.

"Pet":{
    "id":"Pet",
    "properties":{
    ...
      "status":{
        "type":"String",
        "description":"pet status in the store",
        "allowableValues":{
          "valueType":"LIST",
          "values":[
            "available",
            "pending",
            "sold"
          ]
        }
      },
      "happiness": {
        "type": "Int",
        "description": "how happy the Pet appears to be, where 10 is 'extremely happy'",
        "allowableValues": {
          "valueType": "RANGE",
          "min": 1,
          "max": 10
        }
      },
      ...

Does anyone know how this is accomplished using ServiceStack.Api.Swagger?

1条回答
干净又极端
2楼-- · 2020-06-23 06:24

I've been struggling with the same issue, but have realised that this feature is currently unsupported. You basically cannot POST or PUT data using Models. This feature is in flux and under development so I guess it is on the todo list.

If you view the source code, you will see that there is no Models property supported in the ResourcesResponse data contract:

[DataContract]
public class ResourcesResponse
{
    [DataMember(Name = "swaggerVersion")]
    public string SwaggerVersion { get; set; }
    [DataMember(Name = "apiVersion")]
    public string ApiVersion { get; set; }
    [DataMember(Name = "basePath")]
    public string BasePath { get; set; }
    [DataMember(Name = "apis")]
    public List<RestService> Apis { get; set; }
}

If you compare this to the Petstore example on Wordnik, you'll find that the models are included as a root node:

{
   "apiVersion":"0.2",
   "swaggerVersion":"1.1",
   "basePath":"http://petstore.swagger.wordnik.com/api",
   "resourcePath":"/pet",
   "apis":[
      {
         "path":"/pet.{format}",
         "description":"Operations about pets",
         "operations":[
            {
               "httpMethod":"POST",
               "summary":"Add a new pet to the store",
               "responseClass":"void",
               "nickname":"addPet",
               "parameters":[
                  {
                     "description":"Pet object that needs to be added to the store",
                     "paramType":"body",
                     "required":true,
                     "allowMultiple":false,
                     "dataType":"Pet"
                  }
               ],
               "errorResponses":[
                  {
                     "code":405,
                     "reason":"Invalid input"
                  }
               ]
            }
         ]
      }
   ],
   "models":{
      "Category":{
         "id":"Category",
         "properties":{
            "id":{
               "type":"long"
            },
            "name":{
               "type":"string"
            }
         }
      },
      "Pet":{
         "id":"Pet",
         "properties":{
            "tags":{
               "items":{
                  "$ref":"Tag"
               },
               "type":"Array"
            },
            "id":{
               "type":"long"
            },
            "category":{
               "type":"Category"
            },
            "status":{
               "allowableValues":{
                  "valueType":"LIST",
                  "values":[
                     "available",
                     "pending",
                     "sold"
                  ],
                  "valueType":"LIST"
               },
               "description":"pet status in the store",
               "type":"string"
            },
            "name":{
               "type":"string"
            },
            "photoUrls":{
               "items":{
                  "type":"string"
               },
               "type":"Array"
            }
         }
      },
      "Tag":{
         "id":"Tag",
         "properties":{
            "id":{
               "type":"long"
            },
            "name":{
               "type":"string"
            }
         }
      }
   }
}

I think that the only way around this is to post the entire object yourself. Have a request object that takes an entire object, such as Pet. Set the ParameterType to body and the DataType to Pet. In the Swagger interface you'll see a textarea, into which you have to paste an actual JSON object. You request will look like this:

[Api("The Thing Service")]
[Route("/thing", "POST", Summary = @"POST a new thing", Notes = "Send a thing here")]
public class ThingRequest
{
    [DataMember]
    [ApiMember(Name = "Thing", Description = "The thing", ParameterType = "body", DataType = "Thing", IsRequired = false)]
    public ThingDto Thing { get; set; }
}

And your service like this:

/// <summary>
/// Summary description for ThingService
/// </summary>
public class ThingService : Service
{
    public IThingRepository ThingRepository { get; set; }

    public object Post(ThingRequest request)
    {
        var thing = Thing.Map(request);
        ThingRepository.Save(thing);
        return new ThingResponse();
    }
}

The following will be rendered:

Swagger output

Enter the object like so, and the request will be correctly parsed:

enter image description here

查看更多
登录 后发表回答