MountebankBankClient.java
Bridget/payment-gateway-microservices/services/bank-adapter-service/src/main/java/com/checkout/paymentgw/bank/client/MountebankBankClient.java
package com.checkout.paymentgw.bank.client;
import com.checkout.paymentgw.bank.api.dto.AuthorisationCommand;
import com.checkout.paymentgw.bank.api.dto.AuthorisationResult;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.retry.annotation.Retry;
import io.github.resilience4j.timelimiter.annotation.TimeLimiter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestClient;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
/**
* Implementation that talks to the Mountebank bank simulator from the original
* coding challenge. Same wire format; we wrap it with resilience patterns and
* convert errors to a stable internal taxonomy.
*/
@Component
public class MountebankBankClient implements BankClient {
private static final Logger LOG = LoggerFactory.getLogger(MountebankBankClient.class);
private static final DateTimeFormatter EXPIRY = DateTimeFormatter.ofPattern("MM/yyyy");
private final RestClient http;
public MountebankBankClient(RestClient.Builder builder,
@Value("${bank.simulator.base-url}") String baseUrl) {
this.http = builder.baseUrl(baseUrl).build();
}
@Override
@CircuitBreaker(name = "bank")
@Retry(name = "bank")
@TimeLimiter(name = "bank")
public AuthorisationResult authorise(AuthorisationCommand cmd) {
BankRequest body = new BankRequest(
cmd.cardNumber(),
YearMonth.of(cmd.expiryYear(), cmd.expiryMonth()).format(EXPIRY),
cmd.currency(),
cmd.amount(),
cmd.cvv()
);
try {
BankResponse response = http.post()
.uri("/payments")
.body(body)
.retrieve()
.body(BankResponse.class);
if (response == null) {
LOG.warn("empty bank response");
return new AuthorisationResult(false, null, "EMPTY_BANK_RESPONSE");
}
return new AuthorisationResult(
response.authorized(),
response.authorizationCode(),
response.errorMessage()
);
} catch (HttpServerErrorException.ServiceUnavailable e) {
throw new BankUnavailableException("Bank service unavailable", e);
} catch (HttpServerErrorException e) {
throw new BankServerException("Bank server error: " + e.getStatusCode(), e);
} catch (HttpClientErrorException e) {
// Bank rejecting the request shape is a contract failure on our side.
throw new BankClientException("Bank rejected request: " + e.getStatusCode(), e);
}
}
record BankRequest(
@JsonProperty("card_number") String cardNumber,
@JsonProperty("expiry_date") String expiryDate,
String currency,
Integer amount,
String cvv) {}
record BankResponse(
boolean authorized,
@JsonProperty("authorization_code") String authorizationCode,
@JsonProperty("error_message") String errorMessage) {}
public static class BankUnavailableException extends RuntimeException {
public BankUnavailableException(String m, Throwable c) { super(m, c); }
}
public static class BankServerException extends RuntimeException {
public BankServerException(String m, Throwable c) { super(m, c); }
}
public static class BankClientException extends RuntimeException {
public BankClientException(String m, Throwable c) { super(m, c); }
}
}
Artículos relacionados
PaymentGatewayApplication.java
PaymentGatewayApplication.java — java source code from the Bridget learning materials (Bridget/payment-gateway-challenge-java/src/main/java/com/checkout/payment/gateway/PaymentGatewayApplication.java).
Leer artículo →ApplicationConfiguration.java
ApplicationConfiguration.java — java source code from the Bridget learning materials (Bridget/payment-gateway-challenge-java/src/main/java/com/checkout/payment/gateway/configuration/ApplicationConfiguration.java).
Leer artículo →RequestResponseLogger.java
RequestResponseLogger.java — java source code from the Bridget learning materials (Bridget/payment-gateway-challenge-java/src/main/java/com/checkout/payment/gateway/configuration/RequestResponseLogger.java).
Leer artículo →PaymentGatewayController.java
PaymentGatewayController.java — java source code from the Bridget learning materials (Bridget/payment-gateway-challenge-java/src/main/java/com/checkout/payment/gateway/controller/PaymentGatewayController.java).
Leer artículo →PaymentStatus.java
PaymentStatus.java — java source code from the Bridget learning materials (Bridget/payment-gateway-challenge-java/src/main/java/com/checkout/payment/gateway/enums/PaymentStatus.java).
Leer artículo →BankErrorException.java
BankErrorException.java — java source code from the Bridget learning materials (Bridget/payment-gateway-challenge-java/src/main/java/com/checkout/payment/gateway/exception/BankErrorException.java).
Leer artículo →