Skip to content

Commit 5f02b0b

Browse files
committed
feat: add error handling and response mapping for module configuration validation
1 parent 2ab8afe commit 5f02b0b

File tree

8 files changed

+111
-31
lines changed

8 files changed

+111
-31
lines changed

backend/src/main/java/com/park/utmstack/config/RestTemplateConfiguration.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.apache.http.conn.ssl.TrustStrategy;
66
import org.apache.http.impl.client.CloseableHttpClient;
77
import org.apache.http.impl.client.HttpClients;
8+
import org.jetbrains.annotations.NotNull;
89
import org.slf4j.Logger;
910
import org.slf4j.LoggerFactory;
1011
import org.springframework.context.annotation.Bean;
@@ -44,7 +45,7 @@ public RestTemplate rawRestTemplate() {
4445
RestTemplate rest = new RestTemplate();
4546
rest.setErrorHandler(new DefaultResponseErrorHandler() {
4647
@Override
47-
public boolean hasError(ClientHttpResponse response) {
48+
public boolean hasError(@NotNull ClientHttpResponse response) {
4849
return false;
4950
}
5051
});

backend/src/main/java/com/park/utmstack/domain/application_modules/validators/impl/ModuleConfigurationValidator.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ public boolean isValid(GroupConfigurationDTO dto, ConstraintValidatorContext con
3232
return module.validateConfiguration(utmModule, dto.getKeys());
3333
} catch (Exception e) {
3434
context.disableDefaultConstraintViolation();
35-
context.buildConstraintViolationWithTemplate("Invalid configuration for selected module.")
36-
.addPropertyNode("keys")
35+
context.buildConstraintViolationWithTemplate(e.getMessage())
3736
.addConstraintViolation();
3837
return false;
3938
}
Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package com.park.utmstack.service.application_modules.connectors;
22

3+
import com.fasterxml.jackson.databind.JsonNode;
34
import com.park.utmstack.config.Constants;
5+
import com.park.utmstack.service.dto.application_modules.ModuleConfigValidationErrorMapper;
6+
import com.park.utmstack.service.dto.application_modules.ModuleConfigValidationErrorResponse;
47
import com.park.utmstack.service.dto.application_modules.UtmModuleGroupConfWrapperDTO;
58
import com.park.utmstack.service.web_clients.rest_template.RestTemplateService;
69
import com.park.utmstack.util.exceptions.ApiException;
@@ -24,44 +27,61 @@ public class ModuleConfigurationValidationService {
2427

2528
public boolean validateModuleConfiguration(String module, UtmModuleGroupConfWrapperDTO configurations) {
2629
final String ctx = CLASSNAME + ".ModuleConfigurationValidationService";
30+
2731
HttpHeaders headers = new HttpHeaders();
2832
headers.add("Content-Type", "application/json");
2933
headers.add("Accept", "*/*");
3034
headers.set(Constants.EVENT_PROCESSOR_INTERNAL_KEY_HEADER, System.getenv(Constants.ENV_INTERNAL_KEY));
3135

32-
String baseUrl = "http://" + System.getenv(Constants.ENV_EVENT_PROCESSOR_HOST) + ":" + System.getenv(Constants.ENV_EVENT_PROCESSOR_PORT);
36+
String baseUrl = "http://" + System.getenv(Constants.ENV_EVENT_PROCESSOR_HOST) + ":" + System.getenv(Constants.ENV_EVENT_PROCESSOR_PORT);
3337
String endPoint = baseUrl + "/api/v1/modules-config/validate?nameShort=" + module;
34-
try{
35-
ResponseEntity<String> response = restTemplateService.post(
36-
endPoint,
37-
configurations,
38-
String.class,
39-
headers
40-
);
41-
42-
if (!response.getStatusCode().is2xxSuccessful()) {
43-
List<String> errors = response.getHeaders().get("X-UtmStack-error");
44-
String errorMessage = (errors != null && !errors.isEmpty())
45-
? String.join(", ", errors)
46-
: "Unknown error occurred during module configuration validation.";
47-
48-
log.error("{}: Module configuration validation failed for module: {} with status: {}. Cause: {}",
49-
ctx, module, response.getStatusCode(), errorMessage);
50-
throw new ApiException(
51-
String.format("Module configuration validation failed for module: %s. Cause: %s", module, errorMessage),
52-
response.getStatusCode()
53-
);
38+
39+
ResponseEntity<JsonNode> response = restTemplateService.postRaw(
40+
endPoint,
41+
configurations,
42+
JsonNode.class,
43+
headers
44+
);
45+
46+
JsonNode body = response.getBody();
47+
48+
if (response.getStatusCode().is2xxSuccessful() && body != null && body.has("status")) {
49+
return true;
50+
}
51+
52+
if (body != null && body.has("error")) {
53+
String errorText = body.get("error").asText();
54+
55+
if (errorText.contains("{\"meta\"")) {
56+
ModuleConfigValidationErrorResponse structured = ModuleConfigValidationErrorMapper.parse(errorText);
57+
58+
if (structured != null) {
59+
String traceId = structured.getMeta().getTraceId();
60+
String message = structured.getErrors().get(0).getMessage();
61+
62+
log.error("{}: External provider validation failed for module {}. TraceId: {}. Message: {}",
63+
ctx, module, traceId, message);
64+
65+
throw new ApiException(
66+
"External provider validation failed: " + message + " (traceId=" + traceId + ")",
67+
HttpStatus.UNAUTHORIZED
68+
);
69+
}
5470
}
5571

56-
return true;
72+
log.error("{}: Module configuration validation failed for module {}. Cause: {}",
73+
ctx, module, errorText);
5774

58-
} catch (ApiException e) {
59-
throw e;
60-
} catch (Exception e) {
61-
log.error("{}: An error occurred while validating module configuration for module: {}. Cause: {}",
62-
ctx, module, e.getMessage(), e);
63-
throw new ApiException("An error occurred while validating module configuration", HttpStatus.INTERNAL_SERVER_ERROR);
75+
throw new ApiException(errorText, HttpStatus.BAD_REQUEST);
6476
}
77+
78+
log.error("{}: Unexpected response validating module {}.", ctx, module);
79+
throw new ApiException(
80+
String.format("%s: Unexpected response validating module %s.", ctx, module),
81+
HttpStatus.INTERNAL_SERVER_ERROR
82+
);
6583
}
84+
85+
6686
}
6787

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.park.utmstack.service.dto.application_modules;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class CSError {
7+
private int code;
8+
private String message;
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.park.utmstack.service.dto.application_modules;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import lombok.Data;
5+
6+
@Data
7+
public class Meta {
8+
@JsonProperty("trace_id") private String traceId;
9+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.park.utmstack.service.dto.application_modules;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
5+
public class ModuleConfigValidationErrorMapper {
6+
7+
private static final ObjectMapper mapper = new ObjectMapper();
8+
9+
public static ModuleConfigValidationErrorResponse parse(String errorText) {
10+
try {
11+
ObjectMapper mapper = new ObjectMapper();
12+
13+
int start = errorText.indexOf("{\"meta\"");
14+
if (start == -1) return null;
15+
16+
String innerJson = errorText.substring(start);
17+
18+
return mapper.readValue(innerJson, ModuleConfigValidationErrorResponse.class);
19+
20+
} catch (Exception e) {
21+
return null;
22+
}
23+
}
24+
25+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.park.utmstack.service.dto.application_modules;
2+
3+
import lombok.Data;
4+
5+
import java.util.List;
6+
7+
@Data
8+
public class ModuleConfigValidationErrorResponse {
9+
private Meta meta;
10+
private List<CSError> errors;
11+
}
12+
13+

backend/src/main/java/com/park/utmstack/service/web_clients/rest_template/RestTemplateService.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ public <T> ResponseEntity<T> getRaw(String url, Class<T> type) {
5454
return rawRestTemplate.exchange(url, HttpMethod.GET, requestEntity, type);
5555
}
5656

57+
public <T, U> ResponseEntity<U> postRaw(String url, T body, Class<U> type, HttpHeaders headers) {
58+
HttpEntity<T> requestEntity = new HttpEntity<>(body, headers);
59+
return rawRestTemplate.exchange(url, HttpMethod.POST, requestEntity, type);
60+
}
5761

5862
public <T> ResponseEntity<T> get(String url, Class<T> type, HttpHeaders headers) throws Exception {
5963
final String ctx = CLASSNAME + ".get";

0 commit comments

Comments
 (0)