Bad-request vs Unprocessable-entity

Icons made by Freepik, Kiranshastry, and Smashicons from Flaticon.

TL;DR -> Checkout this repository to see how the bad-request and unprocessable-entity responses are managed at different levels of the core application.


During the development of a REST API, there are mainly two types of errors that our clients care about:

  • Bad request responses: We provide information about the input format. For example, if a text input was meant to be an email, we simply tell the client that.
  • Unprocessable entity responses: This type of response aims to tell the client “your input has the right format, BUT somehow the server was not able to process the request”.

For example, let’s imaging we have an API with a single endpoint:

POST /process?

The rules to call this endpoint are:


  • The query parameter accountId CAN NOT be a number.


  • To start the so-called process, the account MUST be OPEN.

The last couple of rules are meant to provide context about a business process. For the sake of this example, let’s say that there are two internal services that allow us to check those statements.

public interface IAccountRepository
Task<bool> IsAccountOpen(string accountId);
public interface IUserRepository
Task<bool> IsUserActive(string userId);

As you can imagine, there is a difference in terms of cost to check the format-rules (very fast and we don’t need any extra call) and the business-rules (Their cost is high since requiring extra operations inside our system).

How we do it

  • All format errors are provided to the client. We follow the core 3.1 format, which is quite handy. Also, the format errors do not have a dedicated error code.
Request and response provided by the example service using Postman.
  • When there is a business error, only the first occurrence is provided to the client to obtain a fast (and cheap) response.
Unprocessable entity response with error code and description when user status is inactive.


  • For the format rules, you need to make use of the class called “ModelState”. This class allows storing errors that would be shown to the user as the content of the bad-request response.
How to manage input format verification with ModelState class.
  • For the business rules, my advice is to use a dedicated “BusinessExceptionMiddleware” that catches business exceptions. You can add it to your middleware pipeline and, at any point inside your service, launch business exceptions.
Business exception middleware.
Injection of the BusinessExceptionMiddleware.

After injecting your middleware, you can launch business exceptions that will be caught by your middleware. Example:

Launching exceptions when business rules are not verified.


And you? How do you do it? 😊

Happy coding!

Proud teacher-volunteer at Migracode and Cloud-engineer at Ohpen where I keep pushing my AWS+Serverless knowledge every day.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store