Parsing JSON from the command line

You can do it with Python and keep it on a single line and zero dependencies

I have this thing I do every day. And every day I wade through menus and sub menus, and it's tedious, just to get a simple discount coupon for students who want to use Rotato. Wouldn't it be cool to just be able to paste it?

Selecting it immediately pastes this

Hi there! You can now take 50% off with the coupon STUDBC93246
when you purchase Rotato.

That's what I built. I activate Alfred, type a few characters, hit enter, and I get a full sentence pasted into any text field, anywhere, not relying on integrations in my CRM system. And, since Alfred lets you back up your settings to Dropbox, it follows me everywhere. Just one problem: to be truly portable, it can't be an app or a script elsewhere on my computer. It had to be a script. And that script should return just the coupon, so Alfred can wrap its sentence around it and paste it.

Getting to work

Okay, for this to work the whole thing must work something like this:

  • Recognize the keyword
  • Generate a coupon using Paddle's REST API using POST, and extract the coupon from the JSON
  • Wrap that coupon in a friendly string (the "Hi there!" bit)
  • Paste it

We'll start with the hardest part, generating the coupon with a

Calling the API

From Paddle's reference, we can see that we can grab a coupon with curl like so:

curl -s -X POST \
-d 'vendor_id=VENDOR' \
-d 'vendor_auth_code=AUTHCODE' \
-d 'coupon_type=checkout' \
-d 'coupon_prefix=STU' \
-d 'num_coupons=1' \
-d 'discount_type=percentage' \
-d 'discount_amount=50' \
-d 'allowed_uses=1' \
-d 'expires=2022-10-01' \
https://vendors.paddle.com/api/2.1/product/create_coupon 

And the output is this JSON

{"success":true,"response":{"coupon_codes":["STU7A90886F"]}}

With that done, we only have one big hurdle left: how do we parse that JSON the safest and most efficient way?

Parsing JSON with a one-line shell command

Now we need to get just the coupon, and leave the JSON clutter in the dirt. Here's how we'll do it: with Python, and more precisely, a tiny Python script. Sure, we could do regular expressions and grep or sed, but why not use something that really understands all the quirks of json?

Here it is, reduced to a single line:

import sys,json;obj=json.load(sys.stdin);print(obj['response']['coupon_codes'][0]);

Notice the sys.stdin bit? That's us getting ready to read the piped input from the curl command.

curl -s -X POST \
-d 'vendor_id=VENDOR' \
-d 'vendor_auth_code=AUTH' \
-d 'coupon_type=checkout' \
-d 'coupon_prefix=STU' \
-d 'num_coupons=1' \
-d 'discount_type=percentage' \
-d 'discount_amount=50' \
-d 'allowed_uses=1' \
-d 'expires=2022-10-01' \
https://vendors.paddle.com/api/2.1/product/create_coupon | python -c "import sys,json;obj=json.load(sys.stdin);print(obj['response']['coupon_codes'][0]);"

Run this, and the output is nothing but the coupon. Sweet. This is already pretty useful, but let's take it to the next level: the Alfred level.

Using the shell script in Alfred

We'll start from the top. In our to-do list above, we said that this should trigger on entering a keyword in the Alfred search bar. So that's our starting point.

We'll go to the Workflow section of the Preferences and open a blank workflow, then add our keyword trigger by right clicking, choosing Inputs, and then Keyword.

Setting up a trigger

Then, we'll fill out the form with the standard stuff it asks about:

The Subtext part is the stuff that Alfred will show you right under the action's title. Here, we're using is as a kind of warning for what's coming.

Okay, the trigger is ready to go. Next, let's tell Alfred what to do when we trigger the action.

Running the script

But wait, where should we save the script we made? Nowhere - that's where! Like I said, we want to make this  setup as portable as possible.

Paste your JSON decoding script and hit Save

Okay, last step is actually pasting the code along with the surrounding words that make up the entire friendly sentence.

(Copy and) paste the output of the script

Write whatever you want, and place {query} where you want the output - in our case, the coupon - of the script to appear.

Connecting it all

Our workflow now looks like this

Three lonely boxes. Let's connect them. Drag the little handle from one box to the other so you get this:

Try it out

Go to a text field - any text field - and activate Alfred and begin typing your trigger keyword. Select it, and there it is!

To me, this not only boosted my productivity, but also made me dread the task less. That's the hidden side of automation: bring a little joy into your daily workflows.