Skip to content

2. Gateway

The main functionality of Gateway Microservice is to route the incoming requests to the appropriate microservice, therefore, it is the entry point for all the incoming requests. In counterpart, each microservice have to expose their own port and endpoints to the internet, which is not a good practice. The Gateway Microservice will act as a reverse proxy and route the incoming requests to the appropriate microservice. Also, it will also handle the authentication and authorization of the incoming requests.

flowchart LR
    subgraph api [Trusted Layer]
        direction TB
        gateway e2@==> account
        gateway e4@==> others
        account --> db@{ shape: cyl, label: "Database" }
        others --> db
    end
    internet e1@==>|request| gateway:::red
    e1@{ animate: true }
    e2@{ animate: true }
    e4@{ animate: true }
    classDef red fill:#fcc

Advantages of using a Gateway Microservice:

  • It provides a single entry point for all the incoming requests, which makes it easier to manage and secure the application;
  • Only a single port needs to be exposed to the internet, which makes it easier to secure the application;
  • It can handle:
    • The authentication and authorization of the incoming requests, which makes it easier to secure the application;
    • The load balancing of the incoming requests, which makes it easier to scale the application;
    • The caching of the incoming requests, which makes it easier to improve the performance of the application;
    • The logging and monitoring of the incoming requests, which makes it easier to debug and troubleshoot the application;
    • The rate limiting of the incoming requests, which makes it easier to protect the application from DDoS attacks;

The key functionalities of Gateway Microservice are:

  • Routing: it will route the incoming requests to the appropriate microservice.
  • Authentication/Authorization: it will handle the authentication and the authorization of the incoming requests.

Gateway-Service

📁 api
├── 📁 gateway-service/
   ├── 📁 src/
      └── 📁 main/
          ├── 📁 java/
             └── 📁 store/
                 └── 📁 gateway/
                     ├──  GatewayApplication.java
                     └──  GatewayResource.java
          └── 📁 resources/
              └──  application.yaml
   ├──  pom.xml
   └──  Dockerfile
├──  .env
└──  compose.yaml

Source

<?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>4.0.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>store</groupId>
    <artifactId>gateway-service</artifactId>
    <version>1.0.0</version>

    <properties>
        <java.version>25</java.version>
        <spring-cloud.version>2025.1.0</spring-cloud.version>
        <maven.compiler.proc>full</maven.compiler.proc>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway-server-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </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.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
spring:
  application:
    name: gateway

  cloud:
    gateway:
      server:
        webflux:

          globalcors:
            corsConfigurations:
              '[/**]':
                allowedOrigins: ${CORS_ALLOWED_ORIGINS:*}
                allowedHeaders: "*"
                allowedMethods: "*"

          routes:

            - id: insper
              uri: https://www.insper.edu.br
              predicates:
                - Path=/insper/**

            - id: accounts
              uri: http://account:8080 # hostname da maquina
              predicates:
                - Path=/accounts/**
package store.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class GatewayApplication {

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

}
package store.gateway;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GatewayResource {

    @GetMapping("/")
    public ResponseEntity<String> hello() {
        return ResponseEntity.ok("Store API");
    }

    @GetMapping("/health-check")
    public ResponseEntity<Void> healthCheck() {
        return ResponseEntity.ok().build();
    }

}
1
2
3
4
FROM eclipse-temurin:25
VOLUME /tmp
COPY target/*.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

Note that the Gateway Microservice is implemented using Spring Cloud Gateway, which is a library that provides a simple and effective way to route the incoming requests to the appropriate microservice. It also provides a lot of features such as authentication, authorization, load balancing, caching, logging, monitoring, and rate limiting.

Also, the Gateway Microservice is implemented using WebFlux, which is a reactive programming model that allows to handle a large number of concurrent requests with a small number of threads. This makes it easier to scale the application and improve the performance of the application.

application.yaml

The application.yaml file is configured to route the incoming requests to the appropriate microservice, therefore, you need to make sure that the microservices are running and exposing their ports before starting the Gateway Microservice.

Also, the application.yaml file is configured the CORs to allow the incoming requests from the internet, therefore, you need to make sure that the CORS configuration is correct before starting the Gateway Microservice.

After finishing the implementation of the Gateway Microservice, we can include it in the compose.yaml file and start it using Docker Compose. You can also test the Gateway Microservice by sending requests to the exposed port of the Gateway Microservice and checking if the requests are routed to the appropriate microservice.

compose.yaml
name: store

services:

  db:
    image: postgres:17
    hostname: db
    ports:
      - 5432:5432
    volumes:
      - ${VOLUME_DB}:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: ${DB_USER:-store}
      POSTGRES_PASSWORD: ${DB_PASSWORD:-devpass}
      POSTGRES_DB: ${DB_NAME:-store}

  account:
    build:
      context: ./account-service
      dockerfile: Dockerfile
    hostname: account
    environment:
      DATABASE_HOST: db
      DATABASE_PORT: 5432
      DATABASE_DB: ${DB_NAME:-store}
      DATABASE_USERNAME: ${DB_USER:-store}
      DATABASE_PASSWORD: ${DB_PASSWORD:-devpass}
    deploy:
      replicas: 2
    depends_on:
      - db

  gateway:
    build:
      context: ./gateway-service
      dockerfile: Dockerfile
    hostname: gateway
    ports:
      - 8080:8080

Note that the other microservices declared in the compose.yaml file do not have its ports exposed to the internet, therefore, they can only be accessed through the Gateway Microservice.