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

JavaScript UI Library for Surveys and Forms

Generate dynamic JSON-driven forms directly in your JavaScript app (Angular, React, Vue.js, jQuery) with a fully customizable drag-and-drop form builder. Easily integrate with any backend system and retain full ownership over your data, with no user or form submission limits.

View demo

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay