Lab 1: Routing - Configure & Monitor Gateway Routes
In this first part we look at one of the core features of an API gateway: Routing.
Info: See Spring Cloud Gateway Route Predicate Factories Reference Doc for all details on how to configure a routing predicates.
Lab Contents
Learning Targets
In this lab you will basically learn how the spring cloud gateway works with route predicates and gateway filters.
The Gateway Handler Mapping determines if a request matches the configured route predicates. If a match is found then the Gateway Web Handler runs the request through a filter chain specific to this request. First, in the request all configured pre-filters are executed. Then the proxied service is called. Finally, all configured post-filters are executed for the response.
In lab 1 you will learn how to:
Configure route predicates and filters using both,
the declarative approach in the
application.yml
filethe functional approach in Java code using a
RouteLocatorBuilder
and the fluent Java routes API
Configure routes from clients to the
customer-service
andproduct-service
backend microservicesConfigure basic filters like the
RewritePath
andRedirectTo
filters.How to monitor configured route definitions and corresponding filters using the actuator endpoint
Folder Contents
In the lab 1 folder you find 2 applications:
initial: This is the gateway application we will use as starting point for this lab
solution: This is the completed reference solution of the gateway application for this lab including all route predicates and filters we introduce during this lab
Start the Lab
Now, let's start with this lab.
Explore the initial application
Starting a new project using the Spring Cloud Gateway is very easy. Usually just go to https://start.spring.io and select the following dependencies:
Gateway (This adds all required Spring Cloud and Spring Cloud Gateway components)
Spring Boot DevTools (To speed up development cycle times)
Spring Boot Actuator (To verify configured gateway routes and provide some metrics)
To speed things further up this project has already been created for you.
Please navigate your Java IDE to the lab1/initial/api-gateway project and explore this project a bit. Then start the application by running the class com.example.apigateway.ApiGatewayApplication
inside your IDE
or by issuing a mvnw[.sh|.cmd] spring-boot:run
command.
If you have not yet seen the sample application architecture we will be building starting with this lab then please look into the sample application architecture.
For this lab we will also need the two provided sample backend services that you can find in the microservices root folder:
product-service: Provides a REST API for products
customer-service: Provides a REST API for customers
To test if the backend microservice applications works as expected, please run the corresponding spring boot starter classes and check if you can access the following REST API endpoints via the browser or the provided postman collection in /setup/postman:
You may also use a command-line client as well. Here are example requests using httpie and curl.
Httpie:
Curl:
To explore the complete APIs provided by the product-service and customer-service you may also check the Swagger UI at http://localhost:9091/swagger-ui.html (customer-service) and http://localhost:9092/swagger-ui.html (product-service).
There is also a machine-readable Open API document available at http://localhost:9091/v3/api-docs (customer-service) and http://localhost:9092/v3/api-docs.
Step 1: Add a route to the product-service
First start using the declarative approach to define routes.
Every routes entry in the application.yml
has the following attributes:
id: Every route requires a unique identifier
uri: This is the target Uniform Resource Identifier (URI) for the routing request
predicates: This list of route predicates defines how a request is matched against a configured route
filters: This list of gateway filters defines pre- and post-filters for the HTTP request and response
Please open the file src/main/resources/application.yml
in the project /lab1/initial/api-gateway and add the following entries (please note that you add these below the existing application.name
entry):
application.yml:
This defines a route from localhost:9090/api/v1/products (gateway) to localhost:9092/api/v1/products (product-service).
Now (re-)start the api-gateway application and make sure you also have started the product-service microservice located in /microservices/product-service project. Next try to call the new route at http://localhost:9090/api/v1/products using either the web browser or the provided postman collection (corresponding request in the Routing folder)
Step 2: Add a route to the customer-service
Now similar to the previous routing let's add a new route entry for the customer-service microservice. What's different to the previous one is that we need to define a route that matches both API versions provided by the customer-service:
Open the file src/main/resources/application.yml
in the /lab1/initial/api-gateway project and add the following entries with id customers after the previous routing entries:
application.yml:
Maybe you spotted already the difference. Here we introduced the placeholder {segment}
for a subsequent segment after the defined root paths. So several possible paths would match this predicate:
http://localhost:9090/api/v1/customers
http://localhost:9090/api/v2/customers
http://localhost:9090/api/v1/products
http://localhost:9090/api/v1/test
http://localhost:9090/api/v2/dummy
The desired routes that we wanted to achieve are these:
This route also would match the previous route of http://localhost:9090/api/v1/products but as we have already defined a more concrete route for products as the first entry that one will be used.
You may also specify the order of routes using the order
property.
Now (re-)start the api-gateway application and make sure you also have started the customer-service microservice located in /microservices/customer-service project. Next try to call the new route at http://localhost:9090/api/v1/customers or http://localhost:9090/api/v2/customers using either the web browser or the provided postman collection (corresponding requests in the Routing folder).
Step 3: Add a route for canary testing of customer service
Next we want to add a route to implement canary testing (canary release). This technique is used to test new functionality with a small group before generally rolling out this functionality to all users.
In Spring Cloud Gateway this can be done by using the weight
precondition type. With using this you can for example tell the gateway to route 80% of requests to the production version V1 of the customers API and 20% of requests to the new functionality of the V2 customers API.
So let's do this (again in the application.yml
file):
application.yml:
Note: We also introduced the
RewritePath
filter as we need to remap the gateway path to the correct target path of the backend API call.
Now (re-)start the api-gateway application and make sure you still have started the customer-service microservice located in /microservices/customer-service. Next try to call the new route at http://localhost:9090/customers using either the web browser or the provided postman collection (corresponding requests in Routing folder).
You will notice that sometimes you get customers with a corresponding address (V2 API) and in other cases just customers without any address (V1 API). In about 80 percent of cases you should only get the customers without addresses (the V1 API version).
Step 4: Enable route to hidden endpoint of customer service
Next we only want a routing to work if a special cookie is set for the request. There is a hidden API endpoint in the customer-service at http://localhost:9091/api/v1/customers/hidden that only returns some special result when the cookie hidden-api
is set to the value of true
.
The desired behaviour is that the gateway should only enable the routing to this endpoint if this special cookie is set correctly.
So let's do this (again in the application.yml
file):
application.yml:
Now (re-)start the api-gateway application and make sure you still have started the customer-service microservice located in /microservices/customer-service. Next try to call the new route at http://localhost:9090/api/v1/customers/hidden using either the web browser or the provided postman collection (corresponding request in folder routing).
You will notice that you get a 404 (not found)
HTTP status. Now retry it by setting the cookie hidden-api
with the value true
(either using developer tools in web browser or the cookies functionality in postman).
Please repeat the request. When the cookie is set correctly you should see the result with a 200 (OK)
HTTP status.
Step 5: Configure routes with the Fluent Java Routes API
Let's leave the declarative approach behind and continue configuration using the Fluent Java Routes API.
So let's do this. Please create a new Java class called GatewayRoutingConfiguration
in the package com.example.apigateway.routing
. Then add the following contents to this file.
GatewayRoutingConfiguration.java:
This configuration is just a standard spring configuration file using the common @Configuration
and @Bean
annotations.
Here we are using the RouteLocatorBuilder
to define routes. Each route()
call also contains the route id, the predicate path, the URI and filters. The first route configuration entries define a call to a predefined public API endpoint at https://httbin.org/get with adding a request and a response header. In the second route a redirect is made to the Spring website.
Now (re-)start the api-gateway application again. The customer-service microservice is not required anymore for this step. Next try to call the new routes at http://localhost:9090/get and http://localhost:9090/spring using either the web browser or the provided postman collection (corresponding request in Routing folder) and see what is happening.
That is all for route configuration features of this lab. The Spring Cloud Gateway provides many more routing capabilities that are beyond the scope of this workshop. Please check the Route Predicate Factories reference doc for details.
In the last step we will look at actuator support for Spring Cloud Gteway.
Step 6: Monitor routes and route metrics
In the last step we will look at what the spring cloud gateway contributes to the Spring Boot Actuator. To enable and remotely access the /gateway
actuator endpoint, in general you have to add some configuration to the application.yml
file.
application.yml:
This configuration is already done, so nothing to do here for you. With this configuration you can call the following actuator endpoints for gateway specific information:
Global filters that are applied to all routes
http://localhost:9090/actuator/gateway/globalfilters
Route filters that are applied to all routes
http://localhost:9090/actuator/gateway/routefilters
All configured route in the gateway
http://localhost:9090/actuator/gateway/routes
Information about a single route with given id
http://localhost:9090/actuator/gateway/routes/{id}
Metrics for the number of defined routes
http://localhost:9090/actuator/metrics/spring.cloud.gateway.routes.count
These actuator endpoints are not only very helpful for production but also helps to find out why some routes may not work as expected. You may try these using the web browser or using the postman collection (in the Actuator folder).
http://localhost:9090/actuator/gateway/routes:
This ends lab 1. In the next lab 2 you will learn how to configure resilience design patterns like retry, circuit breakers with fallback and rate limiting.
Important Note: If you could not finish this lab, then just use the project lab2/initial/api-gateway as new starting point.
To continue please head over to Lab 2.
Last updated