Upgrade to Pro — share decks privately, control downloads, hide ads and more …

When Node and APIs become BFFs

When Node and APIs become BFFs

API development is a common challenge for many teams and companies. In a world of micro-services, multiple backends and ever more demanding front-ends, building the right set of APIs becomes more important.

How can a single API support a diverse set of clients, different data access patterns, and multiple SLAs?

Backend for Frontend (BFF) is a pattern that has emerged to solve some of these challenges and help software engineers build better-focused APIs that can cater to different user experiences. This is achieved by actually building one backend for every frontend client.

In this talk, I discuss and present some of the experience and the challenges me and my team ran into while building API services for all frontends at IFTTT.

Ivayr Farah Netto

November 13, 2017
Tweet

More Decks by Ivayr Farah Netto

Other Decks in Programming

Transcript

  1. IFTTT ❤ • Millions of users • Billions of API

    calls every day • Website, iOS app, Android app
  2. Feed Recommendations Geolocation MonoRail ☁ C
 O O
 R
 D


    I
 N
 A
 T I O N T
 R
 A C
 I
 N G A U T H … v2 -> API Gateway
  3. const promises = Promise.all([ fetch(feedURL), fetch(locationURL) ]) promises.then(result => {

    return res.json({ feed: result[0], location: result[1] }) })
  4. const pTimeout = require(‘p-timeout') // 99pct was ~1500ms
 pTimeout( get(feedURL),

    1600 ).then(onSuccess, onError) function onError(err) { console.error(err) //=> [TimeoutError: Promise timed out] return res.error(err) }
  5. const retry = require(‘p-retry') // retry 2 times before giving

    up retry(loadFeed, { retries: 2 }) // everything is still a promise function loadFeed() { return get(feedURL).then(feedRes => {
 return feedRes.json() }) }
  6. // avg response time is ~200ms const feedTimeout = 250

    pTimeout( loadFeed, feedTimeout ) .then(onSuccess) .catch(onError)
  7. // avg response time is ~200ms const feedTimeout = 250

    const retries = 2 pRetry( () => pTimeout(loadFeed,feedTimeout), { retries } ) .then(onSuccess) .catch(onError)
  8. // avg response time is ~200ms
 const feedTimeout = 250

    const totalTimeout = 700 const retries = 2 pTimeout( pRetry( () => pTimeout(loadFeed, feedTimeout), { retries } ), totalTimeout ) .then(onSuccess) .catch(onError)
  9. // I have 100 queries to run const queries =

    […] const pLimit = require(‘p-limit’) // Only 10 promises at a time const only10 = pLimit(10) const promises = queries.map(q => { return only10( () => fetchAnalyticsQuery(q) ) }) Promise.all(promises).then(onSuccess)
  10. const sleep = require('then-sleep') // Or something a bit simpler

    while (condition) { await runAnalyticsQuery(...) await sleep(250) }
  11. other cool ideas • reducing bursts with jittering: then-sleep, p-defer

    • priority queues: p-queue • circuit breaking: opossum
  12. but they also have limitations • cancellations • error handling

    can be tricky • stack traces aren’t perfect