3

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
  • Maybe, Errorshould 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, is ResultDTO the response model to a command-like REST API?
    – Laiv
    Dec 2, 2016 at 7:40

1 Answer 1

3

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.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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