Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free.

Suppose I'm doing some DDD. Now, I have a microservice reflecting a bounded context/a part of a bounded context.

Now, suppose there is a REST endpoint:

'/somedomainmodel/someaction'

My API user is doing a POST request with somehow invalid data. I'm using Java and assume that following chain is executed:

  • request is handled by a Spring controller or something else

  • controller is invoking a method on an application service

  • application service is doing some action on a domain model

But as I mentioned before, data provided by an user is somehow incorrect and could cause my domain object to get into invalid state. So a subclass of DomainException extends RuntimeException is thrown.

Now: how should I handle this? Suppose my endpoint is used by a frontend and I want to display a proper message to user.

Should I return a status code and a message in a response? Where should it be detected and how? In an application service? Or maybe in a controller? And since it's not a checked exception, how should I handle it? Try/Catch for a runtime exception seems to be awful.

Maybe if we're talking about specifing implementation, should I use something like spring's @ExceptionHandler?

share|improve this question
    

4 Answers 4

I prefer to do something like this:

  1. The rest end point will receive an request with data then,
  2. Business service class is called with the data
  3. Validate the data if invalid throw an exception with proper description, e.g.: throw new InvalidArgumentException("invalid objet Id");
  4. On controller if above exception is thrown then return 400 Bad Request with error description e.g.: {"ok":false, "error":"invalid_argument","msg":"invalid objet Id"}

By doing this way the business class can be used anywhere and response can be handled accordingly.

share|improve this answer

My belief is that you can just send the response from the error handler or test the data before sending if possible. Can also use a preload step during app initialization from your REST interface and store valid value parameters and use those on your client to test data going out.

It would be simple to try to send a response from your handler. Garbage collection will clean up i.e. errors are costly. So a better design is client cleaning. Hope that helps.

share|improve this answer
    
So you think I should basically send a response with error code and maybe a reason in json from my error handler? Validating data before sending a request, on a client side doesn't make any sense - consider a case when you try to participate in a specific event, but you are already assigned for another event at the sime time - I don't want this validation to be done on client side. And maybe there is another, domain restriction which states you cannot participate in specific event - how would you check it on client side? –  slnowak Feb 16 at 11:15

You should return a 4xx error with a detailed description of the reason the request failed in the response body.

Can't help with the Java implementation. In many Python frameworks you would throw a 4xx exception as soon as your code has determined that the HTTP request is going to fail and this is caught by the framework and returns a 4xx HTTP status message.

share|improve this answer

Recently I wrote a detailed post on these and some related questions.

Should I return a status code and a message in a response?

Yes, but message should not contain exception message unless that message was crafted specifically to be shown to end user. Since you talk about DomainException, which probably should be quite specific about explaining what happened and why, you may show this exception message to a user. However, I recommend you to separate domain-level exceptions from API-level exceptions, and make latter be 100% "user-safe", so you can show them to end user without worrying it contains something like "MySQLIntegrityConstraintViolationException".

API-level exceptions should look like this:

// Assume that all those exception classes extend some base class `ApiException`

throw new ApiNotFoundException(404, "Entity with id=" + id + " not found.");

throw new ApiDatabaseUnavailableException(502, "Database server is unavailable. Retry later.")

throw new ApiConstraintViolationException(422, // WebDAV, Unprocessable Entity
    "Entity with id=" + id + " cannot be deleted " +
    "because it is a parent of entity with id=" + childId + ". "
    "Delete all children first.");

Where should it be detected and how?

There are several layers in application where different types of exceptions whould be handled. Basic idea is: handle standard Java exceptions (NPEs, IllegalArgument, etc.) as soon as possible, wrap them into something more specific and throw further. Then later you can handle domain-specific exception in a middle layer, and finally API-specific exceptions can all be handled in a single "catch-them-all" handler/interceptor.

See Logging Exceptions: Where to Log Exceptions? and my post for details.

And since it's not a checked exception, how should I handle it? Try/Catch for a runtime exception seems to be awful.

try/catch is just fine if you catch exceptions at the right level. The main mistake I see people make (which initially made me write about it) is catching exceptions too far up in the call stack from the place they've been thrown - basically, too "late". In such cases people try to guess what happened by examining exception type and/or pattern-matching a message. That was indeed horrible when I saw NPE was interpreted as "item not found in the database" (it actually was just random null somewhere in between).

Maybe if we're talking about specifing implementation, should I use something like spring's @ExceptionHandler?

You should use that kind of things as well, but only for API/domain-level exceptions.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.