DEV Community

David Wells
David Wells

Posted on β€’ Originally published at davidwells.io

4 1

Mocking chainable APIs with ES6 JavaScript Proxies

Originally posted on davidwells.io πŸŽ‰

ES6 proxies are pretty crazy.

Proxies give you the ability to intercept object calls and do pretty much whatever you want with them 🀯.

I highly recommend checking out this video from Michel Weststrate, the creator of immer, for a super deep dive on ES6 proxies and everything you can do with them.

Beware of proxies he warns, they are cool but can potentially lead to some back debugging issues.

Anywho, onto the use case...

How to mock a chainable API

I came across the need for replacing a chainable API inside the netlify-cli for the chalk module.

We needed a global mechanism for disabling terminal colors made with chalk.

There is a setting for this in chalk but that's the easy road out. We are a developer and we must re-invent the wheel. Also, wasn't working for my version of chalk...

So... Let's try some proxies!

First, what is a chainable API?

// Methods can chain together in any order
chalk.blue.bgRed.bold('Hello world!')

There are lots of libraries out there that allow for this type of flexibility.

You can actually use proxies to create chainable APIs

Proxy time

Thanks to safe-object-proxy, I found a proxy implementation that ensures that objects never throw errors if the keys on that object don't exist.

So no more this:

whatever.haha.yolo()
// Uncaught TypeError: Cannot read property 'yolo' of undefined

Instead, the proxy will magically make the function return null.

Pretty cool

There is a similar project out there called nevernull that comes packed with polyfills if you are running proxies in the browser.

With a little tweaking, console logging, & scratching my head on WTF proxies do, I managed to have the chainable API return my values no matter what.

Success πŸŽ‰

// safeChalk.js
const chalk = require('chalk')

/**
 * Chalk instance for CLI
 * @param  {boolean} noColors - disable chalk colors
 * @return {object} - chalk instance or proxy noOp
 */
module.exports = function safeChalk(noColors) {
  // if no colors return chainable "noOp" API
  if (noColors) {
    return NeverNull(chalk)
  }
  // else return normal chalk library
  return chalk
}

/* Chalk NoOp proxy */
function NeverNull(obj) {
  function match(some, none = noOp) {
    return obj != null ? some(obj) : none()
  }
  return new Proxy((some, none) => {
    /* Here was my tweak to make this work with chalks chainable API */
    if (some) return some

    if (!some && !none) return obj
    return match(some, none)
  }, {
    get: (target, key) => {
      const obj = target()
      if (obj !== null && typeof obj === 'object') {
        return NeverNull(obj[key])
      } else {
        return NeverNull()
      }
    },
    set: (target, key, val) => {
      const obj = target()
      if (obj !== null && typeof obj === 'object') {
        obj[key] = val
      }
      return true
    }
  })
}

function noOp() {}

And then using it

const safeChalk = require('./safeChalk')
/**
 * Usage
 */
const disableChalkColors = true
const myChalk = safeChalk(disableChalkColors)

console.log(myChalk.blue.bgRed.bold('Hello world!'))
// 'Hello world!' no coloring

const normalChalk = safeChalk()

console.log(normalChalk.blue.bgRed.bold('Hello world!'))
// 'Hello world!' blue text with red BG that is BOLD

We did it! The chainable API works no matter what!

Wrapping up

As you can see, the proxy is tiny and pretty powerful.

I'd recommend heeding Michael's word of warning with proxies. They are a bit "magical" and debugging proxies looks like a bad time.

What other use cases for proxies have you seen? Leave a comment below

SurveyJS custom survey software

Simplify data collection in your JS app with a fully integrated form management platform. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more. Integrates with any backend system, giving you full control over your data and no user limits.

Learn more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more