response wrapper service layer vs controller

32 views Asked by At

I am currently trying to create a REST API using Spring Boot.

I am using ResponseEntity to provide responses and additionally creating an object for consolidated responses.

The code currently looks like this

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpStatus;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class RestResponse<T> {
  private Integer status;
  private HttpStatus httpStatus;
  private String path;
  private String message;
  private T data;
}

If in the service layer

DeviceEntity resultCreate = deviceMapper.getDeviceByDeviceIndex(deviceEntity.getDeviceIndex());

Send the result to

return RestResponse.builder()
              .status(200)
              .httpStatus(HttpStatus.OK)
              .message("Success")
              .data("")
              .build();


return RestResponse.builder()
              .status(ase.statusCode())
              .httpStatus(HttpStatus.valueOf(ase.statusCode()))
              .message(ase.awsErrorDetails().errorCode())
              .data("")
              .build();

When we use a try catch to return a RestResponse and the controller puts it in a responseEntity and returns it to us, we can use the

Is this the right structure?

Isn't the wrapping supposed to be done at the controller layer?

If we need to modify it, how can we do it?

I am currently thinking that I need to create a RestResponse object in the controller layer.

1

There are 1 answers

0
Tian On

Here's a comprehensive response to your query, combining best practices and addressing your concerns:

Key Points:

  • Wrap responses in the controller layer: Maintain a clear separation of concerns by creating RestResponse objects within controllers.
  • Service layer focuses on business logic: Services should return raw data or domain objects, leaving response formatting to the controller.
  • Consider exception handling: Customize exception responses effectively for better error reporting.

Recommended Structure:

  1. Controller Layer:

    • Handle incoming requests.
    • Call appropriate service methods.
    • Create RestResponse objects based on service results and HTTP status codes.
    • Wrap RestResponse in ResponseEntity and return it.
    @RestController
    @RequestMapping("/api/devices")
    public class DeviceController {
        private final DeviceService deviceService;
    
        @GetMapping("/{index}")
        public ResponseEntity<RestResponse<DeviceEntity>> getDeviceByIndex(@PathVariable String index) {
            DeviceEntity device = deviceService.getDeviceByDeviceIndex(index);
            if (device == null) {
                return ResponseEntity.notFound().build();
            }
            return ResponseEntity.ok(
                RestResponse.<DeviceEntity>builder()
                    .status(200)
                    .httpStatus(HttpStatus.OK)
                    .message("Success")
                    .data(device)
                    .build()
            );
        }
    }
    
  2. Service Layer:

    • Encapsulate business logic.
    • Return raw data or domain objects.
    • Throw custom exceptions for specific errors.
    @Service
    public class DeviceService {
        private final DeviceMapper deviceMapper;
    
        public DeviceEntity getDeviceByDeviceIndex(String deviceIndex) {
            return deviceMapper.getDeviceByDeviceIndex(deviceIndex);
        }
    }
    

Exception Handling:

  • Define custom exception classes for specific API errors.
  • Use @ExceptionHandler in controllers to handle exceptions and construct appropriate RestResponse objects.

Additional Considerations:

  • Tailor RestResponse fields to your API's needs.
  • Explore libraries like Spring HATEOAS for rich hypermedia responses.

By following this structure, you'll create well-structured, adaptable, and user-friendly REST APIs with Spring Boot.