Introducing jaycue - jq in your JS

jaycue logo

Shout out to my son for making the logo! Nice work Joseph!

Previously, I wrote about how useful lodash is when working with JSON in JavaScript. Then we took a look at how to deal with JSON from the command line using the power of jq.

It should come as no surprise where I’m headed here: I want the power of jq filters in my JavaScript code!

Off we go

Instead of doing what I normally do: googling to see if it existed, then getting depressed that it wasn’t unique, I decided to just do it. I thought it would be a fun way to do a little test-driven development, which I kinda miss doing.

I figured that if I could find a way to write a test and run it against my code, grab the output, run it against jq proper, then compare the results, it’d prove that my code was doing what it should.

I’ve executed shell commands from Node.js before, so it seemed doable.

> const exec = require('child_process').execSync;
undefined
> let command = `echo '{"foo": 123}' | jq ".foo"`
undefined
> exec(command).toString();
'123\n'

Cool. That was easy enough. So, in an attempt to make it more generic for a utility method that I can use in the tests, I should be able to do something like:

> let command = `echo '${json}' | jq "${filter}"`

and pass any JSON string and any filter, then collect up the result, and compare!

My goal is to make a function that would allow me to perform an expectation like:

expect(myjq(jsonObject, filter))
    .toEqual(jq(jsonObject, filter));

Check it out here: https://github.com/olore/jaycue/blob/master/tests/test-helper.js#L22

Now that we can test, let’s code!

Once that was in place, it was a matter of choosing which types of filters I wanted to support first. From the documentation, there are A LOT. I decided to go after the ones I would use most often, and expand from there. In particular, there was a single use case I wanted to solve. But to get there, I had to start with the basics.

The “basic” filters could be serviced by lodash.get. For instance, both “versionString” and “.versionString” will work with

lodash.get("versionString");

I would just need to chop off the leading period. Something like “name.firstName” would also work with lodash.get.

From there, I started down the list of Basic Filters. Adding in array indexing and eventually “select” filtering, which was the last piece of the puzzle for the use case I had in mind.

Here it is:

{
  "applicants": [
    {
      "identities": [
        {
          "type": null,
          "number": null
        },
        {
          "type": "SSN",
          "number": "987651234"
        }
      ]
    }
  ]
}

We need to get the “number” whose type is “SSN”, if it exists.
We had code that looked like this:

const ssn = get(data, 'submit.applicants[0].identities', [])
  .reduce((accum, identity) => {
    if (identity.type === 'SSN' && identity.number) {
      accum = identity.number;
    }
    return accum;
  }, '');

Whereas, a jq command like this would work:

cat test.json | jq '.applicants[0].identities[] | select(.type=="SSN") .number'

Now that we had select functionality, this get/reduce JavaScrit code from above could be replaced with:

const ssn = jq(data, '.applicants[0].identities[] | select(.type=="SSN") .number');

And just like that, we’re successful!

Wrapping up

Please go install jaycue and let me know what you think:

npm install jaycue

A big shout-out to my 13yo son for making the jaycue logo! It was a true, family effort. Nice work Joseph!

I hope you have found this useful. I’d love to hear about what features of jq you think should be added next. And as always, I’d love to have you contribute to the jaycue project!

jq: The JSON CLI tool

Thanks to lodash, manipulating JSON from JavaScript is easy. Sometimes we’re working with chunks of JSON and it’s easier to deal with it from the shell. Scenarios like this include digging through log output and that (sometimes painful) time when you are first interacting with a new API.

Working with JSON in the shell is quicker and easier than trying to create a temporary file in your project or IDE, then writing some JavaScript code to open that file, parse its contents and scan for whatever it is you are looking for. Those of you that are skilled with the Node.js shell may disagree, but I’m out to optimize your workflow too!

Hello jq

jq is a CLI (command line interface) for working with JSON. It provides shell friendly features (piping, output redirection, etc) that make it feel as if it’s part of your operating system.

To get started, install jq (on OSX)

brew install jq

Or install it directly from the site

Running the jq command by itself will provide some usage info, but not a ton. You’re going to want to head to the online manual, or the man page (man jq).

Let’s see what jq can do!

jq is normally invoked by “piping” JSON data to it (using the | operator). This can be as simple as an echo command. Here we’ll use the simplest filter ., “which copies jq’s input to its output”.

echo '{"name": "Brian"}' | jq '.'
{
  "name": "Brian"
}

By default, jq will pretty print and colorize its output. Neat!

Because it works with pipes, you can also use commands like curl to get an API response, then pass it through jq like so:

curl https://swapi.co/api/people/1/ | jq '.'
# Run this yourself to see output, it's too long to post here

As you can see this can be very useful when you need a quick sanity check of an API response structure, or if you forget if the key name is eyeColor or eye_color.

jq does more than pretty formatting! It let’s you slice & dice the JSON in many ways. For instance, let’s ask jq to return Luke’s eye_color

curl https://swapi.co/api/people/1/ | jq '.eye_color'
"blue"

Cool!

Thankfully, similar to lodash.get, if we ask for a path that doesn’t exist, it doesn’t die a horrible death

curl https://swapi.co/api/people/ | jq '.does.not.exist'
null

Let’s get more advanced

What if we wanted to get the eye_color of all the people (on the first page of results)? Again, jq provides a syntax similar to lodash.get:

curl https://swapi.co/api/people/ | jq '.results[].eye_color'
"blue"
"yellow"
"red"
"yellow"
"brown"
"blue"
"blue"
"red"
"brown"
"blue-gray"

OK, let’s see if we can make it work a little harder. Let’s get the name of all the people (on the first page of results) that have and eye_color of blue?

curl https://swapi.co/api/people/ | jq '.results[] | select(.eye_color == "blue") .name'
"Luke Skywalker"
"Owen Lars"
"Beru Whitesun lars"

Sweet! This is where the power of jq really shines. There are many more powerful filters, operators and functions I suggest you explore. Hopefully I was able to whet your appetite as this is just the tip of the iceberg of things you can do with jq.

One more

One last quick tip - this is the one I use for making sense of my JSON log messages all the time. If you are in OSX, you have the ability to access the clipboard from the shell using pbcopy and pbpaste. So when I am working with JSON logs, from an application like Splunk, I copy the relevant JSON structure to the clipboard, then run it through jq like this:

pbpaste | jq '.'

The pretty printing alone is super useful. On top of that, you have all the great filtering commands to coerce an intimidating log message into a more approachable piece of data!

Special thanks to https://swapi.co/ for providing a fun API to play with!