Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwashBuckle define Response Body on Error

My application is an ASP.NET Core 1.0 Web API.

I have the following Controller:

    [HttpGet("{someData:MinLength(5):MaxLength(5)}")]
    [Produces("application/json")]
    public async Task<IActionResult> GetSomeData(string someData)
    {
        return this.Ok(JsonConvert.SerializeObject("Data is: " + someData));
    }

Whenever I pass for example the string "111", swagger is showing me the following message:

enter image description here

How can i achive a Response Body like:

"Please enter 5 numbers"

Thank you

like image 235
Moritz Schmidt Avatar asked Feb 04 '23 19:02

Moritz Schmidt


2 Answers

You can annotate your actions with [ProducesResponseType(typeof(ModelStateDictionary), (int)HttpStatusCode.OK)] to return the typical Dictionary typed error messages like when using return BadRequest(ModelState).

But you can't return a text in the schema definition. It is there for json structures, not for error messages. Instead you should use xmldoc (and also enable it in swagger) to add descriptions to the parameters.

Update: Alternative of adding documentation of the parameters and their meaning

/// <summary>
/// Returns some data based on <paramref name="someData"/> parameter.
/// </summary>
/// <param name="someData">Some data. (Must be exactly 5 characters wide)</param>
/// <response code="200">Returns indexed tags on success</response>
/// <response code="400">Invalid data sent</response>
/// <returns>A paged list of results</returns>
[HttpGet("{someData:MinLength(5):MaxLength(5)}")]
[ProducesResponseType(typeof(MyReturnType), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(void), (int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> GetSomeData(string someData)
{
}

Also you need to enable building of xmldocs in your project's properties.

And add to your startup:

services.AddSwaggerGen(options =>
{
    ...
    var appEnv = PlatformServices.Default.Application;

    options.IncludeXmlComments(Path.Combine(appEnv.ApplicationBasePath, $"{appEnv.ApplicationName}.xml"));
    ...
});
like image 145
Tseng Avatar answered Feb 08 '23 16:02

Tseng


I am using ApiBadRequestResponse class , that constructs list of strings from modelState instead of direct ModelState. The class copied from a nice article https://www.devtrends.co.uk/blog/handling-errors-in-asp.net-core-web-api.

Example of use:

 [ProducesResponseType(typeof(ApiBadRequestResponse), (int)HttpStatusCode.BadRequest)]
 public async Task<IActionResult> GetSomeData(string someData)
 {
   return BadRequest(new ApiBadRequestResponse(ModelState));
 }

Implementation ( base class described in the article):

/// <summary>
    ///  an ApiBadRequestResponse class to handle validation errors from modelState or exception.
    /// </summary>
    public class ApiBadRequestResponse : ApiResponse
    {
        public IEnumerable<string> Errors { get; }

        public ApiBadRequestResponse(ModelStateDictionary modelState)
            : base(HttpStatusCode.BadRequest) //400)
        {
            if (modelState.IsValid)
            {
                throw new ArgumentException("ModelState must be invalid", nameof(modelState));
            }

            Errors = modelState.SelectMany(x => x.Value.Errors)
                .Select(x => x.ErrorMessage).ToArray();
        }

        public ApiBadRequestResponse(Exception exception, string message=null)
            : base(HttpStatusCode.BadRequest, message) //400)
        {
            Errors = new List<string>() {exception.ToString()};
        }
    }

Another similar solution is in the article http://www.khalidabuhakmeh.com/a-better-validation-result-for-asp-net-webapi

like image 44
Michael Freidgeim Avatar answered Feb 08 '23 16:02

Michael Freidgeim