S SmartDocs
Serie: Bridget java 96 righe · Aggiornato 2026-05-08

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); }
    }
}

Articoli correlati

Bridget java Aggiornato 2026-03-30

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).

Leggi l'articolo →
Bridget java Aggiornato 2026-03-20

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).

Leggi l'articolo →
Bridget java Aggiornato 2026-03-30

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).

Leggi l'articolo →
Bridget java Aggiornato 2026-04-14

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).

Leggi l'articolo →
Bridget java Aggiornato 2026-03-20

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).

Leggi l'articolo →
Bridget java Aggiornato 2026-03-29

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).

Leggi l'articolo →