Spring Cloud Gateway Custom Filter to Collect Chunks Before Routing - spring-cloud

I am using Spring Cloud Gateway to route requests and I am trying to route a request that is sent by the client via POST with Transfer-Encoding: chunked which I want to "collect" all the chunks first before forwarding it as one large payload downstream (essentially removing the chunking). I would presume there's a way to do this by writing a custom filter (i.e., write an implementation of GatewayFilterFactory<T>) to process the http request to wait for all the chunks and create a new body of the combined chunks? Or is this an unrealistic expectation of what Spring Cloud Gateway is capable of?

Related

Request Response transformation using freemarker in spring cloud gateway

I am using spring cloud gateway Hoxton.M1 release to implement an API gateway. I have the following two spring boot apps -
Client <-> Router App <-> Wrapper App <-> Downstream application
Router App - This application has spring cloud gateway. All routes in application.yml point to a common REST controller end point in Wrapper application by passing a request header attribute "apiendpointid" to diff b/w diff api calls. Below is a sample route entry
- id: milestone
uri: http://localhost:5001
predicates:
- Path=/track/milestone
- Method=POST
filters:
- RewritePath=/track/milestone,/gateway/api/internal/process
- AddRequestHeader=apiendpointid,retailmilestone
- AddRequestHeader=appid,retail
- SecureHeaders
Wrapper App - This is a spring boot application which has Rest controller. Controller method does the following -
Identify JSON schema file basis the "apiendpointid" request
header attribute and apply JSON schema validation. Reject request in
case of schema validation failures by return 400 response to router
app.
Identity the freemarker request transformation file basis the "apiendpointid" request header attribute and transform incoming request to downstream expected format.
Send request to downstream.
Transform response from downstream to expected format again using freemarker response template.
Send response back to router app.
This works fine but there is an extra http "hop" from router to wrapper. We have not yet gone live; so not very sure if it will be a performance concern.
Currently wrapper is not built in a reactive way. Also team does not have much expertise in reactive programming. Are there any production implementations built this way (i.e. having this extra wrapper layer/app in the middle) or is it better to integrate all wrapper functionalities into router app itself? If yes, could you please direct me to some examples where request/response transformations/schema validations are being done in spring cloud gateway itself?

Two channels for one API

We have a SaaS. It consists of Single Page application (client), Gateway, Data Service 1, Data Service 2 and Notification Service.
Client talk with Gateway (using REST) and service route the request to appropriate Data Service (1 or 2) or do own calculations.
One request from the client can be split on multiple at Gateway service. The result is an aggregation of responses from the sub-services.
Notification Service - is a service which pushing information about changes made by other users using MQ and WebSocket connection to the client. Notification can be published by any service.
With enginers, we had a discussion how the process can be optimized.
Currently, the problem that Gateway spending a lot of time just waiting for the response from Data Services.
One of the proposals is letting Gateway service response 200 Ok as soon as message pushed to the Data Service and let client wait for operation progress throw Notification channel (WebSocket connection).
It means that client always sends HTTP request for operation and get confirmation that operation is executed by WebSocket from the different endpoint.
This schema can be hidden by providing JS client library which will hide all this internal complexity.
I think something wrong with this approach. I have never seen such design. But I don't have valuable arguments against it, except complexity and two points of failure (instead of one).
What do you think about this design approach?
Do you see any potential problems with it?
Do you know any public solutions with
such approach?
Since your service is slow it might makes sense to treat it more like a batch job.
Client sends a job request to Gateway.
Gateway returns a job ID immediately after accepting it from the Client.
Client periodically polls the Gateway for results for that job ID.

Pushing MailGun webhook onto AWS SQS

