Modify Request and Response through Interceptors at RestTemplate

Aditya Rewari
2 min readJul 25, 2021

--

Interceptors are generally used in Spring to intercept requests of either self created end point at Controller, OR, to intercept other(3rd party) api calls done by RestTemplate. This article covers the later case, where we apply interceptor to restTemplate for modifying the Request-Response being used in calling 3rd party apis.

This article, will be demonstrating the same by applying Encryption on request body, and decryption on response body.
Encryption-Decryption will be applied on the fly by Interceptor.

Had not been done through Interceptors, it would had been required to apply these modifications(encrypt-decrypt) on Req-Res objects, at every place where we would had to make REST calls requiring encryption.

The respective Interceptor will be applied on restTemplate, a spring implemented bean used to make REST calls.

Recollecting the whole picture, we will be using regular POJO as request-response objects.
The interceptor will be acting on these, performing action of modifications(encryption/decryption).
Thus taking away the responsibility from the developer, to perform this at every request

For demonstration purpose, Encryption-decryption had been used in a very naive manner.

Approach:

We will be using two Rest Template objects in the project.
a) One will be in plain format(normal spring bean object).
— To be used when required to make regular REST calls.
b) The other restTemplate spring bean will have interceptor applied onto it.
— To be used when encryption-decryption needs to be applied over the Request-Response objects

@Bean
@Primary
// This RestTemplate bean will be used for regular REST call
public RestTemplate getPlainRestTemplate() {
RestTemplate restTemplate =
new RestTemplate(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
return restTemplate;
}


@Bean("interceptedRestTemplate")
public RestTemplate getInterceptedRestTemplate() {
RestTemplate restTemplate =
new RestTemplate(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
interceptors.add(interceptor);
restTemplate.setInterceptors(interceptors);
return restTemplate;
}

1 . The interceptor will extract the request object and apply the required modification to it(encryption).
2. Then we execute the request. i.e, make the REST call
3. Upon receiving the request as ClientHttpResponse object, we will firstly perform the response modification(decrypt).
4. Therefore, we intend to convert the receivedResponse to decryptedResponse.
5. Now, create a new object of ClientHttpResponse. Copy decryptedResponse to its body and other fields like headers to be populated from receivedResponse object.
6. Return this new populated object of ClientHttpResponse as response.

@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
String reqBody = new String(body);
byte[] encryptedRequestBody = service.doEncryption(reqBody);
ClientHttpResponse response = execution.execute(request, encryptedRequestBody);
String responseBody = new String(response.getBody().readAllBytes());
byte[] decryptedResponseBodyBytes = service.doDecryption(responseBody);
String decryptedResponseBody = new String(decryptedResponseBodyBytes);

// prepare modified response
ClientHttpResponse decryptedRes = new ClientHttpResponse() {
@Override
public HttpHeaders getHeaders() {
return response.getHeaders();
}

@Override
public InputStream getBody() throws IOException {
// The expected modified response body to be populated here
return new ByteArrayInputStream(decryptedResponseBody.getBytes());
}

@Override
public HttpStatus getStatusCode() throws IOException {
return response.getStatusCode();
}

@Override
public int getRawStatusCode() throws IOException {
return response.getRawStatusCode();
}

@Override
public String getStatusText() throws IOException {
return response.getStatusText();
}

@Override
public void close() {

}
};
return decryptedRes;
}

--

--