We learned what an API Gateway is and why it's useful in a microservices architecture, how a Gateway helps route requests, perform authentication/authorization, balance load, and even protect the system from attacks. Now it's time to put that theory into practice and set up an API Gateway using Spring Cloud Gateway.
Did you know Netflix was a pioneer in building its own API Gateway that inspired the industry? Their Zuul project handled millions of requests per second so well that the Spring Framework created Spring Cloud Gateway as a modern alternative with broader capabilities.
What are we going to do?
In this lecture we'll configure Spring Cloud Gateway to route requests between multiple microservices. You'll learn not only how to create routes but also how to use filters to fine-tune your gateway.
1. Project setup
Creating a new Spring Boot project
We'll start by creating a new Spring Boot project that will act as the API Gateway. You can use Spring Initializr or your favorite tool.
These are the modules we'll need:
- Spring Cloud Gateway (required).
- Spring Boot Web Starter (added automatically).
- Spring Boot Actuator (for monitoring, optional).
Configuring pom.xml or build.gradle
If you're using Maven, add the following dependency to your pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
For Gradle users, add this to build.gradle:
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
Don't forget to specify the correct Spring Cloud version in your dependency management. For example, if you're using Spring Boot 3.x, the compatible Spring Cloud release is 2022.x. Set that in the dependency management section.
2. Configuring routes
A Route is the basic building block in Spring Cloud Gateway. It defines where to forward an incoming request. Let's start with a simple example: forward all requests from the path /service1/** to a local microservice running on port 8081.
Configuration in application.yml
Create an application.yml file under src/main/resources and add the minimal configuration:
spring:
cloud:
gateway:
routes:
- id: service1-route
uri: http://localhost:8081
predicates:
- Path=/service1/**
What's happening here:
id: a unique identifier for the route.uri: where to send the requests (our microservice on port8081).predicates: conditions under which the route is used. Here we say requests starting with/service1/should be handled by this route.
Code-based configuration equivalent
If you're not a fan of YAML, you can configure routes in code. Here's how:
@Bean
public RouteLocator customRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route("service1-route", r -> r.path("/service1/**")
.uri("http://localhost:8081"))
.build();
}
This method returns a RouteLocator containing all routes. Note that you can define routes in more detail by adding filters, which we'll cover next.
Testing the route
Start your API Gateway and the microservice on port 8081. Then use Postman, curl, or a browser to make the request:
GET http://localhost:8080/service1/hello
The API Gateway will forward the request to the microservice at http://localhost:8081/hello.
3. Using filters
Filters let you process requests and responses. Think of them as proxy hooks to add or modify information.
Adding filters
Let's add a filter that injects an HTTP header into every request. Update the application.yml configuration:
spring:
cloud:
gateway:
routes:
- id: service1-route
uri: http://localhost:8081
predicates:
- Path=/service1/**
filters:
- AddRequestHeader=X-Custom-Header, HelloWorld
Now every request to /service1/ will include the header X-Custom-Header: HelloWorld.
Implementing a custom filter
You can also implement your own filter. For example, a filter that logs every request:
@Component
public class LoggingFilter implements GlobalFilter {
private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
logger.info("Request URI: {}", exchange.getRequest().getURI());
return chain.filter(exchange);
}
}
This filter will run for every request. If you only want it for a specific route, add it to the filter chain for that route.
4. Configuring predicates
Predicates define the conditions under which a route will be used. For example, let's make a route active only for a specific HTTP method.
Add to application.yml:
spring:
cloud:
gateway:
routes:
- id: service1-get-route
uri: http://localhost:8081
predicates:
- Path=/service1/**
- Method=GET
Now only GET requests will be routed. All other methods (POST, PUT, etc.) will be ignored.
Advanced predicates
You can combine predicates. For example, the snippet below will only handle GET requests coming to the host mydomain.com:
predicates:
- Path=/service1/**
- Method=GET
- Host=mydomain.com
5. Useful filters and predicates: Handling CORS
If your API Gateway is exposed publicly, you need to account for CORS (Cross-Origin Resource Sharing). Add this configuration:
spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]':
allowedOrigins: "http://localhost:3000"
allowedMethods:
- GET
- POST
This allows requests from a frontend running on localhost:3000.
6. Verifying the result
- Make sure your microservices are running.
- Open Postman or use curl to test a few routes:
http://localhost:8080/service1/hello— should be forwarded to the microservice.http://localhost:8080/service1/unknown— should return 404 if the resource doesn't exist in the microservice.
If everything works, congrats! You just created your first API Gateway.
7. Common mistakes and how to fix them
- 404 when accessing a route: Check whether the path in the predicate matches the request you're sending.
- 500 when calling the microservice: Make sure the URI you specified (for example,
http://localhost:8081) is actually reachable and running. - CORS issues: If the browser blocks requests, ensure your CORS settings are configured correctly.
From here you can dive into more advanced API Gateway configurations like adding authentication, authorization, and load balancing. Useful links to explore:
GO TO FULL VERSION