Zuul Proxy: Aggregated mapper on proxy routing - spring-boot

I have an application which looks like this
Now, whenever a request is received at the gateway, Zuul filter AuthorizationInterceptor gets invoked which does authentication/authorization by making some calls with User Service. If the authorization succeeds then actual microservice is called.
Now the with the new requirement, I need to write some aggregated API which takes data from two services and combine the data. So I added #RestController on Gateway Proxy but before that rest controller gets invoked AuthorizationInterceptor is not getting invoked. How can I tell ZuulFilter to get invoked even when the request is locally served.
Is there any solution for this? Should this be architected in a different way?

I don't think it's a good idea to put this kind of logic into the gateway service.
What you are referring to is an aggregator service which can be after the gateway as the other two services but instead of storing data or doing some business logic, it just takes the data from the two other services and aggregates them. This way the AuthorizationInterceptor will be invoked on the gateway level as well.
Another hacky approach would be to create a custom ZuulFilter which handles an imaginary endpoint call and aggregates the data. This way your AuthorizationInterceptor will be called as well but it's not a good idea to put this kind of logic into your edge service.

Related

Where should I make API calls in a spring application, in the controller or service?

I have a spring application. It exposes an endpoint, which when hit, needs to make an call to some other API. So, where should I make this API call, inside my controller itself or should I do it in the service class?
Based on any Architectural style (DDD, Microservices, etc), we should follow separation of concerns.
Best practice would be to create a Rest Client class for the API you want to consume and make all rest calls inside that.
Then you create a Service class to call the method consuming the API, performing the operation, data filter, anything you want to do with data.
Next would be to inject your service class inside the controller and return the data you just consumed and did some operation on it.
It might not sound well in a small project/feature, but it is the best practice when things get complicated and grow.

Is it correct to make a call to another Spring microservice inside a filter?

I built a Spring authentication microservice that takes care of authenticating each REST request. The authentication mechanism has been built using JWT. Each request should present an Authentication: Bearer header.
I also built a gateway microservice that exposes some of the API of the back end microservices. Each request to the gateway should be authenticated. I was thinking about implementing a OncePerRequestFilter, from which I could call the authentication microservice.
#Component
public class AuthFilter extends OncePerRequestFilter {
#Autowired
private RestTemplate restTemplate;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
// User restTemplate to call the authentication microservice and authenticate the request.
}
}
My question is probably a little too broad, but I wanted to try anyway.
Are there any issues on making a HTTP request inside a Spring filter? Could this lead to hangs or anything in some edge cases or is it just a poor design?
It is okay to call the external service inside a Filter. Spring Security also often does it in various cases (e.g. authenticate against LDAP, get JWK to verify JWT signature etc.) It may not call the external service directly inside the filter , but the filter will delegate to other object to call the external service. But the idea is the same, just make sure that you handle the case when the external service is not available such as setting a reasonable timeout on the HTTP request when calling the external service. Consider it as fail if it cannot receive the response from the external service after timeout.
P.S. Look like you are implementing your own authorization flow. If your authentication service support OAuth2 , you can consider to try Spring Security 5 's OAuth2 support which may make your life easier.
I agree with you that this approach is contradictory.
I see 2 main constraints in this approach:
this filter in request scope, so you can face with connection/read timeout;
more complex error handling (nested structure requires more accuracy in that).
If you can avoid these constraints, you can use this approach: RestTemplate is synchronous and blocking, so your filter will wait for results of RestTemplate call. With WebClient, such task could be unachievable.
Obviously that this implementation contradicts to SOLID, so better change your design/architecture.
It's a general practice to make HTTP calls from one microservice to another.
When dealing with authentication in REST API using JWT tokens it's a common practice to load cryptographic keys from a well known URL (https://YOUR_DOMAIN/.well-known/jwks.json) as JSON Web Key Set (JWKS).
According to SOLID principles, it's a good practice to create a dedicated class (Spring service) responsible for calling another service instead of injecting RestTemplate directly into the Filter.
The less responsibilities class has, the easier (less error-prone) it is to make changes to it in the future and cover code with unit tests. When all the logic is located in a single class, you have a lot of test cases and complicated mocking. When class has a single responsibility and calls another classes, it's easy to mock these classes and test only this single responsibility.
When a microservice calls another microservice via REST API, there are a few aspects that should be taken into account:
Failover - have multiple instances of the microservice to tolerate failure if a single instance
Scalability - dynamically start more microservice instances to handle growing load
Load balancing - route requests to different instances of the microservice
Service discovery - allow microservices to find each other by logical name instead of hard-coding host and port values
Timeouts - drop a request to a downstream microservice after exceeding timeout instead of waiting for the response forever
Retries - retry failed requests to a downstream microservice
Circuit breaker - prevent network or service failure from cascading to other services
These aspects are covered by Kubernetes + Istio or Spring Cloud stack.
If synchronous REST API calls between microservices are replaced with asynchronous messaging then almost all of these aspects are not so important.
For example, service A, instead of calling service B via REST API, subscribes on events emitted by service B to a Kafka topic. Every time event occurs, service A receives notification and persists the required data in own DB.
Such approach allows to achieve maximum decoupling between services but leads to eventual consistency. It means, it doesn't suit authentication and other strongly consistent cases. E.g. checking account balance is strongly consistent and should be done using synchronous call.

