Article

How to Make a Development Faker JSON API Server

Most modern Javascript based front-end frameworks thoroughly entangle layout and styling by depending heavily on CSS to achieve both. I’ve been building some prototypes that don’t use CSS at all in an effort to decouple layout and styling.

Matt Griffith is the author of Elm-UI, a new language for layout and interface, which is gaining traction in the Elm community to address this problem. I love Elm as a functional language but it does the same thing when using the Html package along with CSS, whether provided in-line, through a package, or even importing dot CSS files. Matt believed that layout and style can be treated independently, created an Elm package to support his approach, and gave a talk about his quest to Build a Better Design Toolkit.

Left: A stamp of the word FAKE. Right: A fake visa credit card with a chip, belonging to PETER PAN.

Getting Started

I started building on Alex Korban’s chat layout and wanted to fill the chat pane with fake data so that I could easily see how changes to how I used Elm-UI would be rendered. If I was using a Javascript framework, I could simply import faker.js and quickly mock up some fake chat messages. But this is Elm, a pure, functional language, and generating random data in an Elm app is sort of against the idea of purity. Maybe one day someone will create a faker type package for Elm but I’m not holding my breath. In the meantime, I can query an API from an Elm app to get fake data, so why not build a simple API server that serves up fake data as if I was using faker.js directly?

A large di with question marks on all sides in place of numbers. A red button with the word RANDOM! Mr. Bean's Argentinian passport.

Building the faker JSON server

A quick search on npmjs turned up JSON-server. This is almost perfect and indeed is often used to serve fake data from a pre-built file like this. This is all right from the docs:

{ "posts": [ { "id": 1, "title": "json-server", "author": "typicode" } ], "comments": [ { "id": 1, "body": "some comment", "postId": 1 } ], "profile": { "name": "typicode" }}

Save that to db.json and then serve with

json-server — watch db.json

Now you'll get

{ "id": 1, "title": "json-server", "author": "typicode" }

But I wanted to serve fake data defined by the route. So what should the API look like?

Define the API

I decided early on to mimic the faker.js API as much as possible. I wanted mappings like this:

faker.js API-------------faker.random.number()faker.random.number(10)faker.random.number({min:2,max:5})faker.name.firstName()faker.fake("noparse_38fcb1ad15de6ee3c7ba1e7bb6c7a876, noparse_592c8c897b7a14ecc0eb57907e2ac4ee")faker.helpers.randomize(["one", "two", "three"])map to:faker server URL path-----------------/faker/random/number/faker/random/number?10/faker/random/number?{"min":2,"max":5}/faker/name/firstName/faker/fake?noparse_34079f3ee7a1707cd6e2ae1233b7f4dd,%20noparse_b987f97ac34fcbe9db0a0b0cfa7e180c/faker/helpers/randomize?("one","two","three")

A faker function is mapped to a string path by replacing the dots in the function to slashes. The query string (everything to the right of the question mark) is treated as arguments passed to the faker function. The faker function is called without arguments when there is no query string.

The first three examples show how to generate a random number optionally passing none, a single value, or an object as arguments. The third example describes the syntax to pass an object as the argument.

The fourth example generates a random first name while the fifth generates a composite last name, comma, space, first name.

The fifth example illustrates how to use faker.fake with mustache support. One or more functions are specified in dot notation without arguments and surrounded by double curly braces. The faker.js API wraps the arguments as a double-quoted string whereas the server API omits the double quotes and URL encodes any spaces. This form is a bit clumsy but it allows you to create a composite fake value from more than one primitive.

The final example shows how to pass an array of values as an argument. The spec for a query string does not allow square brackets and since we do not specify function parameters with parens in the server API, we coopt parens to indicate an array.

By far, most of faker.js APIs are simple values. The faker.fake (5th example) form allows for composite fakes built from simple primitive values. The faker.helpers.randomize (6th example) may be used to randomly choose one value out of many.

Caution, some of the query string tokens such as curly braces and spaces must be urlencoded. It is usually only the query string where this is an issue but it is always safe to urlencode the entire path when sending a request.

All requests are simple GET requests with an optional query string. We do not use query parameters at all. The server API is therefore pretty simple and enables the vast majority of faker.js functions with optional arguments.

Things Learned Along the Way

Defining a server API that mimics the faker.js API was not obvious. The lack of square brackets was a surprise. Exposing the faker.fake API was the most challenging as faker.js treats the argument as decorated function calls based on a syntax that resembles Blade, Vue, and React templates.

Translating an API path to a function call with dot notation was challenging. Javascript has no way to call a function given a string value representation of it without invoking eval. However, given access to the root object, you can specify a child with strings by using the form:

root['a']['b']['c']

which is the same as:

root.a.b.c

This enabled me to handle all the faker API variants with a single function.

/** * Service a faker request /server.get('/faker/', (req, res) => { const path = req.path const query = req.query const tag = path.split('/').pop(); const fn = path.split('/').slice(2).reduce((acc, cur) => { return acc[cur] }, faker); const key = Object.keys(query)[0] const parseOpts = args => { try { return JSON.parse(args); } catch (e) { return args } } // options as array in form of (arg, arg ...) let opts if (typeof key === 'string' && key.match(/^(.)$/)) { opts = key.match(/^((.))$/)[1].split(",").map(parseOpts) } else { opts = typeof key === 'string' ? parseOpts(key) : key } let result try catch (e) { result = 'exception: ' + e.message } res.status(200).jsonp({ path, tag, opts, result, });});

The faker function reference is created by reducing the path components building on the real faker object passed as the second parameter to reduce().

const fn = path.split('/').slice(2).reduce((acc, cur) => { return acc[cur] }, faker);

A Little Bit of Fakery Makes it More Better

Here is the chat app prototype with a bunch of fake message posts. Thanks to Alex Korban for the initial version.

Fake message posts from the chat app prototype with time stamps, author names, and messages.

Find on github

simple-faker-json-api-server

Download, build, and run:

git clone https://github.com/stuheiss/simple-faker-json-api-server.gitcd simple-faker-json-api-serveryarn && yarn start---

Download “The Essential Guide to Launching a Digital Product for Experts & Expert Firms”

Let's Talk
Tell us about the opportunity you're pursuing, and we'll follow up in one business day. If you prefer, you can email ask@highlandsolutions.com.