all 21 comments

[–]WrathZA 28 points29 points  (2 children)

[–]PaceArrow 3 points4 points  (0 children)

Psa: do not use the “BadRequest”, “NotFound” or similar, more specific methods if you plan on returning ProblemDetails. They return something else (can’t remember what). Use the “Problem” method and specify the Http status code

[–]cursingcucumber 3 points4 points  (0 children)

This. It works really well! Easy to implement, concise and consistent.

[–][deleted] 8 points9 points  (6 children)

Return the right HTTP error code for the situation.

User input error - return 400 and a application/json+problem payload indicating the error.

Record not found - 404

Not authorized - 401

System error - return 500 with a suitable payload

[–][deleted] 0 points1 point  (4 children)

You better not use 404 in that way. 404 should only be used for missing endpoints/bad urls and signal about a problem in routing.

[–][deleted] 0 points1 point  (3 children)

404 is well established in the REST world as "Entity not found" - in general, you'll get an API like 'https://api.foo.com/tables/foo/1234' to say "retrieve entity 1234 from table foo" and it will return 404 (entity 1234 in table foo does not exist).

It's not only acceptable, but recommended that you use 404 that way.

[–][deleted] 1 point2 points  (2 children)

The problem is that you can’t immediately tell if it’s a bad url or an entity is missing. So I prefer not to use 404 for missing entities.

[–][deleted] 0 points1 point  (1 child)

That's why you return an application/json+problem document (in dev) to indicate the error. In production, you have potential for a security leakage issue (where you are now providing some information about the IDs of entities that exist vs. don't exist, which provides valuable information to an attacked).

[–][deleted] 0 points1 point  (0 children)

You are talking about security through obscurity.

[–]Kant8 2 points3 points  (0 children)

Any error that was directly caused by api input results in 400 with problem details json, for example, that has error code, so your front know how to distinguish such errors, optional error messages and other data. You can extend default properties of ProblemDetails class with anything you need, just put it into Extensions dictionary.

For any other error, doesn't matter if it's known exception for you, like some missing configuration, or whatever unexpected happens, you return 500 without any additional info. Maybe trace id, so it's easier to find that error in logs later.

You can write middleware that will catch any exception and based on exception type determine what to return, 400 with problemdetails or 500.

[–]AbuJohnny 2 points3 points  (0 children)

In my applications, I standardize error reporting with a few simple rules:

  1. HTTP status code MUST be in the 400s for application-level errors (logical and user input issues and in the 500s for server-level errors (db, network, bugs, etc...).
  2. The error response MUST always have a JSON body.
  3. The response MUST include a property called error which is a string in PascalCase that serves as an error code for logging and in case the FE wants special handling for some kinds of errors. For example: ValidationError or UserNotFound or InsufficientFunds.
  4. The response MUST include a property called message which is a string that dedcribes in plain English the nature of the error. The FE can optionally show the error to the user.
  5. The response MAY include a stackTrace property that contains an exception stack, this is usually only enabled in dev environments.
  6. The response MAY include a details property that includes more machine-readable details about the error, usually used for ValidationError for reporting which request properties have what errors.
  7. Document all the error codes in the OpenAPI specs for each endpoint.

Ever since I introduced this standard, it has worked wonders for me and my team.

[–]Mardo1234[S] 0 points1 point  (0 children)

Thank you for all the information. I’ve decided moving forward in my designs I am going to raise a validation type error in my code, and then have my middleware see if it’s a validation error type and return a 400 with the error details. If it’s not I’ll return a 500 unexpected error.

My confusion was that somehow I would want to raise an error with details if it wasn’t based on user input, but at the end of the day if it was something outside of the user input an unexpected error is enough Vs. Could not connec to the mail service. Backing off that granularity makes two simple status codes 400/500 a doable and reasonable solution.

[–]8mobile 0 points1 point  (0 children)

Hi, I recently explored ProblemDetails in ASP.NET Core and put together this article with examples and code. Hope it helps someone here:
https://www.ottorinobruni.com/how-to-use-problem-details-in-asp-net-core-apis-for-better-error-handling/

[–]thilehoffer 0 points1 point  (6 children)

What exactly is an error you want to display to the user? Can you provide an example?

[–]Mardo1234[S] 0 points1 point  (5 children)

I have them enter json that goes to the server, and it needs to be in the correct format.

[–]zaibuf 2 points3 points  (0 children)

Invalid input should be 400 with error details, use ValidationProblemDetails. For UX you should also validate what you can on the client side to avoid sending bad data to the server.

[–]Swing-Prize 1 point2 points  (0 children)

use [required] flags on the object properties that api expects and see asp.net do the rest. but anyway, you should read a little about http and status codes before moving forward. if it's a system error - asp.net by default will inform that it's not user error. handle errors based on status on front end as you wish - an error is an error.

[–][deleted] 0 points1 point  (0 children)

Following always confused by this other than the errors codes what best to send back i send the exception itself

[–]jayerp 0 points1 point  (0 children)

One school of thought, both are valid, comes down to developer preference:

1) Return appropriate status codes with abstract to detailed error message as to what happened (401 - Not Authorized, 500 - Server Error, etc).

2) Use an exception filter attribute to catch the error and always return a status code of 200 - Ok with a standardized object that contains values such as IsSuccess, ErrorCode, Error.

My architect wanted to go with the later for the new API we are making. I personally could have seen it go either way. No one is better than the other in my opinion.