Deprecating the Front End Middleware

 | 

 

Jailene joined Livongo as a front end engineering intern during the summer of 2019. She is a rising senior at Stanford University majoring in Computer Science. This post is about Jailene’s summer project, which was to remove the front end middleware and have the web UI access platform APIs through Livongo’s proxy server.

THE PROBLEM

Web UI ↔ MW ↔ Platform APIs

Livongo originally envisioned using middleware as a “backend for the front end” to provide customized APIs for the needs of the front end. Middleware provided single APIs for fetching all the data needed for a particular page instead of the web UI having to make multiple calls to the platform APIs. Middleware also helped in providing a frontend-specific variant of a platform API such as filtering out unneeded data fields in the response payload for efficiency. We did use middleware for these benefits for some time, but eventually we found it unnecessary as the front end pages themselves were componentized and could make per-component calls to the platform APIs as needed.

We then tried using GraphQL instead of middleware by providing GraphQL endpoints in the platform APIs. Unfortunately, our mobile developers still needed individual platform APIs to be developed because there were challenges using the available mobile client libraries for GraphQL. Given that and our team’s experience and comfort level using platform APIs’ traditional REST APIs, GraphQL was largely abandoned. We were left with the burden and costs of using middleware: extra latency on every API call, extra complexity in the system, and the development cost of maintaining it.

THE CHANGE

Web UI ↔ Proxy Server ↔ Platform APIs

Livongo’s web UI now bypasses the middleware layer and uses a simple nginx proxy server to access the platform APIs; the proxy layer is necessary because of security purposes such as restricting what platform APIs are accessible to the front end. With this modification, development time has been reduced and the web UI’s performance has improved because APIs complete at a faster rate. 

Transitioning APIs to use the proxy URL has consisted of 3 main phases. The first phase involved finding every API in each web flow and testing each, one by one, to see if it successfully completed with the proxy URL. If it did, then the API would have a useProxy parameter that would trigger the HTTP method to use the proxy URL. In the second phase, the proxy URL was made the default, so the useProxy parameter was removed and the few APIs that still needed to use middleware have a useMW parameter.

The proxy URL was added to the config files:

config.api.backend.proxyURL = "https://backend-api.livongo.com"

The code below shows an API that still needs to go through middleware:

return this.get('/v1/coach/appointment/types', params, 
{'Content-Type': 'application/json'}, {useMW: true});

In each HTTP method (get, post, and delete), the URL is determined by the useMW parameter. If the API has this parameter, then it uses middleware and if it doesn’t, then it uses the proxy URL: 

config = _.extend({}, config, {
   method: method,
   url: _.isUndefined(options.useMW) ? getFullProxyURL(url) :       
                                       getFullURL(url),
   timeout: 30000 // 30 seconds
});

The final phase aims to completely remove the front end middleware, so eventually there won’t be a useMW parameter and the URL for an HTTP method will default to be the proxy URL. As of right now, only about 90% of APIs go through the proxy server and the remaining 10% of APIs still go through middleware. Services such as Acuity and Webinato are not supported by our backend yet, so they rely on middleware. APIs that use a system token, such as an encryption API, cannot be exposed to the front end yet because it’s not secure, so they still have to go through middleware. We are currently working on transitioning these APIs to go through the proxy server so that we can completely become independent of the front end middleware.

Challenges

Some APIs required more modifications to successfully complete when going through the proxy server. A few APIs, such as the API to authenticate a login to member portal (/v1/users/me/auth), were blocked by CORS policy, so a Site Reliability Engineer added rules to our web proxy layer to add CORS headers for the hosts that needed them. 

Results

The table below compares the average speeds of APIs called 5 times each with middleware and with the proxy URL. As an example, when a Livongo member enters their member portal and navigates to their logbook, the API called to access the data on their bgs completes 61% faster when it uses the proxy URL instead of going through middleware. Not having to maintain middleware has also reduced the amount of development work for the Front End team which has enabled them to be more agile.

API (5 times) MW

(ms)

proxy

(ms)

net

(ms)

% improvement
/v1/users/me/auth 654 445 -209 32
/v1/users/v2/recruitable  753 544 -209 28
/v1/accounts/me/info 334 165 -169 51
v1/users/me/readings/bgs/data   292 113 -179 61
/v1/users/eligible/matching 373 222 -151 40
/v1/users/me/shares 278 133 -145 52

Our recruitable and member populations are growing rapidly, so we are striving to enhance the efficiency of our web UI to give them a quick and smooth flow experience when they are registering, accessing their member portal, setting up a coaching session, or going through any other web flow. 

Acknowledgements

Thank you for all the help and support from Max Vuong, Ray Thro, and the Front End team in making this project possible!