Controller and Service Methods or Just Controller Alone

I come across the URL - https://dzone.com/articles/quick-guide-to-microservices-with-kubernetes-sprin where both the controller and the service methods are exposed as REST API's
The confusion comes and it araises the question whether we need to expose controller methods as REST APIs or Service methods are APIS
if we made both of them as REST APIs then when we call a controller methods - 2 HTTP request might be sent and will cause performance issue.
Please advise.
The example that you're looking at is Feign, it is a declarative webservice client to make webservice calls easier between multiple microservices. Feign comes with GetMapping because its designed to work with other microservices.
In General, Controllers will have RequestMapping and handle the routing and service will do the work of running your business logic.
If we configure 2 RequestMapping it doesn't mean 2 HTTP calls will be made, only the ones with right url will be invoked and the other one will be a simple spring bean.

Spring Cloud Function-suitable for REST API? How to access GET path params?

I'm new to WebFlux and Serverless. I'm trying to create a REST API as Serverless via AWS API gateway.
The flow would be API Gateway --> Lambda --> DynamoDB
In order to achieve the API flow, would the Spring Cloud Function be the best choice? I found aws-serverless-java-container does the job seamlessly(wrapper of converting the event to http request/response)
I've gone through the documentation on http://cloud.spring.io/spring-cloud-function/single/spring-cloud-function.html and few examples found in https://github.com/spring-cloud/spring-cloud-function.
But still, I'm not convinced on whether with Spring Cloud Function I would be able to achieve the API flavor.
#Bean
//How path or query params can be mapped?
public Function<Flux<String>, Flux<String>> getEmployeeDetails() {
// business logic goes here
}
In the above snippet, how to achieve the GET request/response model. If my endpoint has /{dept}/{employee}/{name}, how Spring cloud function accepts the path params in GET request?
Any pointers would be helpful.
API Gateway wraps all data of the incoming request into an APIGatewayProxyRequestEvent object, which has several attributes, like the request body, path and query parameters, or the HTTP method of the original request.
For your use case, you would get the three path parameters dept, employee, and name.
However, the problem is that SpringBootApiGatewayRequestHandler, which does the mapping between the incoming APIGatewayProxyRequestEvent and your function, currently only considers a request body, but no other parameters at all.
I hope that the developers will fix this in the future.
In the meantime, you could implement a modified version of SpringBootApiGatewayRequestHandler, which considers the required parameters.
I've written a small article, which covers exactly this topic.
I have the same mistake with this, the documentation prompts you to think that you can do this, but you can't. This is only an example from spring-cloud-function, and springboot function aws specific code doesn't have this feature implemented (as far I could see).
You can follow the default route, if you want to implement your application in lambda with spring: https://github.com/awslabs/aws-serverless-java-container/blob/master/samples/springboot/pet-store.
Or... If you want, you can try the hard way, but attemption: you are completely alone: https://github.com/arawn/building-serverless-application-with-spring-webflux.
This project himself implements ObjecMapper conversions and you can get the parameters from request: https://github.com/arawn/building-serverless-application-with-spring-webflux/blob/master/src/main/java/serverless/aws/springframework/http/server/reactive/SimpleAPIGatewayProxyServerHttpRequest.java
The trick from here is to create Path template in lambda with proxy (Path: '/{proxy+}') and request are delegated from aws mapper.
Good luck!

Request filter versus request interceptor?

My application exposes a RESTful API which when called calls out to a mailbox server and fetches data. I want to be able disable the service during application runtime in the event of some outage on the mailbox server. I wanted to do this in a way that the logic of deciding whether or not to call the mailbox server was abstracted from the actual code that calls the mailbox server. Two options which seem to fit this scenario are filters and interceptors however I'm looking for advice on which one best suits this requirement and what are the difference between each?
Thanks
If you are using Spring MVC then you can use an interceptor, which is like a filter but that has access to the Spring context. If you are using Jersey then you can't use interceptors.

Resources