Building Generic Payloads with the Builder Pattern in Java
Tags: webdev, java, backend, payload
Published: 2023-10-30 16:07:16

Java Generics can be used to create reusable code for structured responses in web services. This makes the code easier to maintain and scale. Generics allows the Payload class to be flexible, reusable, and consistent for backend and client-side developers.

## Introduction
A well-structured response from a backend service provides clear information about the outcome of the request, any relevant data, any associated messages, and often metadata such as the timestamp.

## Structured responses from backend services

A well-structured response from a backend service:

- Provides clarity about the outcome (success or failure).
- Contains any relevant data related to the response.
- May provide any associated message with the response.
- Often includes metadata, like the timestamp.

## Using Generics to define a response
Consider the Payload<T> class provided. Here's a breakdown of how it's structured:

- **Message:** A description of the outcome of the request, such as "Request Successful" or "Item not found."
- **Status:** A numerical status code, such as 200 for OK or 404 for NOT FOUND.
- **Payload:** The actual data being sent in the response. This can be of any type, thanks to the use of Generics.
- **Timestamp:** The time at which the response was created.

_**In short:**_ The Payload<T> class provides a structured way to represent backend responses, with fields for the message, status, payload, and timestamp. 

## Using the Builder Pattern 

The builder pattern allows us to construct Payload objects in a more expressive way, as shown in the following example:

```java
Payload<String> successPayload = new Payload.Builder<String>()
                                    .message("Request successful")
                                    .status(PayloadStatus.SUCCESS)
                                    .payload("This is the response data")
                                    .build();

```
## Benefits
- Flexible: Payload can be of any type, thanks to Generics.
- Reusable: A single Payload class can be used for many different response types.
- Consistent: All responses have a consistent structure.

## Usage

```java
// Create a Payload with a String payload.
Payload<String> successPayload = new Payload.Builder<String>()
  .message("Request successful")
  .status(PayloadStatus.SUCCESS)
  .payload("This is the response data")
  .build();

// Create a Payload with a User object payload.
User user = new User("John", "Doe");
Payload<User> userPayload = new Payload.Builder<User>()
  .status(PayloadStatus.SUCCESS)
  .message("User found")
  .payload(user)
  .build();

// Create a Payload with a List of Items payload.
List<Item> items = Arrays.asList(new Item("Book"), new Item("Pen"));
Payload<List<Item>> itemsPayload = new Payload.Builder<List<Item>>()
  .status(PayloadStatus.SUCCESS)
  .message("Items fetched")
  .payload(items)
  .build();

// Create a Payload with an error message.
Payload<Void> errorPayload = new Payload.Builder<Void>()
  .status(PayloadStatus.ERROR)
  .message("Something went wrong!")
  .build();
```

## Payload Builder Pattern
The Payload Builder Pattern is a design pattern that allows you to create complex objects in a step-by-step manner. It is especially useful for creating objects with many optional parameters.
```java
@Getter
@ToString
public class Payload<T> {
    private final String message;
    private final int status;
    private final T payload;
    private final Date timestamp;

    private Payload(PayloadStatus status, String message, T payload) {
        this.status = status.getCode();
        this.message = message;
        this.payload = payload;
        this.timestamp = Date.from(Instant.now().atZone(ZoneId.of("UTC")).toInstant());
    }

    public static class Builder<T> {
        private String message;
        private PayloadStatus status;
        private T payload;

        public Builder<T> message(String message) {
            this.message = message;
            return this;
        }

        public Builder<T> status(PayloadStatus status) {
            this.status = status;
            return this;
        }

        public Builder<T> payload(T payload) {
            this.payload = payload;
            return this;
        }

        public Payload<T> build() {
            return new Payload<>(status, message, payload);
        }
    }
}
```

## Conclusion
The Payload class with builder pattern is a flexible, reusable, and consistent way to represent responses from a backend service. It is easy to use and can be applied to a variety of use cases.