life coded

a personal blog by Maximilian Ehlers

Frontend Microservices

Frontend Microservices

With this article I want to show you the basic idea behind Microservices on the Frontend, or at least how I understood it.

The first thing to do is set up a small skeleton website that I will divide visually into 3 parts that each have some content. For this I am using the new CSS Grid functionality.

Here is a Screenshot (and the files if you want to follow along):
screenshot of website divided into 3 equal parts

html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title></title>
    <link rel="stylesheet" href="dist/css/main.css" typeclass="text/css" media="screen" title="no title" charset="utf-8">
  </head>
  <body>
    <div class="grid-container">
      <div id="first">
        <h1>FIRST</h1>
      </div>
      <div id="second">
        <h1>SECOND</h1>
      </div>
      <div id="third">
        <h1>THIRD</h1>
      </div>
    </div>
    <script type="text/javascript" src="dist/js/main.js"charset="utf-8"></script>
  </body>
</html>

css

html, body {
  height: 100%;
}

.grid-container {
  height: 100%;
  display: grid;
  grid-template-columns: 33.3% 33.3% auto;
  grid-template-rows: 100%;
}

#first {
  text-align: center;
  background-color: #333333;
}

#second {
  text-align: center;
  background-color: #666666;
}

#third {
  text-align: center;
  background-color: #AAAAAA;
}

js

// empty file

As you can see it is a simple page that is clearly divided into 3 parts. So this is a perfect use case for Microservices [JOKE].

Creating Services/Fragments

We are going to split each of these sections into their own service anyway and then load their content into the page dynamically, thus making it possible to split the page into different parts, that teams can work on seperately with whatever technology they want.
Lets call each of these parts a fragment.

The services are just node servers that will serve json containing an html string.
Here is the server code for the first fragment:

const fs = require('fs');
const express = require('express');
const app = express();
const html = fs.readFileSync('index.html', 'utf8');

app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

app.get('/', (req, res) => {
  res.setHeader('Content-Type', 'application/json');
  res.send(JSON.stringify({ fragment: html }));
});

const port = 3101;
app.listen(port, () => {
  console.log(`Example app listening on port ${port}!`);
});

and the html it is serving.

<div class="section1">
  <h1>
    Section1
  </h1>
</div>

Now we can just copy this fragment 2 times and change some stuff like the port and the html it is serving to end up with 3 fragments.
Start all 3 services and note their ports, in my case :

{
  section1: http://localhost:3101,
  section2: http://localhost:3102,
  section3: http://localhost:3103,
}

Loading the fragments

So back on the main page and lets remove the content from our index.html making the content in the body look like this:

    <div class="grid-container">
      <div id="first">
      </div>
      <div id="second">
      </div>
      <div id="third">
      </div>
    </div>
    <script type="text/javascript" src="dist/js/main.js"charset="utf-8"></script>

Screenshot:
same site but now without content

Lets load the fragments as soon as the page is loaded and somehow inject them into the page.

Here is what I have done for this example:

const first = document.getElementById('first');
const second = document.getElementById('second');
const third = document.getElementById('third');

const config = {
  section1: 'http://localhost:3101',
  section2: 'http://localhost:3102',
  section3: 'http://localhost:3103',
}

const getJson = async (url) => await(await(fetch(url))).json();

const getFragment = async (url) => {
  const json = await getJson(url);
  return json.fragment;
}

const setSection1 = () => {
  getFragment(config.section1).then((fragment) => {
    first.innerHTML = fragment;
  })
}

const setSection2 = () => {
  getFragment(config.section2).then((fragment) => {
    second.innerHTML = fragment;
  })
}

const setSection3 = () => {
  getFragment(config.section3).then((fragment) => {
    third.innerHTML = fragment;
  })
}

const main = () => {
  setSection1();
  setSection2();
  setSection3();
  
}

main();

The Code is pretty straight forward:

  1. get domnodes of the sections
  2. set config for the services (this should usually be in an external file and loaded here)
  3. define a function for getting json from a url via the fetch api
  4. define a function for getting the fragment out of the json
  5. we have a function for each section, loading the corresponding fragment into the sections innerHTML
  6. execute the 3 setSection functions

When we look at the page again, we can see that the content was loaded from our services:
website again with content now loaded from services, as shown in network tab

I hope this small example was helpful to you in understanding frontend microservices a bit better.
The whole project is avalaible at https://github.com/bananenmannfrau/fe-microservice-example.
It will be on the basis branch, as I am planning to investigate some more stuff like css encapsulation with this project. Maybe I will post my findings about that as well;

If you want to see a more complex architecture check out https://www.mosaic9.org/ from Zalando!