This is the sixth day of my participation in the August More text Challenge. For details, see: August More Text Challenge

preface

Our business architecture for developing a simple application is as follows:

In the beginning, the front end only needs to call a service to complete the corresponding business. Later, the business logic becomes more complex. The backend decouples the complex business into a new service:

In this case, the front end needs to invoke two different business interfaces to meet business requirements. As businesses become more and more complex, more and more businesses need to be split on the back end (micro-servitization). At this time, the front end needs to meet business requirements, and a function has to call two or more micro-service interfaces to complete the business:

The code implementation of such an architectural front end is bound to become very bloated and cumbersome, and too many requests can lead to network performance bottlenecks. So to solve this problem, someone proposed the BFF layer.

BFF layer

What is the BFF layer

Before you build the BFF layer, first understand what the BFF layer is. Backend For FrontEnd (BFF) simply means the Backend For front-end services. It is not technology, but a logical layering. It sits between the back-end microservices and the front end, and its most direct role is to interconnect and process the front end requests.

Through the BFF layer, when the front-end calls the interface, it only needs to call the BFF layer interface of the business. The BFF layer integrates the microservices that need to be requested in the business. This way, even if we change the microservice on the back end, we only need to change the BFF layer without changing the front-end code.

What can BFF do

  • Service aggregation As mentioned above, THE BFF layer can integrate multiple microservices in the business and expose only one interface point externally. The front end only needs to call one interface and pay attention to data transmission, without paying attention to complex invocation of microservices.

  • Cache data BFF layer is connected with front-end requests. As the processing point of business request microservices, it can also do data cache.

  • Access control service in the permission control, all services in the permission control in the BFF layer, so that the underlying services more pure and independent.

Build the BFF layer using Node

Now that we know what the BFF layer is, let’s build a demo of the BFF layer for service aggregation using Node.js.

The business scenario

There are two microservices in the back end:

  • One is a micro-service for managing big data systems, providing the function of recording and pushing big data information.
  • One is a micro-service that manages order information and provides the function of adding, deleting, modifying and checking orders.
  • The front end also needs to call the function of big data information entry when placing orders.

The system class diagram

The following is a diagram of the system classes that the backend provides services

Call timing diagram

After receiving the WEB request, THE BFF layer sends the request to the Order Service and Data Service. After the two services are processed, the BFF layer returns the message to the forward end. The sequence diagram is as follows:

Build a simple BFF layer

System design finished, now start to implement the code, first to implement order microservices and data microservices

const http = require('http');

// Order service
const orderApp = http.createServer((req, res) = > {
  handleOrderInput(req, res);
});

orderApp.listen(8081.() = > {
  console.log('Order Server is running at 8081 port');
});

// Data services
const dataApp = http.createServer((req, res) = > {
  handleDataInput(req, res);
});

dataApp.listen(8082.() = > {
  console.log('Data Server is running at 8082 port');
});

function handleOrderInput(req, res) {
  switch (req.url) {
    case '/order/add':
      res.end('{ code: 200, msg: "success", data: "" }');
      break;
    default:
      res.end('{ code: 500, msg: "route not found", data: "" }');
      break; }}function handleDataInput(req, res) {
  switch (req.url) {
    case '/data/add':
      res.end('{ code: 200, msg: "success", data: "" }');
      break;
    default:
      res.end('{ code: 500, msg: "route not found", data: "" }');
      break; }}Copy the code

In the code above, we create the order service and the data service, occupying ports 8081 and 8082, respectively. Next, create the BFF layer

const http = require('http');
const BFF = http.createServer((req, res) = > {
  handleBFF(req, res);
});

BFF.listen(8080.() = > {
  console.log('BFF Server is running at 8080 port');
});

function handleBFF(req, res) {
  switch (req.url) {
    case '/order/add':
      addOrder(req, res);
      break;
    default:
      res.end('{ code: 500, msg: "route not found", data: "" }');
      break; }}// Handle the add order method
function addOrder(req, res) {
  if(req.method ! = ='POST') {
    res.end('{ code: 500, msg: "route not found", data: "" }');
    return;
  }

  let data = ' ';
  req.on('data'.(chunk) = > {
    data += chunk;
  });

  req.on('end'.async() = > {const orderResult = await publicRequest(
      'http://localhost:8081/order/add',
      data
    );
    const dataResult = await publicRequest(
      'http://localhost:8082/data/add',
      data
    );
    res.end(JSON.stringify({ orderResult, dataResult }));
  });
}

// Public request method
async function publicRequest(url, data) {
  return new Promise((resolve) = > {
    const request = http.request(url, (response) = > {
      let resData = ' ';
      response.on('data'.(chunk) = > {
        resData += chunk;
      });
      response.on('end'.() = > {
        resolve(resData.toString());
      });
    });

    request.write(data);
    request.end();
  });
}
Copy the code

In the BFF layer, a common request method for user request services is created. The request adds the order and calls the data service interface to add the data. Test it out:

Run the service

Initiate an HTTP request

POST http://localhost:8080/order/add HTTP / 1.1
Content-Type: application-json
{
  "productId": 1,
  "type": "toy"
}
Copy the code

return

HTTP / 1.1 200 OK 
Date: Mon, 16 Aug 2021 06:20:19 GMT 
Connection: close 
Content-Length: 120 {"orderResult":"{ code: 200, msg: \"success\", data: \"\" }","dataResult":"{ code: 200, msg: \"success\", data: \ \ ""}}"Copy the code

At this point, one of the simplest BFF layers is implemented. Note that HTTP requests are now used when invoking other service interfaces in the BFF layer, which is equivalent to a request forwarding between the Intranet. Since the request is based on the HTTP protocol, the network performance may not be very good. Is there a way to transmit request information over the transport layer? The answer is to use RPC

Optimization of BFF layer

  • RPC Remote procedure call

    The simple understanding is that one node requests a service provided by another nodeIt is based on TCP data transmission, data will be directly inThe transport layerThe transmission is complete. The server and client are based onsocketLink. The figure of data transmission is as follows:

  • Implementation in Node

    Implementing an RPC framework is a systems project, and in the next section you’ll use Node.js to implement an RPC.

summary

This article introduced the concept of BFF and how to build a BFF layer using Node.js

If there are any inaccuracies or errors in this article, please note them in the comments section

reference

  • BFF —— Backend For Frontend
  • What is RPC?