6

My current design is to have clients connect to my (Java) Web API Gateway using a browser, the Web API Gateway will call each (Java) microservice to get their JSON data and return it to the UI component that made the request on the client.

The only client side rendering will be from each ReactJS UI component for recurring requests to the gateway.

On the server side the full HTML view will be rendered prior to being sent back to the client.

Client browser

     ▼ (Request Dashboard View)

Web API Gateway

     ▼ (Request microservice JSON data)

Microservice A JSON Data
Microservice B JSON Data
Microservice C JSON Data
Microservice D JSON Data

     ▼ (Return JSON Data to gateway)

Web API Gateway

     ▼ (Render HTML and return to Client)

Client browser

     ▼ (ReactJS UI Components request data from API Gateway)

This is where it gets unclear, would it be best to have each UI component communicate with the Web API Gateway or the parent Microservice it came from to get data?

Considerations

  • Having the UI components talk to the Web API Gateway seems reasonable but will couple the microservices to the gateway, meaning to expose a new API on the microservice the gateway will also need to be updated.
  • Having the UI components talk directly to its Microservice for data removes the need to also update the Web API Gateway, keeping them less coupled. But this then exposes the Microservice to external calls from the client browser.

Design Decisions

  • Having the UI components within the API gateways creates a UI monolith as opposed to having each microservice responsible for its own UI component. Using the monolithic approach simplifies the solution and also avoids the complexities of having to aggregate each microservices UI component when the client requests a particular view.

Tools:

  • Java
  • Nashorn
  • Dropwizard
  • ReactJS
  • Gradle
  • Webpack
  • NodeJS
  • NPM

How do I aggregate multiple microservice ui components on the Web API Gateway using Java and ReactJS then serve this pre-rendered HTML data along with the JavaScript application to the client?

Helpful References:

9
  • You load the data as json from each microservice Commented Apr 13, 2017 at 16:18
  • @ConstantinGALBENU Yes but I'm looking for guidance on how the process should be carried out. I've updated the question. Commented Apr 13, 2017 at 16:24
  • With server side rendering? Commented Apr 13, 2017 at 16:32
  • @ConstantinGALBENU question updated. Commented Apr 13, 2017 at 16:36
  • I still don't understand if you need server side rendering or not Commented Apr 13, 2017 at 16:44

2 Answers 2

3

So, a React component needs two things: the JavaScript source code and the data.

The JavaScript source code can be provided by a CDN.

The data must be provided by the Microservices.

If you don't want server side rendering, then the skeleton index.html file along with the JS files are provided by a CDN.

If you need server side rendering (for SEO purposes, for example) then the API gateway (or another Web server) will render the components using NodeJS by requesting their source code from the CDN and their data from the microservices then return the full HTML to the browser.

On the client side, React will continue to load other data from the right microservice as JSON using the API gateway.

Sign up to request clarification or add additional context in comments.

9 Comments

This is great info, helped alot, but I'm using Java not NodeJS, and I believe the ReactJS UI components should access only the Web API Gateway and not the Microservice it came from.
@mortond It does not matter whether you use Java or NodeJS for the microservices. You could use any stack and the components wouldn't care. The idea is that the components download only JSON data from the microservices, using the API Gateway or not. NodeJS is used only if you need server side rendering.
I understand that it dosent matter how the microservice is implemeted, but I'm using Java/Dropwizard. My question is about server side rendering using a stack of Java/ReactJS.
You situation is complicated because you keep the source code of the component in the microservice. You should keep them all in one location, i.e. a webserver with NodeJS installed and to render them from that webserver as a Single page application.
And you should use Java only to generate the JSON dynamic content
|
3

Problem

How to aggregate ReactJS UI components during server side rendering on the Web API gateway.

Solution

Use a templating framework like Mustache to inject the rendered HTML output of each ReactJS component server side, then serve this HTML back to the client.

Github repo https://github.com/damorton/dropwizardheroku-webgateway

Server Side

The solution I implemented on the Web API gateway first requested the JSON data from the microservice, then rendered the ReactJS component while injecting the JSON data from the microservice as Props. Once I had the fully rendered ReactJS component with data as a HTML string I used Mustache templating to inject the fully rendered ReactJS component HTML into the Mustache template, then returned this to the client.

WebGatewayResource.java

@GET
@Produces(MediaType.TEXT_HTML)
public IndexView index() throws IOException {

    // Get events json data from Events microservice
    ApiResponse events = getEventsJsonData();

    // Render the Events component and pass in props
    @SuppressWarnings("unchecked")
    List<Object> eventsProps = (List<Object>) events.getList();
    String eventsComponent = this.nashornController.renderReactJsComponent(kEventsUiComponentRenderServerFunction, eventsProps);

    IndexView index = new IndexView(eventsComponent);
    return index;
}

Note: Dropwizard performs alot of magic around Mustache templating so all that was needed was to create an index.mustache file and reference this when constructing the IndexView class. Returning this View to the client tells Dropwizard to render the view and return the HTML.

index.mustache

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Dropwizard Heroku Event Service</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react-dom.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react-dom-server.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.16.1/axios.min.js"></script>
</head>
<body>
  <h1>Events</h1>
  <div id="events">{{{eventsComponent}}}</div>
  <script type="text/javascript" src="assets/js/bundle.js"></script>
  <script type="text/javascript" src="assets/js/client.js"></script>
</body>
</html>

Client side

On the client side, to fix an issue with the client and server side rendered HTML being different due to the props for the ReactJS components not being available when the component was mounted initially, a javascript function is called when the page loads to request the JSON data from the gateway.

client.js

var loadEventsFromServer = function(eventsUrl) {
    axios.get(eventsUrl).then(function(res) {
        var data = res.data.list;       
        renderClientEvents(data);
    });
};

loadEventsFromServer('https://domain.webapigateway.com/events');

ReactJS

The client side HTML is not re-rendered when the component is mounted, React is aware of the already existing HTML from the server side render and only adds the event listeners for each component when it mounts. This allows React to update its components individually, and also takes advantage of server side rendering.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.