TIL #5: Representing Response Object in REST API

I was thinking what is the best way to represent response object in REST API. So, I started thinking about all the things response object should provide to work effectively. Below is the list of things I want my response object to have:

  1. A single object structure to handle both successful and error scenarios
  2. Ability to handle multiple types of objects
  3. Ability to easily figure out if request failed or succeeded
  4. Store the error code and error message

The code in this post uses Java as the language of choice. As I use Spring Boot to build REST APIs so Jackson is the default JSON serialisation library.

The code below shows the ApiResponse object that captures both the success and error payload.

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonValue;

public final class ApiResponse<T> {

    private ErrorResponse error;
    private T data;
    private Status status;

    private ApiResponse(Status status, ErrorResponse error) {
        this.error = error;
        this.status = status;
    }

    private ApiResponse(Status status, T data) {
        this.data = data;
        this.status = status;
    }

    @JsonCreator
    public static <T> ApiResponse<T> success(
            @JsonProperty("status") Status status,
            @JsonProperty("data") T data) {
        return new ApiResponse<>(status, data);
    }

    @JsonCreator
    public static <T> ApiResponse<T> error(
            @JsonProperty("status") Status status,
            @JsonProperty("error") ErrorResponse error) {
        return new ApiResponse<>(status, error);
    }

    public enum Status {
        SUCCESS("success"), ERROR("error");

        private final String status;

        Status(String status) {
            this.status = status;
        }

        @JsonValue
        public String getStatus() {
            return this.status;
        }
    }

    public ErrorResponse getError() {
        return this.error;
    }

    public T getData() {
        return this.data;
    }

    public Status getStatus() {
        return this.status;
    }
}

The key points in the class shown above are:

  1. Status enum will hold the status of the request. User can just look at this request to figure out whether request succeeded or failed.
  2. The class is generic so it can be used to store any type of object in the data.
  3. User can get more details about the error from the error object.

The ErrorResponse class is shown below.

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public final class ErrorResponse {
    public final String code;
    public final String message;

    @JsonCreator
    public ErrorResponse(
            @JsonProperty("code") String code,
            @JsonProperty("message") String message) {
        this.code = code;
        this.message = message;
    }
}

The ErrorResponse class has two fields code and message. The code can be HTTP code or any business specific code. The message variable gives details about the error.

I found the above response classes work great for the REST APIs that I recently built.

Example of successful response is shown below.

{
    "status": "success",
    "data": {
        "task": "Write a post",
        "taskStatus":"in_progress",
        "tags":["writing"]
    }
}

Example of failure response is show below.

{
    "status": "error",
    "error": {
        "code" "409",
         "message" : "User with username xyz already exists"
    }
}

One thing that you should ensure is that your JSON serialisation library exclude null values. For example, in case of error scenario you don’t want data field to be null. If you are using Spring Boot, you can instruct Jackson to exclude null fields by specifying a property shown below.

spring.jackson.default-property-inclusion=NON_NULL

If you are using Java 8 or Google’s Gauva and want to exclude Optional type as well then you should use NON_ABSENT value.

spring.jackson.default-property-inclusion=NON_ABSENT
Advertisements

Keeping Spring Boot Powered REST API Request and Response Objects Minimal

I am a big fan of Spring Boot. It is my preferred choice for building REST APIs in Java. It takes less than 5 minutes(given that you have Maven dependencies on your local machine) to get started with Spring Boot thanks to its auto configuration. In this blog, I will talk about a specific aspect of building REST API with Spring Boot. We will look at the request and response objects. The request object that you receive during the HTTP POST request and response object that you send in the response of HTTP GET request. I will discuss how you can keep these request and response objects to the bare minimum so that we can avoid writing and maintaining useless getters and setters.

Read More »

Day 4 — Let’s write Null free Java code

Every Java developer whether beginner, novice, or seasoned has in his/her lifetime experienced NullPointerException. This is a true fact that no Java developer can deny. We all have wasted or spent many hours trying to fix bugs caused by NullPointerException. According to NullPointerException JavaDoc, NullPointerException is thrown when an application attempts to use null in a case where an object is required.. This means if we invoke a method or try to access a property on null reference then our code will explode and NullPointerException is thrown. You can follow the 7 Days with Java 8 series at https://shekhargulati.com/7-days-with-java-8/Read More »