Microservices - Zuul API Gateway

Zuul API Gateway

Spring Cloud provides Zuul(Zool) proxy, similar to Nginx, that can be used to create API Gateway.

API Gateway, aka Edge Service, provides a unified interface for a set of microservices. so that clients no need to know about all the details of microservices internals like hostname & port numbers. However, there are some pros and cons of using API Gateway pattern in microservices architecture.

Pros:

  • Provides easier interface to clients

  • Can be used to prevent exposing the internal microservices structure to clients

  • Allows to refactor microservices without forcing the clients to refactor consuming logic

  • Can centralize cross-cutting concerns like security, monitoring, rate limiting etc

Cons:

server:
  port: 8100

zuul:
  routes:
    doctors-service:
      url: http://localhost:8082
    patient-service:
      url: http://localhost:8083
    disease-service:
      url: http://localhost:8081
  host:
    connect-timeout-millis: 2000
    socket-timeout-millis: 5000

https://github.com/greenlearner01/ApiGateway

Steps to Implement Zuul in our Application

1.Add Zuul & other required dependecies.

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
	<version>2.2.10.RELEASE</version>
</dependency>

2.Enable Zuul API gateway by adding @EnableZuulProxy annotation to our main class

@SpringBootApplication
@EnableZuulProxy
public class IDaamApiGatewayApplication {

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

3.Configure application.yaml file with Route Details (without Eureka Server Load balancer)

server:
  port: 8099
  
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/


# without Eureka Server
zuul:
  routes:
    edc-service:
      url: http://localhost:8031/edc/
    mi-service:
      url: http://localhost:8041/mi/

  host:
    connect-timeout-millis: 2000
    socket-timeout-millis: 5000

4. To access MicroService API via API Gateway use following URL’s

IDAAM API GATEWAY STARTED 
 http://localhost:8099/ 
 	 EDC Service:  http://localhost:8099/edc-service
 	 MI Service :  http://localhost:8099/mi-service

With Eureka Server

# WITH Eureka Server      
zuul:
 routes:
    edcservice:
      path: /edc/**
      serviceId: EDC-MICROSERVICE
 
    miservice:
      path: /mi/**
      serviceId: MI-MICROSERVICE      
 host:
    connect-timeout-millis: 2000
    socket-timeout-millis: 5000

As Zuul act as a proxy to all our microservices, we can use Zuul service to implement some cross-cutting concerns like security, rate limiting etc. One common use-case is forwarding the Authentication headers to all the downstream services.

Typically in microservices, we will use OAuth service for authentication and authorization. Once the client is authenticated OAuth service will generate a token which should be included in the requests making to other microservices so that client need not be authenticated for every service separately. We can use Zuul filter to implement features like this.

package com.idaam;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import javax.servlet.http.HttpServletRequest;
import java.util.UUID;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
 
public class AuthHeaderFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return PRE_TYPE;
    }
 
    @Override
    public int filterOrder() {
        return 0;
    }
 
    @Override
    public boolean shouldFilter() {
        return true;
    } 
    @Override
    public Object run()  {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
 
        if (request.getAttribute("AUTH_HEADER") == null) {
            String sessionId = UUID.randomUUID().toString();             
            ctx.addZuulRequestHeader("AUTH_HEADER", sessionId);
        }
        return null;
    }
}

We are adding AUTH_HEADER as a request header using RequestContext.addZuulRequestHeader() which will be forwarded to downstream services. We need to register it as a Spring bean in our MicroServices.

@Bean
AuthHeaderFilter authHeaderFilter() {
    return new AuthHeaderFilter();
}