b9a2fb0806aaff4b984fb5c2d942e80cc98eb6a6
[demos/kafka/demos-kafka-payment-system-transfer] / src / main / java / de / juplo / kafka / payment / transfer / adapter / TransferController.java
1 package de.juplo.kafka.payment.transfer.adapter;
2
3
4 import de.juplo.kafka.payment.transfer.domain.Transfer;
5 import de.juplo.kafka.payment.transfer.ports.GetTransferUseCase;
6 import de.juplo.kafka.payment.transfer.ports.MessagingService;
7 import lombok.RequiredArgsConstructor;
8 import lombok.extern.slf4j.Slf4j;
9 import org.springframework.http.HttpStatus;
10 import org.springframework.http.MediaType;
11 import org.springframework.http.ResponseEntity;
12 import org.springframework.validation.FieldError;
13 import org.springframework.web.bind.MethodArgumentNotValidException;
14 import org.springframework.web.bind.annotation.*;
15 import org.springframework.web.context.request.async.DeferredResult;
16
17 import javax.servlet.http.HttpServletRequest;
18 import javax.validation.Valid;
19 import java.net.URI;
20 import java.util.Date;
21 import java.util.HashMap;
22 import java.util.Map;
23 import java.util.Optional;
24 import java.util.concurrent.CompletableFuture;
25
26
27 @RestController
28 @RequiredArgsConstructor
29 @Slf4j
30  public class TransferController
31 {
32   public final static String PATH = "/transfers";
33
34   private final GetTransferUseCase getTransferUseCase;
35   private final MessagingService messagingService;
36
37
38   @PostMapping(
39       path = PATH,
40       consumes = MediaType.APPLICATION_JSON_VALUE,
41       produces = MediaType.APPLICATION_JSON_VALUE)
42   public DeferredResult<ResponseEntity<?>> transfer(
43       HttpServletRequest request,
44       @Valid @RequestBody TransferDTO transferDTO)
45   {
46     DeferredResult<ResponseEntity<?>> result = new DeferredResult<>();
47
48     getTransferUseCase
49         .get(transferDTO.getId())
50         .map(transfer ->
51             CompletableFuture.completedFuture(
52                 ResponseEntity
53                     .ok()
54                     .location(location(transferDTO))
55                     .build()))
56         .or(() ->
57             Optional.of(
58                 messagingService
59                     .send(
60                         Transfer
61                             .builder()
62                             .id(transferDTO.getId())
63                             .payer(transferDTO.getPayer())
64                             .payee(transferDTO.getPayee())
65                             .amount(transferDTO.getAmount())
66                             .build())
67                     .thenApply($ ->
68                         ResponseEntity
69                             .created(location(transferDTO))
70                             .build())))
71         .get()
72         .thenAccept(responseEntity -> result.setResult(responseEntity))
73         .exceptionally(e ->
74         {
75           result.setErrorResult(e);
76           return null;
77         });
78
79     return result;
80   }
81
82   private URI location(TransferDTO transferDTO)
83   {
84     return URI.create(PATH + "/" + transferDTO.getId());
85   }
86
87   @GetMapping(
88       path = PATH + "/{id}",
89       produces = MediaType.APPLICATION_JSON_VALUE)
90   public ResponseEntity<TransferDTO> get(@PathVariable Long id)
91   {
92     return
93         getTransferUseCase
94             .get(id)
95             .map(transfer -> ResponseEntity.ok(TransferDTO.of(transfer)))
96             .orElse(ResponseEntity.notFound().build());
97   }
98
99   @ResponseStatus(HttpStatus.BAD_REQUEST)
100   @ExceptionHandler(MethodArgumentNotValidException.class)
101   public Map<String, Object> handleValidationExceptions(
102       HttpServletRequest request,
103       MethodArgumentNotValidException e)
104   {
105     Map<String, Object> errorAttributes = new HashMap<>();
106     errorAttributes.put("status", HttpStatus.BAD_REQUEST.value());
107     errorAttributes.put("error", HttpStatus.BAD_REQUEST.getReasonPhrase());
108     errorAttributes.put("path", request.getRequestURI());
109     errorAttributes.put("method", request.getMethod());
110     errorAttributes.put("timestamp", new Date());
111     Map<String, String> errors = new HashMap<>();
112     e.getBindingResult().getAllErrors().forEach((error) -> {
113       String fieldName = ((FieldError) error).getField();
114       String errorMessage = error.getDefaultMessage();
115       errors.put(fieldName, errorMessage);
116     });
117     errorAttributes.put("errors", errors);
118     errorAttributes.put("message", "Validation failed: Invalid message format, error count: " + errors.size());
119     return errorAttributes;
120   }
121 }