The Single CLI

The story of Single's CLI that we use to administer our system -- written in Go and built in Docker


3 min read
The Single CLI

In the earliest days of Single we had no good way of administering our system. If we needed to make modifications to data that couldn’t be done by interacting with the customer-facing UI, I had to execute database queries on the database server manually. If there was some back-end process that needed to be triggered to replay actions or fix a failed process, I would make endpoints in the API and hit them with a REST client like Postman. While both of those things will work for the most part, they’re time-consuming and error prone at best.

It was clear we needed a better way to administer our system. But, without enough time or developer resources (we’re a very small team), we weren’t able to build an administration UI for these kinds of tasks. So, I decided to build a CLI (command-line interface) that we could use to easily query data and perform common maintenance tasks. Here's some of the most basic commands:

$ single version
single version 4.1.0 [ tammy ] built on 2019-07-12_06:10:16PM

$ single -h
The Single CLI

Usage:
  single [flags]
  single [command]

Available Commands:
  7digital          7Digital Operations
  account           Operations on accounts
  album             Operations on albums
  album-product     Album product commands
  artist            artist operations
  bill              Account bill operations
  billing           Operations on billing
  boostlink         Boostlink Operations
  boostlink-type    Boostlink Type Operations
  buzzangle         Buzzangle Report Operations
  cascading-track   Cascading Track operations
  code              Download Code operations
  email             Email history
  help              Help about any command
  job               Operations on scheduled jobs
  login             Login to Auth0
  order             Operations on orders
  physical-album    Operations on physical albums
  purchase          Purchase history
  set-env           Set the environment in config.
  shopify           Shopify Operations
  short-link        Link shortening operations
  soundscan         Soundscan Report Operations
  storage           file storage and processing operations
  track             Operations on tracks
  trigger           Operations on scheduled job triggers
  user              Operations on users
  variant-migration Variant Migration Commands
  version           Print the version of the CLI
  white-label       Operations on white labels

Flags:
  -h, --help   help for single

Use "single [command] --help" for more information about a command.

Today, the CLI has evolved to be the Swiss army knife of our system. We use it to update incorrect data on releases, trigger failed processes to run again, re-play event streams from Shopify, and query for data when troubleshooting, among other things. The CLI is our main window into the state of our system.

From a technical perspective, the CLI acts as a client to our back end APIs. Input data is passed to commands as flags and arguments. Data is then returned in JSON format (with some tabular and text-based exceptions). Almost every API endpoint in our system is accompanied with a corresponding CLI function. I’ve even ended up using the CLI as a testing tool — to exercise parts of the system as I’m building them. The configuration is set up to be switchable between environments, so we can execute commands against production, staging, and local environments.

What’s interesting about this CLI approach is that the executable can be easily combined with existing command-line tools to extend its functionality. Because the output of most commands is in JSON format, jq can be use to re-format, filter, and search the data. For example, here’s a command for loading basic information about an account:

$ single account summary -d single-fh-dev-3
{
  "accountId": 1251242141,
  "active": true,
  "myshopifyDomain": "single-fh-dev-3.myshopify.com",
  "name": "single-fh-dev-3",
  "shopifyChargeApproved": true,
  "users": [
    {
      "accountUserId": 125122457541,
      "email": "taylor@singlemusic.co"
    },
    {
      "accountUserId": 547345632564,
      "email": "admin@singlemusic.com"
    }
  ]
}

Now, lets say we just want the email addresses associated with the account (kind of a silly example in this case, but you get the idea). Using jq the command and output become:

$ single account summary -d single-fh-dev-3 | jq -r '.users[] | .email'
admin@singlemusic.com
taylor@singlemusic.co

As another example, we can use grep and wc to count the total number of accounts from the command that lists all the accounts like so:

$ single account all | grep accountId | wc -l
436

Because the CLI executes in a shell, we can also use shell scripting to create all kinds of functionality--using the output of certain commands as input for others, looping over files, etc.  Scripts can of course be saved for re-use as well.

The Single CLI is written in Go, using the cobra framework with viper for configuration. Our continuous integration system runs the Docker-based build process that builds a binary executable which is then shipped to an artifact repository so our internal users can simply download it to run it — with a little configuration setup.

So, if you find yourself in need of some administration tools for your API, and don't have enough time to make a UI, consider creating a CLI for those tasks. There's a little bit of a learning curve for less-technically-inclided people, but they'll eventually get the hang of it and be productive.  Structure your output in JSON or some other easily-computer-consumable format so that you can combine it with other CLI tools to extend functionality

Related Articles

Maven-Based Docker Projects
6 min read

Back To Top

🎉 You've successfully subscribed to Single Technology!
OK