How to modify a REST service response without modifying existing code in Spring Boot?

I wanted to modify a REST service with a change in the response.

The service was already doing what it was intended to do . There was a requirement to change certain things related to the representation of the response.

I didn’t want to change the existing code and clutter it with this logic.

So I used an advice instead.

Spring Boot provides RestControllerAdvice to handle this logic.

Here are the steps to do it:

STEP 1:

Create a RestControllerAdvice class (annotate a class with @RestControllerAdvice ) and implement ResponseBodyAdvice interface:

package com.springboot.restadvice;

import java.util.Map;

import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@RestControllerAdvice
public class RestAdvice implements ResponseBodyAdvice<T> {

	

}

STEP 2:

Implement the method required by the interface ResponseBodyAdvice (Replace <T> parameter in the interface with the return type of the REST service ):

package com.springboot.restadvice;

import java.util.Map;

import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@RestControllerAdvice
public class RestAdvice implements ResponseBodyAdvice<Map<String, String>> {

	@Override
	public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {

		String className = returnType.getContainingClass().toString();

		String methodName = returnType.getMethod().toString();

		if (className.contains("RestController") && methodName.contains("modifyRestResponse")) {

			return true;
		}

		return false;
	}

	@Override
	public Map<String, String> beforeBodyWrite(Map<String, String> body, MethodParameter returnType,
			MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType,
			ServerHttpRequest request, ServerHttpResponse response) {

		body.put("message", "Hi! This is Response Body Advice modifying the response");

		return body;
	}

}

There are two methods:

  • supports()
  • beforeBodyWrite()

the supports() method decides when to apply the advice.

In the above case I have checked for the class and the method for which I want to apply this advice.

the beforeBodyWrite() method lets you to modify the response.

In the above case I have put a message on the response .

That is all the change we need to do!

Here is the REST controller for which I am applying this advice:

package com.springboot.restadvice;

import java.util.HashMap;
import java.util.Map;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

@org.springframework.web.bind.annotation.RestController
public class RestController {

	@PostMapping("/modifyRESTResponse")
	public Map<String, String> modifyRestResponse(@RequestBody Map<String,String> message) {

		Map<String, String> result = new HashMap<>();
		result.put("name", "Mr Spring Boot Advice");
		result.putAll(message);

		return result;

	}

}

As you see , the above rest service just returns the message posted by the user along with the name “Mr Spring Boot Advice”.

Here is the response what I got before applying the advice:

And below is the response after applying the advice:

The response has been modified by the advice!

I have not touched the existing controller class.

This provides loose coupling for the logic I added. Also the same advice can be applied to multiple REST services.

Here is the code :

https://github.com/vijaysrj/springboot-restadvice

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s