Creating New API Endpoints
Adding a New REST Endpoint
When you need to add new functionality that doesn’t fit the standard CRUD operations, you can extend your controller with custom endpoints.
Custom Endpoint Example
@RestController
@RequestMapping("/v1/custom")
public class CustomController extends AbstractRestController<CustomEntity> {
private final CustomService customService;
public CustomController(CustomService customService) {
super(customService);
this.customService = customService;
}
@GetMapping("/search")
@Operation(summary = "Search custom entities")
public Page<CustomRepresentation> searchEntities(
@RequestParam String query,
Pageable pageable) {
return customService.searchByQuery(query, pageable);
}
@PostMapping("/{id}/process")
@Operation(summary = "Process a custom entity")
public ResponseEntity<CustomRepresentation> processEntity(
@PathVariable Long id,
@RequestBody ProcessRequest request) {
CustomEntity processed = customService.process(id, request);
return ResponseEntity.ok(assembler.toRepresentation(processed));
}
@GetMapping("/statistics")
@Operation(summary = "Get statistics")
public ResponseEntity<StatisticsDto> getStatistics() {
return ResponseEntity.ok(customService.calculateStatistics());
}
}Request and Response Types
Request DTOs
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProcessRequest {
@NotNull
private String action;
@Valid
private Map<String, Object> parameters;
@Future
private LocalDateTime scheduledFor;
}Response DTOs
@Data
@Builder
public class StatisticsDto {
private Long totalCount;
private Map<String, Long> countByStatus;
private LocalDateTime lastUpdated;
}Path Variables and Request Parameters
Path Variables
@GetMapping("/{id}")
public ResponseEntity<CustomRepresentation> getById(@PathVariable Long id) {
return ResponseEntity.ok(service.findById(id));
}Request Parameters
@GetMapping
public Page<CustomRepresentation> findAll(
@RequestParam(required = false) String filter,
@RequestParam(defaultValue = "name") String sortBy,
Pageable pageable) {
return service.findAllWithFilter(filter, sortBy, pageable);
}Validation
Use Bean Validation annotations to validate input:
@PostMapping
public ResponseEntity<CustomRepresentation> create(
@Valid @RequestBody CustomDto dto) {
CustomEntity entity = service.create(dto);
return ResponseEntity
.status(HttpStatus.CREATED)
.body(assembler.toRepresentation(entity));
}Error Handling
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(EntityNotFoundException e) {
ErrorResponse error = ErrorResponse.builder()
.message(e.getMessage())
.timestamp(LocalDateTime.now())
.status(HttpStatus.NOT_FOUND.value())
.build();
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}Security
Add security annotations to protect endpoints:
@PreAuthorize("hasRole('ADMIN')")
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
service.delete(id);
return ResponseEntity.noContent().build();
}OpenAPI Documentation
Document your endpoints using OpenAPI annotations:
@Operation(
summary = "Create a new entity",
description = "Creates a new entity with the provided data"
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "201",
description = "Entity created successfully",
content = @Content(schema = @Schema(implementation = CustomRepresentation.class))
),
@ApiResponse(
responseCode = "400",
description = "Invalid input"
)
})
@PostMapping
public ResponseEntity<CustomRepresentation> create(@RequestBody CustomDto dto) {
// Implementation
}