dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.42k stars 10.01k forks source link

[Question] Is there a way to properly emulate InvalidModelStateResponseFactory in minimal apis? #57337

Open michaeltg17 opened 2 months ago

michaeltg17 commented 2 months ago

Hi.

When trying to migrate some existing endpoints to minimal apis, I discovered that is not as easy as in controllers to change the behaviour of a binding error (and I wanted to return the same responses...).

In controllers you have the InvalidModelStateResponseFactory which you can use to modify the response to these invalid requests:

image

When trying to do the same in minimal apis, I have found two ways, filter or middleware.

With a filter you get the arguments but you don't know why the binding failed (required parameter not provided vs. not parsable) and the arguments have default values (like 0 but you passed a string)

With a middleware you can catch the exception but you only get a message like "Failed to bind parameter "long id" from "this has to be a long"."

So the question is, is there another way so I can return the same response as before when using controllers but using minimal apis?

Thanks.

captainsafia commented 2 months ago

@michaeltg17 Thanks for filing this issue!

Unfortunately not, there isn't a super great way to do this with minimal APIs at the moment. We've been tracking this in the backlog via https://github.com/dotnet/aspnetcore/issues/35501.

The referenced issue recommends a workaround using middleware (ref).

With a middleware you can catch the exception but you only get a message like "Failed to bind parameter "long id" from "this has to be a long"."

Is there additional information not in the exception message that you would like to have access to? Also, can you share an example of the ValidationProblemDetails that you are currently returning?

michaeltg17 commented 2 months ago

Hi, thanks for the reply.

I'm doing this test request:

image

To controller endpoint:

image

To minimal api endpoint:

image

This is the response from the controller:

{
    "detail": "Please check the errors property for additional details.",
    "errors": {
        "": [
            "A non-empty request body is required."
        ],
        "date": [
            "The value 'b' is not valid."
        ],
        "id": [
            "The value 'a' is not valid."
        ],
        "request": [
            "The request field is required."
        ]
    },
    "instance": "/TestController/Post/a",
    "status": 400,
    "title": "ValidationException",
    "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1"
}

The errors object in the response comes from the ModelState which is passed into the constructor of ValidationProblemDetails, so it builds that.

Wanted the same response in minimal api, but in the exception I only have this:

Capture

So I guess this is hard to recreate as it happens during the binding... and the exception doesn't contain all the errors or all the parameters with their current values so that you can build something similar. I'm not saying it should though.

In any case this was what I was trying to do, but I'll try to return a different response in case of minimal api if there is no other option.

Regarding the workaround (https://github.com/dotnet/aspnetcore/issues/35501#issuecomment-902072079), I don't really understand how it could help.

Thanks!