Skip to content

Commit

Permalink
[EWT-192] Add support for a limited set of custom HTTP headers (#204)
Browse files Browse the repository at this point in the history
  • Loading branch information
dili91 authored May 24, 2023
1 parent 3733b7f commit ba576b5
Show file tree
Hide file tree
Showing 51 changed files with 1,156 additions and 221 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {
// to publish packages
id 'maven-publish'
// code linting
id "com.diffplug.spotless" version "6.18.0"
id "com.diffplug.spotless" version "6.19.0"
// test coverage
id 'jacoco'
id 'com.github.kt3k.coveralls' version '2.12.2'
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Main properties
group=com.truelayer
archivesBaseName=truelayer-java
version=7.0.0
version=8.0.0

# Artifacts properties
sonatype_repository_url=https://s01.oss.sonatype.org/service/local/
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/truelayer/java/ITrueLayerClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
import com.truelayer.java.http.entities.ApiResponse;
import com.truelayer.java.mandates.IMandatesHandler;
import com.truelayer.java.merchantaccounts.IMerchantAccountsHandler;
import com.truelayer.java.payments.IPaymentsApi;
import com.truelayer.java.payments.IPaymentsHandler;
import com.truelayer.java.paymentsproviders.IPaymentsProvidersHandler;
import com.truelayer.java.payouts.IPayoutsApi;
import com.truelayer.java.payouts.IPayoutsHandler;
import java.util.concurrent.CompletableFuture;

/**
Expand All @@ -27,7 +27,7 @@ public interface ITrueLayerClient {
* Entrypoint for payments endpoints.
* @return a utility to interact with payments endpoints.
*/
IPaymentsApi payments();
IPaymentsHandler payments();

/**
* Entrypoint for payments providers endpoints.
Expand All @@ -51,7 +51,7 @@ public interface ITrueLayerClient {
* Entrypoint for payouts endpoints.
* @return a utility to interact with payouts endpoints.
*/
IPayoutsApi payouts();
IPayoutsHandler payouts();

/**
* Entrypoint for Hosted Payment Page related services.
Expand Down
27 changes: 16 additions & 11 deletions src/main/java/com/truelayer/java/TrueLayerClient.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package com.truelayer.java;

import com.truelayer.java.auth.IAuthenticationHandler;
import com.truelayer.java.commonapi.ICommonApi;
import com.truelayer.java.commonapi.ICommonHandler;
import com.truelayer.java.commonapi.entities.SubmitPaymentReturnParametersRequest;
import com.truelayer.java.commonapi.entities.SubmitPaymentReturnParametersResponse;
import com.truelayer.java.hpp.IHostedPaymentPageLinkBuilder;
import com.truelayer.java.http.entities.ApiResponse;
import com.truelayer.java.mandates.IMandatesHandler;
import com.truelayer.java.merchantaccounts.IMerchantAccountsHandler;
import com.truelayer.java.payments.IPaymentsApi;
import com.truelayer.java.payments.IPaymentsHandler;
import com.truelayer.java.paymentsproviders.IPaymentsProvidersHandler;
import com.truelayer.java.payouts.IPayoutsApi;
import com.truelayer.java.payouts.IPayoutsHandler;
import java.util.concurrent.CompletableFuture;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
Expand All @@ -23,22 +23,24 @@
*/
@AllArgsConstructor
public class TrueLayerClient implements ITrueLayerClient {

private IAuthenticationHandler authenticationHandler;
private IPaymentsApi paymentsHandler;
private IPaymentsHandler paymentsHandler;
private IPaymentsProvidersHandler paymentsProvidersHandler;
private IMerchantAccountsHandler merchantAccountsHandler;
private IMandatesHandler mandatesHandler;
private IPayoutsApi payoutsHandler;
private IPayoutsHandler payoutsHandler;
private ICommonHandler commonHandler;

private IHostedPaymentPageLinkBuilder hostedPaymentPageLinkBuilder;
private ICommonApi commonApi;

public TrueLayerClient(
IAuthenticationHandler authenticationHandler,
IHostedPaymentPageLinkBuilder hostedPaymentPageLinkBuilder,
ICommonApi commonApi) {
ICommonHandler commonHandler) {
this.authenticationHandler = authenticationHandler;
this.hostedPaymentPageLinkBuilder = hostedPaymentPageLinkBuilder;
this.commonApi = commonApi;
this.commonHandler = commonHandler;
}

/**
Expand All @@ -61,7 +63,7 @@ public IAuthenticationHandler auth() {
* {@inheritDoc}
*/
@Override
public IPaymentsApi payments() {
public IPaymentsHandler payments() {
if (ObjectUtils.isEmpty(paymentsHandler)) {
throw buildInitializationException("payments");
}
Expand All @@ -73,6 +75,9 @@ public IPaymentsApi payments() {
*/
@Override
public IPaymentsProvidersHandler paymentsProviders() {
if (ObjectUtils.isEmpty(paymentsProvidersHandler)) {
throw buildInitializationException("payment providers");
}
return paymentsProvidersHandler;
}

Expand All @@ -96,7 +101,7 @@ public IMandatesHandler mandates() {
}

@Override
public IPayoutsApi payouts() {
public IPayoutsHandler payouts() {
if (ObjectUtils.isEmpty(payoutsHandler)) {
throw buildInitializationException("payouts");
}
Expand All @@ -117,7 +122,7 @@ public IHostedPaymentPageLinkBuilder hpp() {
@Override
public CompletableFuture<ApiResponse<SubmitPaymentReturnParametersResponse>> submitPaymentReturnParameters(
SubmitPaymentReturnParametersRequest request) {
return commonApi.submitPaymentReturnParameters(request);
return commonHandler.submitPaymentReturnParameters(request);
}

private TrueLayerException buildInitializationException(String handlerName) {
Expand Down
21 changes: 15 additions & 6 deletions src/main/java/com/truelayer/java/TrueLayerClientBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

import com.truelayer.java.auth.AuthenticationHandler;
import com.truelayer.java.auth.IAuthenticationHandler;
import com.truelayer.java.commonapi.CommonHandler;
import com.truelayer.java.commonapi.ICommonApi;
import com.truelayer.java.commonapi.ICommonHandler;
import com.truelayer.java.hpp.HostedPaymentPageLinkBuilder;
import com.truelayer.java.hpp.IHostedPaymentPageLinkBuilder;
import com.truelayer.java.http.OkHttpClientFactory;
Expand All @@ -19,9 +21,13 @@
import com.truelayer.java.merchantaccounts.IMerchantAccountsHandler;
import com.truelayer.java.merchantaccounts.MerchantAccountsHandler;
import com.truelayer.java.payments.IPaymentsApi;
import com.truelayer.java.payments.IPaymentsHandler;
import com.truelayer.java.payments.PaymentsHandler;
import com.truelayer.java.paymentsproviders.IPaymentsProvidersHandler;
import com.truelayer.java.paymentsproviders.PaymentsProvidersHandler;
import com.truelayer.java.payouts.IPayoutsApi;
import com.truelayer.java.payouts.IPayoutsHandler;
import com.truelayer.java.payouts.PayoutsHandler;
import com.truelayer.java.versioninfo.LibraryInfoLoader;
import java.time.Clock;
import java.time.Duration;
Expand Down Expand Up @@ -207,20 +213,22 @@ public TrueLayerClient build() {

// We're reusing a client with only User agent and Idempotency key interceptors and give it our base payment
// endpoint
ICommonApi commonApiHandler = RetrofitFactory.build(authHttpClient, environment.getPaymentsApiUri())
ICommonApi commonApi = RetrofitFactory.build(authHttpClient, environment.getPaymentsApiUri())
.create(ICommonApi.class);
ICommonHandler commonHandler = new CommonHandler(commonApi);

// As per our RFC, if signing options is not configured we create a client which is able to interact
// with the Authentication API only
if (isEmpty(signingOptions)) {
return new TrueLayerClient(authenticationHandler, hppLinkBuilder, commonApiHandler);
return new TrueLayerClient(authenticationHandler, hppLinkBuilder, commonHandler);
}

OkHttpClient paymentsHttpClient = httpClientFactory.buildPaymentsApiClient(
authHttpClient, authenticationHandler, signingOptions, credentialsCache);

IPaymentsApi paymentsHandler = RetrofitFactory.build(paymentsHttpClient, environment.getPaymentsApiUri())
IPaymentsApi paymentsApi = RetrofitFactory.build(paymentsHttpClient, environment.getPaymentsApiUri())
.create(IPaymentsApi.class);
IPaymentsHandler paymentsHandler = new PaymentsHandler(paymentsApi);

IPaymentsProvidersHandler paymentsProvidersHandler = PaymentsProvidersHandler.New()
.clientCredentials(clientCredentials)
Expand All @@ -236,8 +244,9 @@ public TrueLayerClient build() {
.create(IMandatesApi.class);
IMandatesHandler mandatesHandler = new MandatesHandler(mandatesApi);

IPayoutsApi payoutsHandler = RetrofitFactory.build(paymentsHttpClient, environment.getPaymentsApiUri())
IPayoutsApi payoutsApi = RetrofitFactory.build(paymentsHttpClient, environment.getPaymentsApiUri())
.create(IPayoutsApi.class);
IPayoutsHandler payoutsHandler = new PayoutsHandler(payoutsApi);

return new TrueLayerClient(
authenticationHandler,
Expand All @@ -246,7 +255,7 @@ public TrueLayerClient build() {
merchantAccountsHandler,
mandatesHandler,
payoutsHandler,
hppLinkBuilder,
commonApiHandler);
commonHandler,
hppLinkBuilder);
}
}
29 changes: 29 additions & 0 deletions src/main/java/com/truelayer/java/commonapi/CommonHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.truelayer.java.commonapi;

import static com.truelayer.java.http.mappers.HeadersMapper.toMap;
import static java.util.Collections.emptyMap;

import com.truelayer.java.commonapi.entities.SubmitPaymentReturnParametersRequest;
import com.truelayer.java.commonapi.entities.SubmitPaymentReturnParametersResponse;
import com.truelayer.java.http.entities.ApiResponse;
import com.truelayer.java.http.entities.Headers;
import java.util.concurrent.CompletableFuture;
import lombok.Value;

@Value
public class CommonHandler implements ICommonHandler {

ICommonApi commonApi;

@Override
public CompletableFuture<ApiResponse<SubmitPaymentReturnParametersResponse>> submitPaymentReturnParameters(
SubmitPaymentReturnParametersRequest request) {
return commonApi.submitPaymentReturnParameters(emptyMap(), request);
}

@Override
public CompletableFuture<ApiResponse<SubmitPaymentReturnParametersResponse>> submitPaymentReturnParameters(
Headers headers, SubmitPaymentReturnParametersRequest request) {
return commonApi.submitPaymentReturnParameters(toMap(headers), request);
}
}
5 changes: 4 additions & 1 deletion src/main/java/com/truelayer/java/commonapi/ICommonApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import com.truelayer.java.commonapi.entities.SubmitPaymentReturnParametersRequest;
import com.truelayer.java.commonapi.entities.SubmitPaymentReturnParametersResponse;
import com.truelayer.java.http.entities.ApiResponse;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import retrofit2.http.Body;
import retrofit2.http.HeaderMap;
import retrofit2.http.POST;

/**
Expand All @@ -16,11 +18,12 @@ public interface ICommonApi {

/**
* Submits payments return parameters.
* @param headers map representing custom HTTP headers to be sent
* @param request a submit payment return parameters payload
* @return the response of the <i>Submit payment returns parameters</i> operation
* @see <a href="https://docs.truelayer.com/reference/submit-payments-provider-return-parameters"><i>Submit payments return parameters</i> API reference</a>
*/
@POST("/payments-provider-return")
CompletableFuture<ApiResponse<SubmitPaymentReturnParametersResponse>> submitPaymentReturnParameters(
@Body SubmitPaymentReturnParametersRequest request);
@HeaderMap Map<String, String> headers, @Body SubmitPaymentReturnParametersRequest request);
}
16 changes: 16 additions & 0 deletions src/main/java/com/truelayer/java/commonapi/ICommonHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.truelayer.java.commonapi;

import com.truelayer.java.commonapi.entities.SubmitPaymentReturnParametersRequest;
import com.truelayer.java.commonapi.entities.SubmitPaymentReturnParametersResponse;
import com.truelayer.java.http.entities.ApiResponse;
import com.truelayer.java.http.entities.Headers;
import java.util.concurrent.CompletableFuture;

public interface ICommonHandler {

CompletableFuture<ApiResponse<SubmitPaymentReturnParametersResponse>> submitPaymentReturnParameters(
SubmitPaymentReturnParametersRequest request);

CompletableFuture<ApiResponse<SubmitPaymentReturnParametersResponse>> submitPaymentReturnParameters(
Headers headers, SubmitPaymentReturnParametersRequest request);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.truelayer.java.entities;

import lombok.Value;

@Value
public class EmptyRequestBody {}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@
import com.truelayer.java.http.auth.AccessTokenInvalidator;
import com.truelayer.java.http.auth.AccessTokenManager;
import com.truelayer.java.http.auth.cache.ICredentialsCache;
import com.truelayer.java.http.interceptors.AuthenticationInterceptor;
import com.truelayer.java.http.interceptors.IdempotencyKeyInterceptor;
import com.truelayer.java.http.interceptors.SignatureInterceptor;
import com.truelayer.java.http.interceptors.TrueLayerAgentInterceptor;
import com.truelayer.java.http.interceptors.*;
import com.truelayer.java.http.interceptors.logging.HttpLoggingInterceptor;
import com.truelayer.java.http.interceptors.logging.SensitiveHeaderGuard;
import com.truelayer.java.versioninfo.LibraryInfoLoader;
Expand Down Expand Up @@ -105,7 +102,7 @@ public OkHttpClient buildAuthApiClient(OkHttpClient baseHttpClient, ClientCreden

OkHttpClient.Builder clientBuilder = baseHttpClient.newBuilder();

clientBuilder.addInterceptor(new IdempotencyKeyInterceptor());
clientBuilder.addInterceptor(new IdempotencyKeyGeneratorInterceptor());

return clientBuilder.build();
}
Expand All @@ -120,7 +117,7 @@ public OkHttpClient buildPaymentsApiClient(
// as all the others are inherited
OkHttpClient.Builder paymentsHttpClientBuilder = authApiHttpClient.newBuilder();

paymentsHttpClientBuilder.addInterceptor(new SignatureInterceptor(signingOptions));
paymentsHttpClientBuilder.addInterceptor(new SignatureGeneratorInterceptor(signingOptions));

AccessTokenManager.AccessTokenManagerBuilder accessTokenManagerBuilder =
AccessTokenManager.builder().authenticationHandler(authenticationHandler);
Expand Down
18 changes: 0 additions & 18 deletions src/main/java/com/truelayer/java/http/entities/Header.java

This file was deleted.

21 changes: 21 additions & 0 deletions src/main/java/com/truelayer/java/http/entities/Headers.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.truelayer.java.http.entities;

import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

/**
* Class representing custom TL headers that we allow our users to set.
*/
@Builder
@Getter
@ToString
@EqualsAndHashCode
public class Headers {
private String idempotencyKey;

private String signature;

private String xForwardedFor;
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
package com.truelayer.java.http.interceptors;

import static org.apache.commons.lang3.ObjectUtils.isEmpty;

import com.truelayer.java.Constants;
import java.io.IOException;
import java.util.UUID;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

public class IdempotencyKeyInterceptor implements Interceptor {
public class IdempotencyKeyGeneratorInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();

if (!needsIdempotencyGeneration(request)) {
return chain.proceed(request);
}

Request newRequest = request.newBuilder()
.header(Constants.HeaderNames.IDEMPOTENCY_KEY, UUID.randomUUID().toString())
.build();

return chain.proceed(newRequest);
}

private boolean needsIdempotencyGeneration(Request request) {
return isEmpty(request.header(Constants.HeaderNames.IDEMPOTENCY_KEY));
}
}
Loading

0 comments on commit ba576b5

Please sign in to comment.