New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to generate Response examples and Schema defaults? #283
Comments
I've thought about how to implement this, and I came up with this: <response code="201" examples="{'application/json' : {'id' : '123', 'firstname' : 'John', 'lastname' : 'Smith'}}"><paramref name="account"/> created</response> i.e. the user can put raw json into an examples attribute. Hmm so we're mixing json inside xml - maybe not the cleanest solution. Anyway, I've implemented this locally and could submit a PR if you wish. |
@mattfrear I'm interested in seeing more about this. Not entirely sure how "the user can put ... into an examples attribute." Is that an XMLDoc attribute, or some other mechanism? |
The is an XMLDoc element which Swashbuckle already supports, I suggested adding an examples attribute to it. I got this working locally by changing the Swashbuckle source. However I code reviewed my changes with one of my colleagues and he came up with another idea to get it working without changing the Swashbuckle source, by writing an IOperationFilter. I've blogged about it here. http://mattfrear.com/2015/04/21/generating-swagger-example-responses-with-swashbuckle/ I'm happy to close this issue since I've gotten it working, although I think it would be better if we changed [SwaggerResponse] to support an examples parameter. |
Awesome, sounds good! |
+1 for supporting response example. |
What about using the cref attribute to refer to the type of the response object instead? Like
That way C# understands that you're trying to reference a class type, and the example could be generated automatically from the schema of the class referenced. It might still be nice however, to have explicit example response for more dynamic responses. |
@MerickOWA your last sentence nails what we're trying to achieve here. We can already do what you've suggested right now, using the [SwaggerResponse] attribute. It's something like this (apologies, I'm not on a Windows machine at the moment):
I don't know why a new [SwaggerResponse] attribute was created for this; I think what you've suggested using the /// xml documentation is cleaner - in my code right now I have 3 usages of [SwaggerResponse] on one method and it's getting quite ugly. How about something like this:
This would call CreatedResponseBuilder.GetExamples(201) in order get the examples to be added to the response. I don't know if it's illegal to invent my own attributes (e.g. examplesProvider) I'm happy to implement this if it is wanted, but I don't want to spend the time creating a rejected PR. |
@mattfrear - there is an impedance mismatch between "code comments" (i.e. Xml comments) and description of a HTTP/REST based API. The former describes implementation details (i.e. controllers, c# types etc.) encapsulated by the API whereas the latter describes the actual API and how it should be consumed. The introduction of non-standard attributes to Xml comments only further highlights the existence of this mismatch. This presents a problem because the "intent" becomes blurred. For example, a developer may provide implementation detail in Xml comments that's only intended for an internal audience. This is perfectly understandable, particularly if they're unfamiliar with Swashbuckle. After-all, this is what Xml comments are intended for. However, they sure do provide a convenient way to assign the "textual" Swagger properties. For the more structured properties like response codes, operation id's and even examples, I think custom attributes are a better approach for the following reasons.
So, with all that said, I'm comfortable (enough) to continue support for "descriptive" properties through the existing "standard" Xml attributes, purely for the convenience it affords (assigning paragraphs of text to an attribute property would be tricky). However, with the next version, I'm leaning toward removing support for the current "response" attribute in favor of the SwaggerResponse attribute. |
For response examples, I have no immediate plans to provide any additional support out-of-the-box whether it's through Xml or custom attributes. I already cited my reasons for avoiding the Xml comments approach above. For custom attributes, I like the approach that @mattfrear blogged about. But right now, I don't plan to add it out-of-the-box because it requires the consuming app to implement an extension point anyway (IProvidesExamples). I would prefer to limit the introduction of new abstractions if possible. Maybe a compromise would be to have SB support "per-operation" filters so you could provide your examples as follows:
Where "ProductExamples" is just an implementation of IOperationFilter that specifically sets examples on the operation responses. OR for request body parameters ...
Where in this case ProductExamples provides an implementation for ISchemaFilter that sets the "default" property on the corresponding Schema |
Thanks @domaindrivendev for providing insight as to the design of SwaggerResponse re: the impedance mismatch of using xml comments for everything. That makes sense. I think I understand your suggestion. Going back to my blogged example (http://mattfrear.com/2015/04/21/generating-swagger-example-responses-with-swashbuckle/), we would have something like:
and then CountriesExamples.cs:
Is that what you were suggesting or did I misunderstand? (apologies if it does not compile, I'm not on a Windows box) If it is, then a downside would be that you could only give examples for one type of SwaggerResponse, right? |
Echoing @mattfrear -- thank you @domaindrivendev for providing insights into the design of SwaggerResponse. In my naive view, it could be possible to support the definition of many example responses if there was a way of providing some discriminator to the SwaggerOperationFilter. Don't think I have a concrete suggestion of how to do this, though. |
@mattfrear - my thinking is that you create a per-action filter with the sole responsibility of assigning response examples to a given operation. Something along the following lines ...
|
I also discovered some behavior in the swagger-ui that could simplify things further ... If you assign the @default property on an object Schema, then that will be used as the sample JSON anywhere on the UI where that Schema is referenced, for responses AND parameters. So, you could achieve the behavior you originally wanted, plus additional support for showing the sample JSON for parameters, by just doing the following ...
|
OK cool, this looks great. Once this is released I'll give it a go. |
Personally, the fact that the SwaggerSchemaFilter attribute would need to leak into our data model would not work well for us. As much as I dislike the web api help page implementation, the SetSampleObjects feature works very well. Is there no possibility to implement something similar? |
If you don't want to pollute your data model with cross-cutting concerns, you can simply wire up a global operation filter that branches on the "type" to assign specific values like "examples" and "default". This way you would be providing all the samples in one place instead of scattering throughout the code |
Sorry meant to say "Schema filter" above as opposed to "operation filter" |
Ok, thanks. I will have to play around with this to see how it works. Can I supply an instance of a populated model or do I need to get more involved? |
With regards to this - the default generated model schema follows my JSON Serialization Convention to use lower_snake_case
but once I follow @domaindrivendev recommendation of setting a global schema.@default it reverts to the C# style capitalisation:
Is there anyway to get the defaults to use the serializer settings? Right now I'm working around it by using an anonymous type or my schema example but I'd prefer it to be strongly typed so when I rename stuff it's automatically updated. |
Should be resolved in latest release - 5.2.0 |
@domaindrivendev Thanks for that, however I just updated to the new version but it still doesn't appear to be working for me. Model has the correct casing, but model schema doesn't. Any ideas what I might be doing wrong? |
@RodH257 - for the time being, you're going to be stuck with the "anonymous object workaround". The problem is that the serialization of the SwaggerDocument (generated by Swashbuckle) requires it's own specific serialization settings to conform to the swagger-spec. It can't use the application's serialization settings because these could result in invalid Swagger JSON. However, the "example" and "default" objects are part of that SwaggerDocument. One solution would be to create a custom implementation of IContractResolver that uses the Swagger-specific settings for all properties except for the values of "example" and "default". For these, it would delegate to the ContractResolver configured by the app. This would be a non-trivial piece of work and given that a reasonable workaround exists, it's not high on the list of priorities at the moment. I closed the issue because I believe the original question is resolved with the introduction of per-action/per-schema filters. I think your problem is definitely valid and would like to address it at some point - perhaps you could create a separate issue just to keep it on the backlog? Thanks |
EDIT: scratch that guys, I got it, it's easy. :) Hello guys, I'm sorry to bother you but I'm a noob trying to navigate the world of Swagger and Swashbuckle. I was trying to use SB to document an API and I'm running into some issues and learning some workarounds. At the moment I have an issue when I list certain operations with very complex objects whose automatically inferred model schemas take 30-60s to load. BTW, I really like SB and Swagger, I wish I'd known about this sooner, I find documentation to be very important. Keep up the good work. |
This is an old issue but is one of the first to show up in Google. So for anyone arriving here like me, @domaindrivendev's answer above works for the Value text box but not for the Model Schema to the right of it. For complex objects, I ended up setting both |
Hi Matt @mattfrear, Could you please help me out in implementing default request data to the controller action of the model schema on the Swagger UI with Swagger 6.0.0-rc1-final with C#, same like your above implementation. As i'm using Swagger 6.0.0-rc1-final the functions which are used at above link are not found in this swagger which i'm using. |
Thank you @hvaughan3 for your reply, as i'm using Swagger 6.0.0-rc1-final, the functions which are used at above answer are not available in the version which i'm using, i'm using IOperationFilter for default values? |
Hi @mattfrear |
@Simar15, I added a generic 401 response to all methods like this: In config: c.OperationFilter<AddDefaultResponse>(); AddDefaultResponse class: public class AddDefaultResponse : IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
operation.responses.Add("401", new Response { description = "The request did not have the correct authorization header credientials." });
}
} |
@atrophic , Thanks for the help!, although I think I posted the question in a wrong thread, I was looking for generic responses in yaml spec file, I used this for generic responses. |
Hi,
Swagger's Response object supports examples:
https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#response-object
https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#example-object
Does Swashbuckle support this?
Matt
The text was updated successfully, but these errors were encountered: