I've started the journey of learning more about this architecture using Spring Cloud and the Netflix's projects.
From a general standpoint, I do understand the architecture but now that I'm actually coding an app, a horizon of doubts has appeared about some minimal stuff that could have a big impact in the big approach of this architecture.
First, my app is based on this tutorial which I assume as valid since it's from Spring itself: https://spring.io/blog/2015/07/14/microservices-with-spring
And now, the problem: (ALL THIS USES EUREKA) let's say I've a microservice "accounts" which consist only in Spring Data REST for the persistence/HATEOAS and on top of that I've a client service which consumes those endpoints using RestTemplate (because I'm using Ribbon's load balancer). From my view, this is how it works: user -> frontend -> client service -> Spring Data REST endpoints (the microservice) -> DB.
This is nice and all but when I get the endpoint response (from the RestTemplate), it contains hypermedia going directly to the microservice, and per se, you now can drive your way through the microservice while ignoring the load balancer, which, for me, kills the purpose of it. And if I've like 5 microservices scaling to each other, it means the user is now focusing into just one of a broad way of 5 microservice that are supposedly managed by load balancer.
Q1: Is ok for an user to have that knowledge of the API (and then kinda killing part of the structure)?
Even if I add the links to the services detected by Eureka and delete the current endpoints to that microservice, those links aren't going to work and such means I'm chopping of the hypermedia links.
Q2: Is there another approach to this? Through some kind of proxy, external load balancer, dns or something like that?
P.D: I don't know if I'm being clear enough. Please let me know if something is misty.
P.D.2: Summary question: what to do with those media links? Let them be or use something else (please tell) to actually get them "right"?
Edit: Based on the advices below, I added Zuul which seems to be the solution to my problem. Now, about Zuul, where should I use to filter?
My app is like this right now: account-microservice (Spring Data REST) and account-web-service (client with the RestTemplate Load balancer). Those are the Eureka registered names.
Where must go the @EnabledZuulProxy? Inside the microservice or inside the client?
My current config is this one (currently, the @EnabledZuulProxy is in the client):
My microservice:
@SpringBootApplication
@EnableEurekaClient
public class AccountServer {
public static void main(String[] args) {
System.setProperty("spring.config.name", "AccountServerClient");
SpringApplication.run(AccountServer.class, args);
}
}
//Config:
spring.application.name=account-microservice
spring.application.freemarker.enabled=false
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
eureka.client.instance.leaseRenewalIntervalInSeconds=5
My client:
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
@EnableCircuitBreaker
public class AccountMicroService {
public static void main(String[] args) {
// Tell server to look for registration.properties or registration.yml
System.setProperty("spring.config.name", "AccountMicroServiceClient");
SpringApplication.run(AccountMicroService.class, args);
}
}
//Config
# Spring properties
spring.application.name=account-web-service
spring.freemarker.enabled=false
eureka.instance.leaseRenewalIntervalInSeconds: 5
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
zuul.routes.account-web-service.path=/accounts/**
zuul.routes.account-web-service.serviceId=account-web-service
zuul.routes.account-web-service.stripPrefix=false
Client code to consume SDR:
//@HystrixCommand(fallbackMethod="test")
public ResponseEntity<PagedResources<AccountResource>> findAll(Pageable pageable) throws RestClientException, URISyntaxException {
return restTemplate.exchange(serviceUrl + "/accounts" + "?page={page}&size={size}&sort={sort}", HttpMethod.GET,
null, new ParameterizedTypeReference<PagedResources<AccountResource>>() {
}, pageable.getPageNumber(), pageable.getPageSize(), pageable.getSort());
}
Like this, it doesn't work at all. No filtering neither. If I change that and use it in the microservice, then it keeps sending everything directed to the microservice to the client, even the request from the client, which ends up with a loop and then an error (timeout, load balancer full, circuit broken...) which is generally this though: com.netflix.zuul.exception.ZuulException: Forwarding error.
Edit 2: I finally got Zuul to work and understood what it does. Now, when I access my new gateway app, it forwards the request to my microservice and the resulting hypermedia is now pointing to that gateway, which is what I wanted.
The problem was initially architectural and then turned into a coding problem, but now I think am clear about this technologies.
The cup of tea was understanding what Zuul does, when and how it does it. @Ryan Baxter guideline and this two articles: https://dzone.com/articles/microservice-architecture-with-spring-cloud-and-do and https://spring.io/guides/gs/routing-and-filtering/ where fundamentals to get this done. I'm gonna redact an answer for this with what I did and what I understood.