[Golang] How to parse the JSON arguments from the Command-line flags

parse json arguments from command-line flags

Passing the JSON argument via the Command-line flag seems to be not typical, but we may need it in some cases. This post will show you how to implement it in Golang.

The package flag provides an easy way to implement it. Let’s take a look at a simple example of using package flag first:

package main

import (
	"flag"
	"fmt"
)

func main() {
	var version string

	// parse the value of the flag setVersion to variable version
	flag.StringVar(&version, "setVersion", "1.0.0", "")  
	flag.Parse()

	fmt.Println("version = ", version)
}

The output is

go run main.go -setVersion "2.0.0"
version = 2.0.0

What if we want to pass a struct variable via the Command-Line arguments, how can we do? For example, set a Profile?

type Profile struct {
    Name string 
    Age uint
    Verified bool
}

Let’s change the above code to see what will happen

package main

import (
	"flag"
	"fmt"
)

type Profile struct {
	Name     string
	Age      uint
	Verified bool
}

func main() {
	var version string
	var profile Profile  // new added

	flag.StringVar(&version, "setVersion", "1.0.0", "")
	flag.Var(&profile, "setProfile", "")  // new added
	flag.Parse()

	fmt.Println("version = ", version)
	fmt.Println("profile = ", profile)  // new added
}

When we execute it, the output shows like below

go run main.go -setProfile "{\"Name\": \"oscar\", \"Age\": 18, \"Verified\": false}"
# command-line-arguments
.\main.go:28:11: cannot use &profile (type *Profile) as type flag.Value in argument to flag.Var:
        *Profile does not implement flag.Value (missing Set method)

The error message *Profile does not implement flag.Value (missing Set method) indicates that the struct Profile is not completed for function flag.Var.

flag.Var allows us to implement a user-defined value. Its prototype is flag.Var(value Value, name string, usage string). We notice that the type of the first argument value is Value which is an interface. The prototype is

type Value interface {
    String() string
    Set(string) error
}

So what we need to do next is to implement the methods String() string and Set(string) error for struct Profile.

package main

import (
	"encoding/json"
	"flag"
	"fmt"
)

type Profile struct {
	Name     string
	Age      uint
	Verified bool
}

// new added
func (this *Profile) String() string {
	b, _ := json.Marshal(*this)
	return string(b)
}

// new added
func (this *Profile) Set(s string) error {
	return json.Unmarshal([]byte(s), this)
}

func main() {
	var version string

	var profile Profile
	flag.StringVar(&version, "setVersion", "1.0.0", "")
	flag.Var(&profile, "setProfile", "")
	flag.Parse()

	fmt.Println("version = ", version)
	fmt.Println("profile = ", profile)
}

The output is

go run main.go -setProfile "{\"Name\": \"oscar\", \"Age\": 18, \"Verified\": false}"
version =  1.0.0
profile =  {oscar 18 false}

In a nutshell, with the function flag.Var, we can freely parse any values of user-defined type, like array, map, and struct.


If this post helped you to solve a problem or provided you with new insights, please upvote it and share your experience in the comments below. Your comments can help others who may be facing similar challenges. Thank you!
Buy Me A Coffee
DigitalOcean Referral Badge
Sign up to get $200, 60-day account credit !