Pollito Dev
April 9, 2024

Spring Cloud: api-gateway and naming-server concepts

Posted on April 9, 2024  •  8 minutes  • 1690 words  • Other languages:  Español

Inspiration

At the end of my previous blog Anime Poster Generator 4: A backend dev approach to frontend , I said:

The very important people that decide my salary won’t seat with me for an annual review until I complete some courses in an educational platform of their choice, to which I gotta pay from my money or use the educational bonus they give me (which at the end of the day, is my money) […] Can’t help but think it is stupid you want me to demostrate that I know Java after a year coding in Java. But meh, whatever, will play by their rules (what a waste of time though).

Said educational platform is pluralsight . I just speedrun through the required knowledge I had to demonstrate, skipping the courses completely and going straight for the skill assesments.

When it came time to show off my Spring Cloud knowledge, I remembered that I had some notes about the Master Microservices with Spring Boot and Spring Cloud Udemy course. It is a very complete course I finished back in April 2023.

Funny enough, the skill assessment questionnaire was more focused in sleuth and ribbon , both of which I don’t have any experience with nor use at my work. I came out swinging with a good qualification nonetheless. This is a perfect example on the close to pointless fact that is to evaluate developers.

Here’s the result: my pluralsight profile + my DEVSU score (99%, nice).

skills

After reading through my notes about Spring Cloud, decided to revisit the course to improve on them and maybe write a blog. What a nice surprise was to see that the guy who made the course is still updating it to the latest version of Spring Boot. Another reason for you to go and spend the money in the course. The man is a natural educator.

Anyways, here’s wonderwall my improved notes on Spring Cloud.

DISCLAIMER: this is not a copy-paste of Master Microservices with Spring Boot and Spring Cloud Udemy course. I highly recommend buying that course. All the code shown below was written by me. Enjoy.

Check the code!

You can check the code in the following repos (in all of them, stick to the branch feature/docker-compose. You may find other branches, that’s me experimenting other solutions).

What’s an api-gateway?

Let’s analyze this diagram:

diagram

We have:

So far so good. So… what’s that thing “api-gateway”?

An API Gateway is the front door to your application, ensuring that every request is directed to the correct destination. This gateway serves several critical functions and can be leveraged in various use cases:

Use Cases:

By acting as the central point for managing and directing traffic, a gateway microservice enhances the maintainability, scalability, and security of cloud-based applications.

Example

Let’s analyze the diagram, again, with more focus on the step by step.

diagram

  1. Someone calls api-gateway/microservice-a. api-gateway recieves this request and does whatever it is coded to do with said request (could maybe add a header, check auth, encode/decode info, or just be transparent and do nothing).
  2. api-gateway knows where microservice-a is, and passes the request.
  3. microservice-a recieves the request. It needs something from microservice-b, so makes a new request that goes through the gateway.
  4. Again, api-gateway does whatever it is coded to do with this new request to microservice-b. It knows where microservice-b is, and passes the request.
  5. microservice-b recieves a request, process it, and returns.
  6. api-gateway returns.
  7. microservice-a does what needed to do with microservice-b’s response, and retuns.
  8. Final response.

Could you’ve saved a few request/response by going straight from microservice-a to microservice-b? yep totally. Just for example purposes, I decided to do it this way. Maybe your reality needs to save those extra request, or maybe in needs to always go through the gateway. Each reality is different.

A look into api-gateway code

When you get into the api-gateway code, you notice something… It is very empty.

api-gateway code

How does the api-gateway know where to send the requests? The answer is in the pom.xml.

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

The spring-cloud-starter-gateway dependency gives to the microservice all the discused gateway characteristics.

Here the star of the show is spring-cloud-starter-netflix-eureka-client. It registers your API Gateway as a client with the Eureka Server (a service registry). This enables the gateway to discover and keep track of the instances of microservices available in your ecosystem.

When a request arrives at the API Gateway, the following steps occur:

  1. The gateway identifies the route and the microservice to which the request should be forwarded based on the configured routing rules.
  2. The gateway consults the Eureka Server to obtain the current instances of the target microservice, including their network locations.
  3. The Eureka Server responds with the information about the available instances. It might return multiple instances if the target microservice is scaled horizontally for high availability.
  4. The gateway applies any configured load balancing strategy to select an instance if multiple are available.
  5. The request is forwarded to the chosen microservice instance for handling.

This combination of Spring Cloud Gateway and Eureka Client enables dynamic routing based on service discovery, making the system more resilient and scalable.

The API Gateway doesn’t need to be statically configured with the locations of microservices. Instead, it dynamically resolves them, accommodating real-time changes in the microservices landscape, such as scaling events or services going down for maintenance.

naming-server

Eureka Client register microservices into a service registry. Now we need that, a service registry. I call it naming-server.

When you look into its code, you notice something… It is literally empty! Just the main Spring Boot class with an annotation.

@SpringBootApplication
@EnableEurekaServer
public class NamingServerApplication {

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

}

Again, all the magic is done by a dependency in the pom.xml file.

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

Some considerations

Registering in naming-server

Every microservice that wants to be registered in the naming-server to be found by other microservices, needs:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>3.2.4</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>4.1.1</version>
</dependency>
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka #or wherever eureka server is
  instance:
    prefer-ip-address: true

What are those micrometer and zipkin dependencies?

The Master Microservices with Spring Boot and Spring Cloud Udemy course also comes with some content about logging and tracing, so I decided to implement them here as well.

Without getting to technical about it, those dependencies helps with:

The only thing that had to change in the proper business code to make these dependencies work were:

@Configuration
@ComponentScans(
    value = {
      @ComponentScan(
          basePackages = {
            "dev.pollito.microserviceb.api",
          })
    })
@RequiredArgsConstructor
public class MicroserviceBApiConfig {
  private final MicroserviceBProperties microserviceBProperties;
  private final MeterRegistry meterRegistry;
  private final ObservationRegistry observationRegistry;

  @Bean
  public HelloWorldApi microServiceBApi() {
    return Feign.builder()
        .client(new OkHttpClient())
        .encoder(new GsonEncoder())
        .decoder(new GsonDecoder())
        .errorDecoder(new MicroserviceBErrorDecoder())
        .logger(new Slf4jLogger(HelloWorldApi.class))
        .logLevel(Logger.Level.FULL)
        .addCapability(new MicrometerObservationCapability(observationRegistry))    // <-- THIS IS NEW
        .addCapability(new MicrometerCapability(meterRegistry))                     // <-- THIS IS NEW
        .target(HelloWorldApi.class, microserviceBProperties.getBaseUrl());
  }
}
logging:
  pattern:
    level: "%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]"
management:
  tracing:
    sampling:
      probability: 1.0

Let’s get this thing working

Use the docker-compose file to get everything started. I won’t go into details on how docker compose works. This is a Spring Cloud blog, not a docker one.

I personally like to use docker desktop for these things, but you can go full CMD.

docker desktop

If you check localhost:8761 , you’ll find the Eureka Server with all the services that got registered.

Eureka Server

Executing this curl will make the whole process of going through the api-gateway, microservice-a, microservice-b and back.

curl --location 'http://172.22.224.1:8765/microservice-a'

postman

We can see the whole request travel through the microservices thanks to zipkin. Go to http://localhost:9411/zipkin/ .

zipking

Click on “RUN QUERY” and you’ll find your request.

run query

Click on “SHOW” to see more details.

show

Next steps

Deploying this same idea in Google Cloud GKE.

Hey, check me out!

You can find me here