Spring Cloud Gateway Pre and Post Filters

Reading Time: 4 minutes

Spring Cloud Gateway

Spring Cloud Gateway provides a flexible way of routing requests based on a number of criteria, as well as focuses on cross-cutting concerns such as security, resiliency, and monitoring. An API gateway allows you to implement the complexity separately from the client, moving that responsibility from user side to server side. All the client needs to know is how to talk to the gateway. It doesn’t matter whether the backend services run, go offline, or become unstable as long as the gateway knows how to handle these situations. Spring Cloud Gateway Pre and Post filters are can be used in incoming request and outgoing response filter.

Spring Cloud Gateway Architecture

  • Route: Route is the basic building block of the gateway. It consists of
    • ID
    • destination URI
    • Collection of predicates and a collection of filters
  • Route is matched if the aggregate’s predicate is true.
  • Predicate: It is similar to Java 8 Function Predicate. Using this functionality we can match HTTP request, such as headers , url, cookies or parameters.
  • Filter: These are instances of Spring Framework GatewayFilter. Using this we can modify the request or response as per the requirement.

Implement Student Microservice

Maven project will be like this

student-service-architecture

The pom.xml will be as follows-

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.7.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.javainuse</groupId>
	<artifactId>student-service</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>  
		    <groupId>com.googlecode.json-simple</groupId>  
		    <artifactId>json-simple</artifactId>  
		    <version>1.1</version>  
		</dependency>
	</dependencies>

</project>

Define the application.yml as follows

spring:
  application:
    name: student-service
server:
  port: 8081

Create the bootstrap class(StudentApplication) with the @SpringBootApplication annotation

package com.springmicroservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class StudentApplication {

	public static void main(String[] args) {
		SpringApplication.run(StudentApplication.class, args);
	}

}

Create a Controller class that exposes the GET REST service as follows

package com.springmicroservice.controller;

import org.json.simple.JSONObject;
import org.springframework.web.bind.annotation.*;

package com.springmicroservice.controller;

import org.json.simple.JSONObject;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/student")
public class StudentController {
	
	/**
     * Controller is used to invoke services and it's return json object as response.
     */

	@GetMapping("/records")
	public JSONObject test(@RequestHeader("student-request") String header) {
		JSONObject obj=new JSONObject();  
		  obj.put("subject_code","Math");   
		  obj.put("dept_name","CSE"); 
		  obj.put("name","Sumit");  
		  obj.put("id",new Integer(101));  
		  System.out.println("Student Service Invoked...");
		  System.out.println(header);
	return obj;
	}
}

Implement Subject Microservice

Maven project will be like this

subject-service-architecture

The pom.xml will be as follows-

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.7.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.javainuse</groupId>
	<artifactId>subject-service</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>  
		    <groupId>com.googlecode.json-simple</groupId>  
		    <artifactId>json-simple</artifactId>  
		    <version>1.1</version>  
		</dependency>
	</dependencies>

</project>

Define the application.properties as follows

spring:
application:
name: subject-service
server:
port: 8082

Create the bootstrap class(SubjectApplication) with the @SpringBootApplication annotation

package com.springmicroservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SubjectApplication {

	public static void main(String[] args) {
		SpringApplication.run(SubjectApplication.class, args);
	}

}

Create a Controller class that exposes the GET REST service as follows-

package com.springmicroservice.controller;

import org.json.simple.JSONObject;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/subject")
public class SubjectController {
	
	/**
     * Controller is used to invoke services and it's return json object as response.
     */
	
	@GetMapping("/records")
	public JSONObject test(@RequestHeader("subject-request") String header) {
		JSONObject obj=new JSONObject();   
		  obj.put("code","Math");   
		  obj.put("name","Mathematics");  
		  obj.put("subjectId",new Integer(101));  
		  System.out.println("Subject Service Invoked...");
		  System.out.println(header);
	return obj;
	}
}

Implement Pre and Post filters in Spring Cloud Gateway using java based config

spring-cloud-gateway-architecture

The pom.xml will be as follows

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.javainuse</groupId>
	<artifactId>cloud-gateway-service</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>gateway-service</name>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-gateway</artifactId>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/milestone</url>
		</repository>
	</repositories>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

Create the bootstrap class(APIGatewayApplication) with the @SpringBootApplication annotation

package com.springcloudgateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;

import reactor.core.publisher.Mono;

@SpringBootApplication
public class APIGatewayApplication {

	public static void main(String[] args) {
		SpringApplication.run(APIGatewayApplication.class, args);
	}
}

To make Custom filters we need to inherit AbstractGatewayFilterFactory class.

Specify the Custom Filter in the route in application.yml file

server:
  port: 8080

Create the SpringCloudConfig class with the @Configuration

package com.springcloudgateway.config;

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SpringCloudConfig {

        @Bean
	public RouteLocator gatewayRoutes(RouteLocatorBuilder builder) {
		return builder.routes()
		      .route(r -> r.path("/student/**")
		//Pre and Post Filters provided by Spring Cloud Gateway
.filters(f -> f.addRequestHeader("student-request", "student-request-header")
								.addResponseHeader("student-response", "student-response-header"))
						.uri("http://localhost:8081/")
			.id("studentModule"))

			.route(r -> r.path("/subject/**")
		//Pre and Post Filters provided by Spring Cloud Gateway
.filters(f -> f.addRequestHeader("subject-request", "subject-request-header")
								.addResponseHeader("subject-response", "subject-response-header"))
						      .uri("http://localhost:8082/")
			.id("subjectModule"))
			.build();
	}
}

Start the applications-

  • cloud-gateway-service-java-based
  • student-service
  • subject-service

Run the application.

Go to browser Right click ->inspect->Network then type localhost:8080/student/records in address bar.

student-service

In the below images we can see that the Pre filter has been applied to request header and post filter is applied for response header.

spring-cloud-gateway-request-filter

spring-cloud-gateway-response-filter

Go to browser Right click ->inspect->Network then type type localhost:8080/subject/records in address bar.

subject-service

In the below images we can see that pre filter is applied for request header and post filter is applied for response header.

spring-cloud-gateway-request-filter

subject-post-response-filter

Conclusion

In this blog, we have covered how to implement and configure pre and post Filters to Spring Cloud Gateway Service. Now you are ready to go to implement pre and post Filters to Spring Cloud gateway. For more, you can refer to the documentation: https://cloud.spring.io/spring-cloud-gateway/reference/html/

Written by 

Gaurav Dubey is a Java Developer at Knoldus Software LLP. He has done M.CA from Kurukshetra University and completed Bachelor's Degree in Computer Science from M. D. University. He is a tech enthusiast with good knowledge of Java. He is majorly focused in Java practice. On the personal front, he loves to cook and travel.