This is part of a series of articles. Read the other parts here:
- Building a command line tool with Go and Cobra
- Adding flags to a command line tool built with Go and Cobra
Prerequisites
In this tutorial, we will learn how to add flags to a CLI tool built with Go and Cobra. In the first part of this tutorial series, we created a dad joke command line application that gives us a random dad joke right in our terminal. In this second part, we will be learning how we can use a flag to retrieve dad jokes that contain a specific term.
If you did not follow the first tutorial, but would like to follow along with this tutorial, you can use the finished code from the first part as your starting point. You can find that in the repo for the first tutorial.
Adding a flag
If you’re familiar with command-line tools, you will recognise the use of flags. A flag provides a way for the user to modify the behaviour of a command. In this tutorial, we will be modifying the random
command to allow us to search for a random joke that includes a specific term
.
Cobra has two types of flags:
- Persistent flags - available to the command it is assigned to, as well as all its sub-commands
- Local flags - only assigned to a specific command
Our example is small enough that this distinction does not have a real impact. We will, however, choose to apply a persistent flag because in an imaginary future, we’d like all sub-commands of random
to be able to take in a term
.
In the init
function of our cmd/random.go
file, we can add a persistent flag. We have named it term
and given it a description:
|
|
That’s all it takes to add a flag to a command. There are several ways we can make use of this flag. Here’s how we will approach it:
- First we check for the presence of a term
- If the
random
command was run with theterm
flag, we will run a function that knows how to handle search terms - But if the
random
command is run without any flags, we will run another function that merely returns a random joke, without knowing anything about search terms. This function is calledgetRandomJoke()
and was created in the previous tutorial
Let’s put together the initial skeleton of the function we need to handle search terms. In cmd/random.go
, we will add this new function. For now, all it does is print out the search term to the terminal. We will build up the function as we proceed:
|
|
Now we can move on to check whether the user has used the term
flag. In the Run
function of our randomCmd
, we can add the following check:
|
|
What’s essentially happening here is:
- We are getting the value from our
term
flag and storing it in the variablejokeTerm
- If the
jokeTerm
value is not empty, we will run ourgetRandomJokeWithTerm
method and pass thejokeTerm
value in to it - Else if
jokeTerm
is empty, we’ll just get a random joke by runninggetRandomJoke
. Again, this was a function we created in the previous article.
Now we can go into our terminal and run the random command with and without the term
flag:
|
|
Understanding the response
As a reminder, we are using the icanhazdadjoke API for all our jokes data. If we take a look at the API documentation, we can see that we can pass a search term to our request
We can run the example curl command in our terminal:
|
|
We can represent the JSON response as a struct in our code:
|
|
Get data with search term
Now that we have a better understanding of the data that we’ll be working with, let’s move on and create a method get the data.
First we will need to create a skeleton method. To begin, we just want to be able to pass a search term to which we can pass in to the API call.
|
|
In the previous article, we had already created a method that helped us to get joke data. We even creatively called it getJokeData()
. This method takes in an API url
as it’s only argument. Within the body of our newly created getJokeDataWithTerm
function, we can add the following lines:
|
|
Then we want to unmarshal the returned responseBytes
, following the shape of the SearchResult{}
struct
|
|
Unmarshalling the responseBytes
gives us the Results
as json.RawMessage
. We will have to unmarshal this raw JSON, following the shape of Joke{}
, which is a struct we had created in the first article.
Our Results
may often contain more than one joke. We can store all the jokes in a []Joke{}
(slice of Joke{}
).
|
|
Next, we’ll want to return all the jokes we process using this method. We also want to know how many jokes we got back as well. We can update the function to be able to return these two values:
|
|
Now that our getJokeDataWithTerm
function is fleshed out, we can use it within our getRandomJokeWithTerm
function. Replace the contents as follows:
|
|
For the time being, we throw away the totalJoke
value by using an underscore (_
). We are only doing this for demonstration purposes, so fret not, we will use it in the next section.
Randomising the search results
If we head into the terminal now and test our command, we just keep getting all the search results.
|
|
This isn’t really what we’re going for. We want to be able to get one random joke that contains a specified search term each time we run the command with the flag. We can achieve this by introducing a function to randomise our results.
First, though, let’s import a couple of packages
|
|
Then we can write a skeleton randomiser function:
|
|
Our randomiseJokeList
function takes in 2 arguments:
length
- to be used as the ceiling for our random rangejokeList
- the data we want to randomise
We can update our randomiseJokeList
method with the following code:
|
|
Here’s what’s going on in the above code snippet:
- We are getting a random value within a range
- If the number of jokes is less than or equal to zero, we let the user know that we weren’t able to find any jokes with that term
- But if there are jokes present, then we print out a random one
With our newly created randomiseJokeList
function all complete, we can return to our getRandomJokeWithTerm
function and update it:
|
|
If we go into our terminal and test our flag now, we will be able to get a random dad joke that contains a specified term:
|
|
Distributing your CLI tool
Everybody likes a good dad joke from time to time, so I’m sure your friends will want to use your tool. We will be able to distribute this dadjoke CLI tool as a Go
package. In order to do this:
- Upload your code to a public repo
- Install it by running
go get <link-to-your-public-repo>
e.g.go get github.com/example/dadjoke
Then you will be able to run your tool like this:
|
|
Conclusion
In this tutorial we learnt how to extend our dadjoke CLI tool so we could implement a flag for our random command. You’ll be able to find all the code in the github repo.
Congratulations, you did great. Keep learning and keep coding. Bye for now.