
What is an API? Why do we need it?
An API gateway is programming that sits in front of an API ( Application Programming Interface) and is the single-entry point for defined back-end APIs and microservices (which can be both internal and external). Sitting in front of APIs, the gateway acts as protection, administering security and scalability, and high availability. To put it simply, API Gateway takes all API requests from a customer, determines which services are demanded, and combines them into a unified, flawless experience for users.
Advantages of API Gateway
- It improves the security of the microservices as we limit the access of external calls to all our services.
- The cross-cutting concerns like authentication, monitoring/metrics, and resiliency will be needed to be implemented only in the API Gateway as all our calls will be routed through it.
- The client does not know about the internal architecture of our microservices system. The client will not be able to determine the location of the microservice instances.
- Simplifies client interaction as he will need to access only a single service for all the requirements.
Spring Cloud Gateway Architecture?
Spring Cloud Gateway is API Gateway implementation by the Spring Cloud team on top of the Spring reactive ecosystem. It consists of the following building blocks-
Route: Route the basic building block of the gateway. It consists of an ID, destination URI Collection of predicates, and a collection of filters. A route is matched if the aggregate predicate is true.
Predicate: This is similar to Java 8 Function Predicate. Using this functionality we can match HTTP requests, such as headers, URLs, cookies, or parameters.
Filter: These are instances of Spring Framework GatewayFilter. Using this we can modify the request or response as per the requirement.



Implementing Spring Cloud API Gateway
Using Spring Cloud Gateway we can create routes in either of the two ways –
- Use java based configuration to programmatically create routes
- Use property based configuration(i.e application.properties or application.yml) to create routes.
In this tutorial, we will be implementing Spring Cloud Gateway using property-based configurations.
We will be implementing Spring Cloud Gateway application which routes requests to two other microservices depending on the URL pattern.



Implement First MicroService:
The Maven project will be as follows-



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 https://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.6.2</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com</groupId>
<artifactId>first-microservice</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>first-microservice</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.0</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Define the application.yml as follows-
spring:
application:
name: first-microservice
server:
port: 8081
eureka:
instance:
hostname: localhost
Create a Controller class that exposes the GET REST service as follows-
package com.firstmicroservice.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/first")
public class FirstController {
@GetMapping("/message")
public String test() {
return "Hello this is my first microservice";
}
}
Create the main class with the @SpringBootApplication annotation.
package com.firstmicroservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class FirstMicroserviceApplication {
public static void main(String[] args) {
SpringApplication.run(FirstMicroserviceApplication.class, args);
}
}
Implement Second MicroService:
The Maven project will be as follows-



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 https://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.6.2</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com</groupId>
<artifactId>second-microservice</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>second-microservice</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.0</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Define the application.yml as follows-
spring:
application:
name: second-microservice
server:
port: 8082
eureka:
instance:
hostname: localhost
Create a Controller class that exposes the GET REST service as follows-
package com.secondmicroservice.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/second")
public class SecondController {
@GetMapping("/message")
public String test() {
return "Hello this is my Second Service";
}
}
Create the main class with the @SpringBootApplication annotation.
package com.secondmicroservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SecondMicroserviceApplication {
public static void main(String[] args) {
SpringApplication.run(SecondMicroserviceApplication.class, args);
}
}
Implement Eureka Server:
Eureka Server is an application that holds information Above all,client-service applications. Every Microservice will register into the Eureka server and the Eureka server knows all the client applications running on each port and IP address. Eureka Server is also known as Discovery Server.
Building a Eureka Server
Eureka Server comes with the bundle of Spring Cloud. Therefore, we need to develop the Eureka server and run it on the default port 8761.
The Maven project will be as follows-



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 https://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.6.2</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>eurekaserver</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eurekaserver</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.0</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka- server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Define the application.yml as follows-
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
server:
waitTimeInMsWhenSyncEmpty: 0
instance:
hostname: localhost
Create the main class with the @SpringBootApplication annotation.
package com.example.eurekaserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaserverApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaserverApplication.class, args);
}
}



Implement Spring Cloud Gateway using property based config
The Maven project will be as follows-



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 https://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.6.2</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com</groupId>
<artifactId>springcloud-gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-gateway</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.0</spring-cloud.version>
<!-- <spring-cloud.version>Greenwich.SR2</spring-cloud.version>-->
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Define the application.yml as follows-
server:
port: 8080
eureka:
instance:
hostname: localhost
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: first-microservice
uri: http://localhost:8081/
predicates:
- Path=/first/**
- id: second-microservice
uri: http://localhost:8082/
predicates:
- Path=/second/**
Create the main class with the @SpringBootApplication annotation.
package com;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class SpringcloudGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudGatewayApplication.class, args);
}
}
Start the three microservices we have developed-
- Go to url – localhost:8080/first/message



Go to URL – localhost:8080/second/message



Conclusion:
API Gateway is an important design concept. With an increasing number of microservices, it becomes important to have a common pattern that can handle a lot of the common workload of these services, and API Gateway helps with that.



1 thought on “Spring Cloud API Gateway With An Example13 min read”
Comments are closed.