Enterprise Java

Creating an API Gateway with Zuul and Spring Boot

Introduction

When working with micro services it is common to have unified access-point to your system (also called API Gateway). Consumers only talk with the API Gateway and not with the services directly. This hides the fact that your system is composed out of multiple smaller services. The API Gateway also helps solving common challenges like authentication, managing cross-origin resource sharing (CORS) or request throttling.

Zuul is a JVM-based API Gateway developed and open-sourced by Netflix. In this post we will create a small Spring application that includes a zuul proxy for routing requests to other services.

Enabling zuul proxy

To use zuul in a project we have to add the spring-cloud-starter-netflix-zuul dependency. If we want to use the spring zuul actuator endpoint (more on this later), we also need to add the spring-boot-starter-actuator dependency.

01
02
03
04
05
06
07
08
09
10
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
 
<!-- optional -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Next we have to enable the zuul proxy using @EnableZuulProxy in our spring boot application class (or any other spring @Configuration class)

1
2
3
4
5
@SpringBootApplication
@EnableZuulProxy
public class ZuulDemoApplication {
    ...
}

Now we can start configuring our routes.

Configuring routes

Routes describe how incoming requests should be routed by zuul. To configure zuul routes we only have to add a few lines to our spring boot application.yml (or application.properties) file:

application.yml:

1
2
3
4
5
6
7
8
zuul:
  routes:
    users:
      path: /users/**
      url: https://users.myapi.com
    projects:
      path: /projects/**
      url: https://projects.myapi.com

Here we define the routes for two endpoints: /users and /projects: Requests to /users will be routed to https://users.myapi.com while requests to /projects are routed to https://projects.myapi.com.

Assume we start this example application locally and send a GET request to http://localhost:8080/users/john. This request matches the zuul route /users/** so zuul will forward the request to https://users.myapi.com/john.

When using a service registry (like Eureka) we can alternatively configure a service id instead of an url:

1
2
3
4
5
zuul:
  routes:
    users:
      path: /users/**
      serviceId: user_service

Another useful option is sensitiveHeaders, which allows us to remove headers before the request is routed to another service. This can be used to avoid leaking of sensitive headers into external servers (e.g. security tokens or session ids).

1
2
3
4
5
6
zuul:
  routes:
    users:
      path: /users/**
      url: https://users.myapi.com      
      sensitiveHeaders: Cookie,Set-Cookie,Authorization

Note that the shown example headers (Cookie,Set-Cookie,Authorization) are the default value of the sensitiveHeaders property. So these headers will not be passed, even if sensitiveHeaders is not specified.

Request / Response modification with filters

We can customize zuul routing using filters. To create a zuul filter we create a new spring bean (marked with @Component) which extends from ZuulFilter:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Component
public class MyFilter extends ZuulFilter {
 
    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }
 
    @Override
    public int filterOrder() {
        return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
    }
 
    @Override
    public boolean shouldFilter() {
        return true;
    }
 
    @Override
    public Object run() {
        RequestContext context = RequestContext.getCurrentContext();
        context.addZuulRequestHeader("my-auth-token""s3cret");
        return null;
    }
}

ZuulFilter requires the definition of four methods:

  • Within filterType() we define that our filter should run before (PRE_TYPE) the actual routing. If we want to modify the response of the service before it is send back to the client, we can return POST_TYPE here.
  • With filterOrder() we can influence to order of filter execution
  • shouldFilter() indicates if this filter should be executed (= calling the run() method)
  • in run() we define the actual filter logic. Here we add a simple header named my-auth-token to the request that is routed to another service.

Filters allow us to modify the request before it is send to the specified service or to modify the response of the service before it is send back to the client.

Actuator endpoint

Spring cloud zuul exposed an additional Spring Boot actuator endpoint. To use this feature we need to have spring-boot-starter-actuator in the classpath.

By default the actuator endpoint is disabled. Within application.yml we enable specific actuator endpoints using the management.endpoints.web.exposure.include property:

1
2
3
4
5
management:
  endpoints:
    web:
      exposure:
        include: '*'

Here we simply enable all actuator endpoints. More detailed configuration options can be found in the Spring Boot actuator documentation.

After enabling the zuul actuator endpoint we can send a GET request to http://localhost:8080/actuator/routes to get a list of all configured routes.

An example response might look like this:

1
2
3
4
{
    "/users/**":"https://users.myapi.com",
    "/projects/**":"project_service"
}

Summary

With Spring cloud you can easliy integrate a zuul proxy in your application. This allows you the configuration of routes in .yml or .properties files. Routing behaviour can be customized with Filters.

More details on spring’s support for zuul can be found in the offical spring cloud zuul documentation. As always you can find the examples shown in this post on GitHub.

Published on Java Code Geeks with permission by Michael Scharhag, partner at our JCG program. See the original article here: Creating an API Gateway with Zuul and Spring Boot

Opinions expressed by Java Code Geeks contributors are their own.

Michael Scharhag

Michael Scharhag is a Java Developer, Blogger and technology enthusiast. Particularly interested in Java related technologies including Java EE, Spring, Groovy and Grails.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button