-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
WebApiToSwaggerGenerator
- Package: NSwag.Generation.WebApi
- Type: NSwag.Generation.WebApi.WebApiOpenApiDocumentGenerator
- Settings: WebApiOpenApiDocumentGeneratorSettings
- Usage: Code (below)
The WebApiOpenApiDocumentGenerator
class is used to generate a Swagger specification from ASP.NET Web API controllers:
var settings = new WebApiOpenApiDocumentGeneratorSettings
{
DefaultUrlTemplate = "api/{controller}/{action}/{id}"
};
var generator = new WebApiOpenApiDocumentGenerator(settings);
var document = await generator.GenerateForControllerAsync<PersonsController>();
var swaggerSpecification = document.ToJson();
The generator internally uses the JsonSchemaGenerator class from the NJsonSchema project to generate the JSON Schemas of the request and response DTO types.
ASP.NET Core
Important: This reflection based generator is deprecated for ASP.NET Core projects and replaced by the new APi Explorer based generator AspNetCoreOpenApiDocumentGenerator!
When generating a Swagger specification for an ASP.NET Core application, set the IsAspNetCore
setting to true.
- Controller classes:
-
RoutePrefixAttribute
on the controller class -
DescriptionAttribute
on the controller class (used to fill the Swagger 'Summary')
-
- Action methods:
-
RouteAttribute
andActionNameAttribute
on the action method, with support for Route constraints (e.g.[Route("users/{id:int}"]
) -
DescriptionAttribute
on the action method (used as Swagger operation 'Description') - One or more
ProducesResponseTypeAttribute
on the action method - HTTP verb attributes:
AcceptVerbsAttribute
HttpGetAttribute
HttpPostAttribute
HttpPutAttribute
HttpDeleteAttribute
HttpOptionsAttribute
-
- Action method parameters:
-
FromBodyAttribute
on the action method parameter ModelBinderAttribute
-
The generator also supports data annotations, check out this page for more information.
- Package: NSwag.Annotations
SwaggerResponseAttribute(httpAction, type)
Defines the response type of a Web API action method and HTTP action. See Specify the response type of an action.
SwaggerDefaultResponseAttribute()
Adds the default response (HTTP 200/204) based on the return type of the operation method. This can be used in conjunction with the SwaggerResponseAttribute
or another response defining attribute (ProducesResponseTypeAttribute
, etc.). This is needed because if one of these attributes is available, you have to define all responses and the default response is not automatically added. If an HTTP 200/204 response is already defined then the attribute is ignored (useful if the attribute is defined on the controller or the base class).
OpenApiIgnoreAttribute()
Excludes a Web API method from the Swagger specification.
SwaggerOperationAttribute(operationId)
Defines a custom operation ID for a Web API action method.
SwaggerTagsAttribute(tags)
Defines the operation tags. See Specify the operation tags.
SwaggerExtensionDataAttribute()
Adds extension data to the document (when applied to a controller class), an operation or parameter.
- Package: NJsonSchema
NotNullAttribute and CanBeNullAttribute
Can be defined on DTO properties (handled by NJsonSchema), operation parameters and the return type with:
[return: NotNull]
public string GetName()
The default behavior can be changed with the WebApiOpenApiDocumentGeneratorSettings.DefaultReferenceTypeNullHandling
setting (default: Null).
Sometimes, the response type of an action method cannot be determined using reflection. As an example, this is the case when a method returns an HttpResponseMessage
or IActionResult
. To define the response type for the Swagger generator, you can add the SwaggerResponseAttribute
to the action method (or the ASP.NET Core built-in attribute ProducesResponseTypeAttribute
):
[SwaggerResponse(typeof(Person))]
public HttpResponseMessage Get(int id)
{
...
}
You can use the attribute from the System.Web.Http.Description
namespace or the NSwag.Annotations
NuGet package. If you use the latter attribute, you can also define result types per HTTP status code:
[SwaggerResponse("200", typeof(Person))]
[SwaggerResponse("500", typeof(PersonNotFoundException))]
public HttpResponseMessage Get(int id)
{
...
}
The SwaggerResponseAttribute
with the HTTP status code parameter can be found in the NSwag.Annotations
NuGet package, or can implemented in your own project (it just needs the same class name and properties). The implementation can be copied here (the namespace can be changed).
To define an operation without a response (i.e. HTTP 204 or 404), use the SwaggerResponseAttribute
attribute and typeof(void)
:
[SwaggerResponse(typeof(void))]
[SwaggerResponse(404, typeof(void))]
public HttpResponseMessage Save(Person person)
{
...
}
If the response type cannot be determined, the type of generated response will be file
:
"responses": {
"200": {
"schema": {
"type": "file"
}
}
}
To force a file response, specify the response type with the SwaggerResponseAttribute
:
[SwaggerResponse(typeof(IActionResult))]
public HttpResponseMessage DownloadFile(string name)
{
....
}
We recommend to catch exceptions and return them with a custom HTTP status code. Sample Web API action:
[HttpPost]
[SwaggerResponse(200, typeof(int))]
[SwaggerResponse(500, typeof(LocationNotFoundException))]
public async Task<ActionResult> Create([FromBody]Person person)
{
try
{
var location = await _geoService.FindLocationAsync(person.Location);
person.LocationLatitude = location.Latitude;
person.LocationLongitude = location.Longitude;
}
catch (LocationNotFoundException locationNotFoundException)
{
return StatusCode(500, locationNotFoundException);
}
await _dataContext.SaveChangesAsync();
return Ok(person.Id);
}
In order to correctly serialize the custom exception, just add the JsonExceptionConverter from the NSwag.Annotations NuGet package (or use the JsonExceptionFilterAttribute):
[JsonConverter(typeof(JsonExceptionConverter))]
public class LocationNotFoundException : Exception
{
[JsonProperty("location")]
public string Location { get; }
public LocationNotFoundException(string location, Exception exception)
: base("The location could not be found.", exception)
{
Location = location;
}
}
With the SwaggerTagsAttribute
you can specify the Swagger tags for a Web API action method:
[SwaggerTags("foo", "bar")]
public void MyActionMethod()
{
...
}
If the attribute is not available, the controller name is added to the list of operation tags.
An operation parameter is treated as form file upload if it is/inherits/implements one of the following types (or a collection of it):
- IFormFile
- HttpPostedFile
- HttpPostedFileBase
You can also add the SwaggerFileAttribute
to a parameter or a class (implemented in the NSwag.Annotations
package):
public void MyOperation([SwaggerFile] MyClass myParameter)
{
...
}
You should use the OWIN middlewares to serve a Swagger specifications via HTTP.
You can serve the Swagger specification by running the Swagger generator in a Web API action method:
[RoutePrefix("api/MyWebApi")]
public class MyWebApiController : ApiController
{
// TODO: Add action methods here
private static readonly Lazy<string> _swagger = new Lazy<string>(() =>
{
var settings = new WebApiOpenApiDocumentGeneratorSettings
{
DefaultUrlTemplate = "api/{controller}/{action}/{id}"
};
var generator = new WebApiOpenApiDocumentGenerator(settings);
var document = Task.Run(async () => await generator.GenerateForControllerAsync<MyWebApiController>())
.GetAwaiter().GetResult();
return document.ToJson();
});
[SwaggerIgnore]
[HttpGet, Route("swagger/docs/v1")]
public HttpResponseMessage Swagger()
{
var response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.OK;
response.Content = new StringContent(_swagger.Value, Encoding.UTF8, "application/json");
return response;
}
}
The Swagger specification can now be accessed via the path http://myhost/api/MyWebApi/swagger/docs/v1
.
The following code shows how to implemented a controller which serves the Swagger specification for multiple controllers:
public class SwaggerController : Controller
{
private static readonly Lazy<string> _swagger = new Lazy<string>(() =>
{
var controllers = new[] { typeof(FooController), typeof(BarController) };
var settings = new WebApiOpenApiDocumentGeneratorSettings
{
DefaultUrlTemplate = "api/{controller}/{action}/{id}"
};
var generator = new WebApiOpenApiDocumentGenerator(settings);
var document = Task.Run(async () => await generator.GenerateForControllersAsync(controllers))
.GetAwaiter().GetResult();
return document.ToJson();
});
[SwaggerIgnore]
[HttpGet, Route("swagger/docs/v1")]
public HttpResponseMessage Swagger()
{
var response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.OK;
response.Content = new StringContent(_swagger.Value, Encoding.UTF8, "application/json");
return response;
}
}
Known issues:
- Bug: Action methods which return a string are not encoded as JSON (https://github.com/aspnet/Mvc/issues/4945). Either remove
StringOutputFormatter
or ensure that the response is a JSON.- Fixed in 2.0(https://github.com/aspnet/Mvc/releases/tag/rel%2F2.0.0)