I need to process MailGun webhooks. I did implement a solution directly on our web servers to process the webhooks, but MailGun generates so many calls from a large campaign that it effectively becomes a DOS attack.
One solution I've been looking at is using AWS API Gateway to a Lambda function to then push onto an SQS queue. We can then poll the queue at a rate we can manage. Unfortunately we can't get this to work as AWS API Gateway does not support multipart/form-data content types (which some of the webhooks are). This means that our SQS messages are not well formatted / structured. The best we can do is use the $util.escapeJavaScript($input.body) function in the mapping template to create an SQS message that contains the raw string of the webhook content (with escaped javascript chars) that is effectively unparsable i.e. we can't get data out of it.
I've had a go at using Zapier to process the webhook and push directly on the SQS queue. This can parse the various content types effectively and create a nicely structured message for us, but the cost of the service is not viable.
Has anybody managed this problem in another way? Are there solutions to API Gateway not parsing the content properly? I've deliberately stayed away from MailGuns event polling API as it involves significant delays before the polled data can be 'trusted' (according to MailGun).
Basically, is there another way of getting a nicely parsed message from content types multipart/form-data and application/x-www-form-urlencoded onto the queue?
Any ideas would be much appreciated!
To add, this link higlights issues with APS Gateway and multipart\form-data content:
API Gateway - Post multipart\form-data
As you've mentioned you can base64 encode in api gateway and call base64decode in the lambda function to retrieve the original payload (There are standard libraries in every language).
Also, note you can that you can use multipart form data for non file bodies.
Get non file body from multipart/form-data using AWS API Gateway and Lambda
I had the same challenge when building Suet. I ended up switching to Google Cloud functions which I really recommend. Don't waste time on Amazon API Gateway. Use Google Cloud Functions and use a middleware like multer. (You can see the source of Suet's webhook handler here).
Not sure if you ever came to a solution, but I have this working with the following settings.
Setup your API Gateway method to use "Use Lambda Proxy integration"
In your lambda (I use node.js) use busboy to work through the multi-part submission from the mailgun webhook. (use this post for help with busboy Busboy help)
Make sure that any code you are going to execute after all busboy is complete is executed in the 'finish' portion of the busboy code.

Send batched data to Google Calendar with Scala/Spray

We are successfully sending data for new, changed, and removed events to Google Calendar from a Scala app using Spray HTTP. However, we are currently sending one event per request, and this becomes very inefficient when there are multiple events for the current user. In these cases we would like to send batched data, as described here:
https://developers.google.com/google-apps/calendar/batch
The documentation begins with:
A batch request is a single standard HTTP request containing multiple
Google Calendar API calls, using the multipart/mixed content type.
Within that main HTTP request, each of the parts contains a nested
HTTP request.
Since we are already using spray http we would like to use its support for multipart/mixed requests (spray.http.MultipartContent) but it isn't clear that this is possible since the parts must consist of one or more spray.http.BodyPart instances and there doesn't seem to be a way to turn a spray.http.HttpRequest into a BodyPart.
Has anyone successfully done this? We are also taking a look at the Google API Client for Java but would rather not go down that path if there is a more Scala-friendly way to do it.

Programmatically Call REST URL

Summary
Is there a way to programmatically call REST URLs setup in JBoss via RESTEasy so that the programmatic method call actually drills down through the REST processor to find/execute the correct endpoint?
Background
We have an application that has ~20 different REST endpoints and we have set the application up to receive data from other federated peers. To cut down on cross network HTML requests, the peer site sends a bulk of requests to the server, and the receiving server needs to act upon the URL it receives. Example data flow:
Server B --> [Bulk of requests sent via HTTP/Post] --> Server A breaks list down to individual URLs --> [Begin Processing]
The individual URLs are REST URLs that the receiving server is familiar with.
Possible Solutions
Have the receiving server read through the URLs it receives, and call the management beans directly
The downside here is that we have to write additional processing code to decode the URL strings that are received.
The upside to this approach is that there is no ambiguity as to what happens
Have the receiving server execute the URL on itself
The receiving server could reform the URL to be http://127.0.0.1:8080/rest/..., and make a HTTP request on itself.
The downside here is that the receiving server could have to make a lot of HTTP requests upon itself (it's already somewhat busy processing "real" requests from the outside world)
Preferred: Have the receiving server access the main RESTEasy bean somehow and feed it the request.
Sort of combo of 1 & 2, without the manual processing of 1 or the HTTP requests involved with 2.
Technology Stack
JBoss 6.0.0 AS (2010 release) / Java 6
RESTEasy