I have an example input model as follows:
public class CarInputModel {
public string Name { get; set; }
public string ModelName { get; set; }
}
This values will come from UI, what kind of annotations can I use with swagger to describe this API model as much as possible?
You can't use many annotations at all to describe the model. You mostly describe the API itself
[HttpGet] and [HttpPost] for the http attributes
[Produces(typeof(CarInputModel)] for the return type of an action and [ProducesResponseType(typeof(CarInputModel), (int)HttpStatusCode.OK)] for result types based on http code (i.e. return different model on error)
[Route] for the route itself
Additionally you can use Xml Docs to describe the classes and their parameters.
/// <summary>
/// Adds a new car model.
/// </summary>
/// <param name="model">The model to add</param>
/// <response code="201">Returns when the car was added successfully and returns the location to the new resource</response>
/// <response code="400">Invalid Request data.</response>
/// <response code="409">Car mode already exists.</response>
/// <returns>The newly added model on success and a list of errors on failure.</returns>
[HttpPost]
[ProducesResponseType(typeof(CarInputModel), (int)HttpStatusCode.Created)]
[ProducesResponseType(typeof(SerializableError), (int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(void), (int)HttpStatusCode.Conflict)]
public IActionResult AddCar(CarInputModel model)
{
}
/// <summary>
/// Represents a car
/// </summary>
public class CarInputModel {
/// <summary>
/// Name of the car
/// </summary>
public string Name { get; set; }
/// <summary>
/// Model of the car
/// </summary>
public string ModelName { get; set; }
}
In order to use XmlDocs you need to enable compilation of the xml docs in your project settings (and the of your models) and then add this to your Startup.cs
services.AddSwaggerGen(options =>
{
var appEnv = PlatformServices.Default.Application;
options.IncludeXmlComments(Path.Combine(appEnv.ApplicationBasePath, $"{appEnv.ApplicationName}.xml"));
});
Related
I'm working on a GET API in dotnet and I've been trying to document the query parameter being passed which is an aggregate object for the pagination of results (page size and page number).
Comments/documentation for get method:
/// <param name="Id">ID used to identify a record</param>
/// <param name="paginationParams">Request object that contains the pagination parameters <inheritdoc cref="PaginationParameters"/></param>
As you can see above, I'm referring to the PaginationParameters aggregate object/model. Now, this doesn't seem to be working correctly, or has no affect as I can change the field to [Required] and the swagger then reflects that. However, it's worth noting the ID field is documenting fine.
Below is the method signature for the get method:
public async Task<IActionResult> GetStuff([FromHeader][BindRequired] int Id, [FromQuery] PaginationParameters paginationParams)
Finally, my model is as of below:
/// <summary>
/// Pagination parameters
/// </summary>
public class PaginationParameters
{ /// <summary>
/// PageNumber
/// </summary>
[Required]
public int? PageNumber { get; set; } = null;
/// <summary>
/// PageSize
/// </summary>
[Required]
public int? PageSize { get; set; } = null;
}
It's driving me up the wall that it's not working and I'm sure it would be a simple fix, it just seems to be ignoring my descriptions for page size and page number.
TIA,
I am trying to set up examples using tag but, it is not working for me. I am using Swashbuckle.AspNetCore library.
Some code samples are below,
Added the following to my csproj. file
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Program.cs
builder.Services.AddSwaggerGen(options =>
{
options.OperationFilter<SwaggerDefaultValues>();
var filePath = Path.Combine(System.AppContext.BaseDirectory, "My.xml");
options.IncludeXmlComments(filePath);
});
Controller looks like,
[Authorize]
[ApiController]
[ApiVersion("1.0")]
[Route("[controller]")]
[Route("v{version:apiVersion}/[controller]")]
[Produces("application/json")]
public class MyController : ControllerBase
{
}
My method looks like,
/// <summary>
/// Method to Post an Incident
/// </summary>
/// <param name="initiateRequest" example="FORM_CODE"></param>
[ProducesResponseType(typeof(InitiateResponseDTO), StatusCodes.Status201Created)]
[ProducesResponseType(typeof(ExceptionDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[HttpPost]
public async Task<ActionResult<InitiateResponseDTO>> PostAsync(MyRequest myRequest)
{
//Logic
return StatusCode(StatusCodes.Status201Created, InitiateResponseDTO);
}
MyDTO looks like,
/// <summary>
/// Initiate Response DTO
/// </summary>
public class InitiateResponseDTO
{
/// <summary>
/// IncidentId
/// </summary>
/// <example>985769890</example>
public int IncidentId { get; set; }
}
Exception Details Class
/// <summary>
/// Exception Details class
/// </summary>
public class ExceptionDetails
{
/// <summary>
/// HTTP status code for the exception.
/// </summary>
/// <example>400</example>
public int StatusCode { get; set; } = (int)HttpStatusCode.InternalServerError;
/// <summary>
/// (Friendly) message about the exception.
/// </summary>
/// <example>Invalid form code supplied: FORM_CODE</example>
public string Message { get; set; } = "An error occured";
/// <summary>
/// Error code for the returned error.
/// </summary>
/// <example>UNKNOWN_FORM</example>
public string ErrorCode { get; set; } = ErrorCodes.Generic;
/// <summary>
/// Exception Target denoting the method in which the error occurred.
/// </summary>
/// <example>MoveNext <- Method name from which the error occurred</example>
public string? Target { get; set; }
/// <summary>
/// InnerError message denoting the StackTrace.
/// </summary>
/// <example> Some Sample</example>
public string? InnerError { get; set; }
}
Still in Swagger UI, I don't see the example values,
Is there anything incorrect with the config? I am using Swashbuckle.AspNetCore 6.4.0
One simple option would be to decorate your properties with the [DefaultValue]
/// <summary>
/// Initiate Response DTO
/// </summary>
public class InitiateResponseDTO
{
/// <summary>
/// IncidentId
/// </summary>
/// <example>985769890</example>
[DefaultValue(985769890)]
public int IncidentId { get; set; }
}
Depending on how the serialization is done in your project, it should work.
There is also the possibility to look into the Swashbuckle.AspNetCore.Filters Nuget library to setup your examples as you like, but it requires more work: https://github.com/mattfrear/Swashbuckle.AspNetCore.Filters#automatic-annotation
In C# (Asp.Net Core) )I have the following documentation over a child object of type NameValue.
I wish to have the documentation I added here over FromWarehouse, but when Swagger renders, it uses the definition for NameValue, not FromWarehouse.
/// <summary>
/// The warehouse this transfer is coming from
/// </summary>
/// <remarks>GLW, WDI, PSO, SMA, SHW</remarks>
public NameValue FromWarehouse { get; set; }
You need to do 3 things:
The summary should be moved from class property to class.
not here
public NameValue FromWarehouse { get; set; }
but to
/// <summary>
/// The warehouse this transfer is coming from
/// </summary>
/// <remarks>GLW, WDI, PSO, SMA, SHW</remarks>
public class NameValue{
....
You need to add document generation, with Include Xml Comments
services.AddSwaggerGen(c =>
{
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
});
Add this to your .csproj file
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
This is the example I used
/// <summary>
/// The warehouse this transfer is coming from
/// </summary>
/// <remarks>GLW, WDI, PSO, SMA, SHW</remarks>
public class NameValue
{
/// <summary>
/// The Name
/// </summary>
public string Name { get; set; }
/// <summary>
/// The Value
/// </summary>
public string Value { get; set; }
}
Here is the result:
The remarks, I was not able to include the, but as far as I understand, remarks are used to provide payload example, and it is used on top of the resource method.
All this I use with dotnet 6 and Swashbuckle.AspNetCore Version 6.2.3.
I hope it helps.
Reference to Microsoft documentation.
I am trying to call a service through swagger, by passing a parameter in XML format.
Method is hitting, but the passed parameter is blank
Means "xlff" is blank. Do you have clue what wrong i am doing
/// <summary>
/// Get or insert blog comments which is approved based on blogs
/// </summary>
/// <remarks> Get or insert blog comments which is approved based on blogs</remarks>
/// <param name="xlf">The comment.</param>
/// <response code="200">Get approved blog comments</response>
/// <response code="404">Not found</response>
/// <returns>IHttpActionResult</returns>
[Route("api/smartling/ProcessSmartlingTranslation")]
[VersionedRoute("", 1)]
[ResponseType(typeof(HttpResponseMessage))]
[HttpPost]
public IHttpActionResult ProcessSmartlingTranslation([FromBody]xliff xlff)
{
return Content(HttpStatusCode.BadRequest, "Any object");
}
/// <summary>
/// XliffModel created
/// </summary>
public class xliff
{
/// <summary>
/// file getter setter method
/// </summary>
public string file { get; set; }
/// <summary>
/// body getter setter method
/// </summary>
public string body { get; set; }
}
Your parameter content type is application/json, but you're sending xml. You should change the content type to application/xml.
Code is further down in the post.
Question: I would like Swashbuckle to generate the following two "GET" requests:
1. mydomain.com/api/books?apikey=12345567891011121314151617181920
2. mydomain.com/api/books/1234?apikey=12345567891011121314151617181920
Swashbuckle does fine on #1 and it works great from the Swagger UI. But for #2, it ends up generating (and calling):
mydomain.com/api/books/{Id}?id=1234&apikey==12345567891011121314151617181920
Needless to say, that GET fails. Swashbuckle is picking up the literal "Id" from the route attribute as well as the BookDetail object. In fact, it shows both IDs in the UI, but I was able to solve that by de-duping by hooking up a custom IOperationFilter, but that obviously didn't help with correcting the actual GET request path.
I already looked at Duplicate parameter output in Swagger 2 but that answer does not work for me. I am looking for having Swashbuckle use the "Id" that's part of the BookDetail object so that Swagger UI shows the description (from the XML comment) while supporting route based ID rather than query string based: mydomain.com/api/books/1234.... What am I doing wrong? (I am on Swashbuckle 5.2.2).
Code:
/// <summary>
/// Books controller
/// </summary>
[RoutePrefix("api")]
public class BooksController : ApiController
{
/// <summary>
/// Returns books matching the search query
/// </summary>
/// <param name="searchRequest"></param>
/// <returns></returns>
[Route("books")]
public IHttpActionResult Get(BookSearch searchRequest)
{
//Do stuff with request
return Ok();
}
/// <summary>
/// Retruns a single book for the given ID
/// </summary>
/// <param name="detailRequest"></param>
/// <returns></returns>
[Route("books/{id:int}")]
public IHttpActionResult Get(BookDetail detailRequest)
{
//Do stuff with request
return Ok();
}
/// <summary>
/// Book search
/// </summary>
public class BookSearch
{
/// <summary>
/// API key
/// </summary>
[Required]
public string ApiKey { get; set; }
/// <summary>
/// Search terms
/// </summary>
public string Query { get; set; }
}
/// <summary>
/// Book detail
/// </summary>
public class BookDetail
{
/// <summary>
/// API key
/// </summary>
[Required]
public string ApiKey { get; set; }
/// <summary>
/// Book of the ID you want to retrieve
/// </summary>
[Required]
public int Id { get; set; }
/// <summary>
/// Boolean indicating whether to include photos or not
/// </summary>
public bool IncludePhotos { get; set; }
}
}