I have created an API method using Web API 2 (MVC 5), as shown below:
/// <summary>
/// Import all of the jobs for the given organisation. This method assumes that all of the organisation's active jobs are present in the jobs array.
/// To delete a job, simply exclude it from the jobs array. To delete all of the jobs, pass an empty array
/// </summary>
/// <param name="org">Organisation Id, provided by Shopless team</param>
/// <param name="jobs">Full list of jobs which should be imported, json array</param>
/// <response code="200">Jobs list have been queued for import (includes validation errors if any)</response>
/// <response code="401">Access to this organisation was denied</response>
/// <response code="404">Invalid organisation id</response>
[SwaggerResponse(HttpStatusCode.BadRequest)]
[SwaggerResponse(HttpStatusCode.NotFound)]
[SwaggerResponse(HttpStatusCode.Unauthorized)]
[HttpPost]
[Route("org/{org}/jobs/full-import")]
public IHttpActionResult FullImport(long org, [FromBody] List<JobApiDto> jobs)
{
if (!ModelState.IsValid)
{
return BadRequest("Jobs array is invalid");
}
else if (org < 1)
{
return NotFound("Invalid organisation id");
}
else if (!((ClaimsPrincipal)User).HasReadWriteAccessToOrganisation(org))
{
return Unauthorized("Access to this organisation was denied");
}
_apiProductUploader.Upload(org, jobs, out string message);
return Accepted(message);
}
The above methods accepts a list of JobApiDto
:
public class JobApiDto
{
/// <summary>
/// Job Id (unique id assigned to the job by the API consumer)
/// </summary>
/// <example>e5f52dae-e008-49bd-898b-47b5f1a52f40</example>
public string UniqueThirdPartyId { get; set; }
/// <summary>
/// Short description which will be displayed in search result
/// </summary>
/// <example>Competitive salary, great team, cutting edge technology!</example>
public string Synopsis { get; set; }
// more properties
And this is how the Swagger documentation looks like:
When I expand OrganisationJobs
action:
As you can see the xml documentation for the controller has generated the correct description for the API method, but I am not able to understand why the description that I have provided for my model (i.e. JobApiDto
) does not show?
Also when I click on Example Value nothing happens.
Thanks to Alexandre for pointing out this answer.
I installed Swashbuckle.Examples Nuget package. (The documentation is great.)
I had to annotated the controller with:
[SwaggerRequestExample(typeof(JobApiDto), typeof(ListJobApiDtoExample), jsonConverter: typeof(StringEnumConverter))]
This is how the controller definition looks like:
/// <summary>
/// Import all of the jobs for the given organisation. This method assumes that all of the organisation's active jobs are present in the jobs array.
/// To delete a job, simply exclude it from the jobs array. To delete all of the jobs, pass an empty array
/// </summary>
/// <param name="org">Organisation Id, provided by Shopless team</param>
/// <param name="jobs">Full list of jobs which should be imported, json array</param>
[SwaggerRequestExample(typeof(JobApiDto), typeof(ListJobApiDtoExample), jsonConverter: typeof(StringEnumConverter))]
[SwaggerResponse(HttpStatusCode.OK, Description = "Jobs array has been queued for import", Type = typeof(ImportResponse))]
[SwaggerResponseExample(HttpStatusCode.OK, typeof(ImportResponseExamples))]
[SwaggerResponse(HttpStatusCode.BadRequest, "Jobs array is invalid")]
[SwaggerResponse(HttpStatusCode.NotFound, "Invalid organisation id")]
[SwaggerResponse(HttpStatusCode.Unauthorized, "Access to this organisation was denied")]
[HttpPost]
[Route("org/{org}/jobs/full-import")]
public IHttpActionResult FullImport(long org, [FromBody] List<JobApiDto> jobs)
{
if (!ModelState.IsValid)
{
return BadRequest("Jobs array is invalid");
}
else if (org < 1)
{
return NotFound("Invalid organisation id");
}
else if (!((ClaimsPrincipal)User).HasReadWriteAccessToOrganisation(org))
{
return Unauthorized("Access to this organisation was denied");
}
_apiProductUploader.Upload(org, jobs, out ImportResponse importResponse);
return Accepted(importResponse);
}
And here is the implementation of ListJobApiDtoExample
:
public class ListJobApiDtoExample : IExamplesProvider
{
public object GetExamples()
{
return new JobApiDto()
{
UniqueThirdPartyId = "e5f52dae-e008-49bd-898b-47b5f1a52f40",
CategoryId = 1183,
Title = "Senior Software Developer",
Description = "Example company is looking for a senior software developer... more details about the job",
Reference = "",
Synopsis = "Competitive salary, great team, cutting edge technology!",
MinSalary = 120000,
MaxSalary = 140000,
SalaryPer = "Per annum",
DisplaySalary = true,
CustomSalaryText = "plus bonus",
WorkType = "Full time",
Location = "Wellington CBD",
ContactName = "John Smith",
ContactEmail = "[email protected]",
ContactPhoneNumber = "021 123 456 789",
ApplicationUrl = "",
LogoUrl = "https://www.example-company.com/my-company-logo",
YouTubeVideo = "https://www.youtube.com/watch?v=khb7pSEUedc&t=1s",
StartDate = null,
PostedAt = null
};
}
}
Note that I also have an example for my API return type, ImportResponse
. Similar to previous model, I have this annotation on the controller:
[SwaggerResponseExample(HttpStatusCode.OK, typeof(ImportResponseExamples))]
And here is it's implantation:
public class ImportResponseExamples : IExamplesProvider
{
public object GetExamples()
{
return new ImportResponse()
{
Message = "Products are queued to be imported"
};
}
}
And now, the documentation shows the examples correctly: