Getting started with CLI's using Golang.
Tags: go, cobracli, cli, backend
Published: 2023-01-01 16:54:46

## Introduction :

In this blog we are going to get started with CLI using [Golang](https://go.dev/) and [Cobra CLI](https://cobra.dev/). We are just going to make a simple Quiz game CLI and get friendly with the Cobra-CLI library.

## Why Cobra-CLI?

[Cobra](https://cobra.dev/) is both a library for creating powerful modern CLI applications and a program to generate applications and CLI applications in Go. Cobra powers most of the popular Go applications including CoreOS, Delve, Docker, Dropbox, Git Lfs, Hugo, Kubernetes, and many more. With integrated command help, autocomplete and documentation.

## Prerequisites :

To continue with tutorial, firstly you need to have Golang and Cobra-CLI installed.

### Installation :

- [Golang](https://golang.org/)
- For installing Cobra-CLI you can go to [Cobra](https://cobra.dev/) or run `go install github.com/spf13/cobra-cli@latest` in the terminal.


## Initializing the Project

After completing the Installation part to get started make a folder for eg. `go_quiz` , run the given command

```
go mod init github.com/Siddheshk02/go_quiz
```
In place of `Siddheshk02` use the name in which your project directories are. Now the structure will look like this

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bzc0zt6vpz4i5hxkmere.png)

```
Cobra-cli init
```
This command initializes the CLI and make a `main.go` file along with `cmd` folder containing `root.go`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v7xapg6y0erdoeh9y7iv.png)

The `main.go` file will have the following code,

```
package main

import "github.com/Siddheshk02/go_quiz/cmd"

func main() {
    cmd.Execute()
}
```
This means the main cli commands implementation will be in `cmd` which is called through `main.go`.

Make the following changes in the `root.go` file.

```
package cmd

import (
    "os"

    "github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
    Use:   "go_quiz",
    Short: "A Simple Quiz game CLI",
    Long: `A Simple Quiz game CLI using Golang.`,

}

func Execute() {
    err := rootCmd.Execute()
    if err != nil {
        os.Exit(1)
    }
}

func init() {
    rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
```
In `root.go`, function `Execute` gets called from `main.go` and it executes the `rootCmd`. `Use` is used to define the command to be used and `Short` and `Long` contains the information or description for the Command in short and long format respectively.

Now run `go run main.go` or `go build .` and `.\go_quiz` or `go_quiz`.

```
C:\Users\Admin\Go\src\github.com\Siddheshk02\go_quiz> go run main.go
A Simple Quiz game CLI using Golang.
```

```
C:\Users\Admin\Go\src\github.com\Siddheshk02\go_quiz> go build .
C:\Users\Admin\Go\src\github.com\Siddheshk02\go_quiz> .\go_quiz
A Simple Quiz game CLI using Golang.
```

```
C:\Users\Admin\Go\src\github.com\Siddheshk02\go_quiz>go_quiz -h       
A Simple Quiz game CLI using Golang.

Usage:
  go_quiz [flags]
  go_quiz [command]

Available Commands:
  completion  Generate the autocompletion script for the specified shell
  help        Help about any command
  start       Starting a new Quiz

Flags:
  -h, --help     help for go_quiz
  -t, --toggle   Help message for toggle

Use "go_quiz [command] --help" for more information about a command.
```
Now let's make a csv file `data.csv` in the `go_quiz` directory, to store the questions and answers for the quiz.

Store the following values in the file.

```
5+5,10
7+3,10
1-1,0
8+3,11
1+2,3
8-6,2
3-1,2
1+4,5
5-1,4
2+3,5
3+3,6
7-4,3
5+2,7
9-2,7
4+8,12
1+8,9
```
Lets make a new command which will be used to start a Quiz.

for adding a new command run this code `Cobra-cli add start`, here `start` is the new command made.

This will create a new file `start.go` in the cmd folder.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/by159bn7yrwk6rbc59ic.png)

Make the following changes in the `start.go` file

```
package cmd

import (
    "fmt"

    "github.com/spf13/cobra"
)

var startCmd = &cobra.Command{
    Use:   "start",
    Short: "Starting a new Quiz",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("start called")
    },
}

func init() {
    rootCmd.AddCommand(startCmd)
}
```
let's try running our new command. Run `go build .` in the terminal and then run `go_quiz start`

```
C:\Users\Admin\Go\src\github.com\Siddheshk02\go_quiz>go_quiz start    
start called
```
you can also try running `go_quiz start -h`.

Now, for the main implementation of the Quiz game, we will make a folder pkg in the project directory i.e. `go_quiz` and a file `quiz.go` in the pkg folder.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/opdkg3tllzf1c7j0vr3y.png)
In the `quiz.go` make a function `Quiz` that returns a string `res`

```
func Quiz() (res string) {

    return res
}
```
This function will be called in the `start.go` as :

```
Run: func(cmd *cobra.Command, args []string) {
        res := pkg.Quiz
},
```
Now, let's code in the `Quiz` function in `quiz.go`

Firstly, we need to open and read the `data.csv` file to get the questions and there answers.

```
package pkg

import (
    "encoding/csv"
    "errors"
    "fmt"
    "io"
    "log"
    "os"
    "strconv"
)

func Quiz() (res int, err error) {
    res = 0

    f, err := os.Open("C:/Users/Admin/Go/src/github.com/Siddheshk02/go_quiz/data.csv")
    if err != nil {
        log.Fatal(err)
    }

    defer f.Close()

    csvReader := csv.NewReader(f)
    var ans int
    for {
        rec, err := csvReader.Read()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatal(err)
        }

        fmt.Print(rec[0] + " : ")

        c, _ := strconv.Atoi(rec[1])

        fmt.Scanf("%d\n", &ans)

        if ans == c {
            res = res + 1
            fmt.Println("correct")
            continue

        } else {
            err = errors.New("Incorrect Response!!")

            break
        }

    }
    return res, err
}
```
Here, we are taking the questions and answers in `rec` which is a string array, so for each iteration in the loop the `rec` array takes question in `rec[0]` and answer in `rec[1]`.

Then for comparing the user input `ans` with the original answer i.e. `rec[1]`, we first convert `rec[1]` into integer type as `ans` is in integer whereas `rec` is string.

A `res` variable is created to store the result count, which is returned along with `err` error after completing the quiz or after giving an Incorrect response.

So, the `start.go` will look like the following code after all changes :

```
Run: func(cmd *cobra.Command, args []string) {
        res, err := pkg.Quiz()
        if err != nil {
            fmt.Println(err)
            fmt.Printf("Your Score is %d", res)
        } else {
            if res == 16 {
                fmt.Println("Congrats!, you got all questions Correct")
            }
            fmt.Printf("Your Score is %d", res)
        }
    },
```
Now, run `go build .` and then `go_quiz start` to test the CLI.

```
C:\Users\Admin\Go\src\github.com\Siddheshk02\go_quiz>go_quiz start 
5+5 :
```
Enter the answers after getting the question :)

If all the given responses are correct

```
.
.
.
1+8 : 9
correct
Congrats!, you got all questions Correct
Your Score is 16
```
And if any of the response is Incorrect :(

```
.
.
7+3 : 10
correct
1-1 : 0
correct
8+3 : 1 
Your Score is 3
```
The complete code is saved on [GitHub](https://github.com/Siddheshk02/go_quiz)

## Conclusion :
In this tutorial we learnt how to create a command-line application with Go and Cobra. In the next upcoming tutorial , we will learn how to add flags, commands, etc. and build more such amazing stuff.

If you enjoyed this article and you'd like more, consider following [Siddhesh on Twitter](https://twitter.com/siddhesh1102) to get the latest updates.

Congratulations🎉, you did great. Keep learning and keep coding :)