I'm not sure what the best design is for returning an object that can both return a result for successful REST calls, or failed REST calls.
I'm currently thinking of something like this (written in Java):
public class ResultDTO<T> {
public enum Status {
SUCCESS, FAILURE
}
private Status status;
private String message;
private T result;
}
So it can be used like:
return new ResultDTO<User>(Status.SUCCESS, "", new User("john doe")); // Correct usage of API
return new ResultDTO<User>(Status.FAILURE, "Invalid e-mail", null); // Incorrect usage of API
But I'm not quite sure about this design. Does anyone have any experience with designing Objects for REST API's and can recommend me something?
1 Answer 1
It's difficult to provide a definitive answer to this because REST is a "style" of building applications and because you don't provide enough context of how your application works to produce the results, but nevertheless I'll try to offer some advice.
It's good that you want to use a homogeneous way to present all your results, be them of a success or error status, but you should not represent both with the same class. Take this code for example:
new ResultDTO<User>(Status.SUCCESS, "", new User("john doe"));
new ResultDTO<User>(Status.FAILURE, "Invalid e-mail", null);
See anything wrong with it? The only useful information here is new User("john doe")
and "Invalid e-mail"
. The rest is noise. Having an empty string for the message in the successful case, and a null result in the error case are a giveaway that the results should be exclusive, something like:
new SuccesfulResult<User>(new User("john doe"));
new ErrorResult("Invalid e-mail");
Your code might turn into this to reflect the new semantic:
public abstract class AbstractResult {
public enum Status {
SUCCESS, FAILURE
}
private final Status status;
protected AbstractResult(Status status) {
this.status = status;
}
private final Status getStatus() {
return this.status;
}
}
public class SuccesfulResult<T> extends AbstractResult {
private T result;
public SuccesfulResult(T result) {
super(AbstractResult.Status.SUCCESS);
this.result = result;
}
// ...
}
public class ErrorResult extends AbstractResult {
private final String message;
public ErrorResult(String message) {
super(AbstractResult.Status.FAILURE);
this.message = message;
}
// ...
}
It's a lot more code to write, but you write it once. You will call it a lot more times in your application and it beats having to always type ""
and null
all over the place.
Now, about the comment on your question. Don't make this part of your domain. The T result
is part of your domain. The rest is just metadata that accompanies the result so that the client knows if it's a successful call or a failed one. Your application should work with T
(whatever that represents) and only add the result metadata when marshalling the response for the client. Frameworks can help you there, especially for the error handling. In your application code you might throw
an exception then let the framework catch it and transform it in a new ErrorResult(...)
based on a mapping you provide.
Above are my observations regarding the code you posted. For other information try searching for "good REST API design" and "best practices for handling errors in rest APIs". You'll find more information there that you might not have though of, and it might be more useful to you than any solution you receive on this post.
Error
should be an object of your API domain. It has enough meaning to be an object, which can be modelled beyond a simple message text or code. On the other hand, isResultDTO
the response model to a command-like REST API?