0

I have a project on Asp.net Web Api 2. I faced kind of interesting behavior of .net framework during testing one of the endpoint.

this is the simplified version of endpoint:

    [Route("api/v1/bookings/documenttype/{clientId}/{companyCode}/{year}")]
    [HttpGet]
    [ResponseType(typeof(IEnumerable<UserVoucherType>))]
    public IHttpActionResult GetUserDocumentTypes(int clientId, string companyCode, 
                                                  int year, [FromUri] int? month = null)
    {
        //Do Some work
        return Ok();
    }

the problem here when I send a non integer value as value of 'month' parameter instead of getting bad request or something like this I get null during run time and this cause problem. For example one of the consumer of endpoint were sending '[1,2,3]' and getting all data for whole year instead of getting an error message.

For example for this request I am getting below values that I pointed on ss: http://localhost:64652/api/v1/bookings/documenttype/1/0001/2019?month=[1,2,3] enter image description here

Now my question how can I return a bad request for a case like this.

The month parameter is optional and I can't understand on endpoint did consumer send this parameter null on purpose or they send a not valid value for parameter.

Is there a setting for this ? I was thinking to write a custom paramater binder but isn't this over engineering ? I think the behavior of framework should be default returning bad request or am I missing something?

nzrytmn
  • 6,193
  • 1
  • 41
  • 38
  • you should validate users's input, if failed you can return badrequest, read here on how to return bad request https://stackoverflow.com/a/10734690/1638261 – jomsk1e Dec 17 '20 at 08:35
  • 1
    @jomsk1e How can I do validate parameter, it is getting null and this can be normal behavior too because of it is optional parameter , the problem I can't understand on endpoint is someone really send month parameter null or send a wrong value and become null. – nzrytmn Dec 17 '20 at 08:55

2 Answers2

1

You could create a model for your optional params and apply the Range attribute to month.

(This is .NET5 so I'm using [FromQuery], but this should work for [FromUri] too)

public OkResult GetUserDocumentTypes(int clientId, string companyCode, 
                                            int year, [FromQuery] GetUserDocumentTypesOptionalInput optional)
{
//Do Some work
    return Ok();
}

public class GetUserDocumentTypesOptionalInput 
{
    [Range(1, 12, ErrorMessage = "Invalid month")]
    public int? Month {get; set; } // 1 or 0 based? 
}

It will depend on your configuration if you have to manually check ModelState.IsValid to catch the error.


Also, with <TargetFramework>net5.0</TargetFramework> and [FromQuery] int? month = null the following error would be returned:

{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "00-65615fa2ff03a141b2cd80d7fc4f9dca-db45cf7466ae6f4f-00",
    "errors": {
        "month": [
            "The value '[1,2,3]' is not valid."
        ]
    }
}
tymtam
  • 31,798
  • 8
  • 86
  • 126
0

You can change the Route attribute to include the data type constraint.

[Route("api/v1/bookings/documenttype/{clientId}/{companyCode}/{year:int{min:2000}/{month:int?}")]

I have added 2 constraints - data type for month and year, and min value for year.

For more details, refer to the official documentation from Microsoft.

samiksc
  • 167
  • 10
  • Unfortunately Changing path is not an option for us. The all optional parameters must be query parameter in our api. – nzrytmn Dec 17 '20 at 09:39
  • Path is not changed here from user's point of view. User will still use the same path like api/v1/bookings/documenttype/1/0001/2019?month=11 The change is suggested on the server side, in the Route attribute on top of the GetUserDocumentTypes(). Let's add constraints on data type and values for the query parameters there. – samiksc Dec 22 '20 at 06:15