Build a CLI program using Go

Guanhui
Release: 2020-06-13 09:03:28
forward
3583 people have browsed it

Build a CLI program using Go

You may have practiced Go syntax again and again, but unless you build an application yourself, you have not experienced the real feel of writing applications in Go. .

In this blog post, we will build a CLI application in Go, let’s call it go-grab-xkcd. The application pulls comics from XKCD and provides them for you through command line parameters Provide various operation options.

We will build the entire application using only the Go standard library without using external dependencies.

The idea of ​​this application may seem a bit silly, but the purpose is Practice writing production-level (sort of) code in Go without trying to get acquired by Google.

There’s a bonus at the end

Note: This article assumes that the reader is already familiar with Go syntax and terminology, and Somewhere between beginner and intermediate.

Let's run the app first and then move on

$ go-grab-xkcd --help
Usage of go-grab-xkcd:
  -n int
        Comic number to fetch (default latest)
  -o string
        Print output in format: text/json (default "text")
  -s    Save image to current directory
  -t int
        Client timeout in seconds (default 30)
$ go-grab-xkcd -n 323
Title: Ballmer Peak
Comic No: 323
Date: 1-10-2007
Description: Apple uses automated schnapps IVs.
Image: https://imgs.xkcd.com/comics/ballmer_peak.png
$ go-grab-xkcd -n 323 -o json
{
  "title": "Ballmer Peak",
  "number": 323,
  "date": "1-10-2007",
  "description": "Apple uses automated schnapps IVs.",
  "image": "https://imgs.xkcd.com/comics/ballmer_peak.png"
}
Copy after login

You can try other options by downloading and running the app on your computer .

After the end of this tutorial you will be familiar with the following topics:

Receiving command line parameters

Converting between JSON and Go structures

Make API calls

Create files (download and save from the network)

String operations

The following is the project structure

$ tree go-grab-xkcd
go-grab-xkcd
├── client
│   └── xkcd.go
└── model
    └── comic.go
├── main.go
└── go.mod
go.mod - Go Modules file used in Go for package management
main.go - Main entrypoint of the application
comic.go - Go representation of the data as a struct and operations on it
xkcd.go - xkcd client for making HTTP calls to the API, parsing response and saving to disk
Copy after login

1: Initialize project

Create a go.mod file -

$ go mod init
Copy after login

This will help you with package management (think package.json files in JS).

2: xkcd API

xkcd is amazing and you don’t need any registration or access keys to use their API. Open the xkcd API "Documentation" and you will find that there are two endpoints -

http://xkcd.com/info.0.json - Get the latest comics

http://xkcd. com/614/info.0.json - Get the specified comic by comic number

The following is the JSON response of these endpoints-

{
  "num": 2311,
  "month": "5",
  "day": "25",
  "year": "2020",
  "title": "Confidence Interval",
  "alt": "The worst part is that's the millisigma interval.",
  "img": "https://imgs.xkcd.com/comics/confidence_interval.png",
  "safe_title": "Confidence Interval",
  "link": "",
  "news": "",
  "transcript": ""
}
Copy after login

Article related xkcd

2: Comic creation model

According to the above JSON response, we create a struct called ComicResponse in comic.go in the model package

type ComicResponse struct {
    Month      string `json:"month"`
    Num        int    `json:"num"`
    Link       string `json:"link"`
    Year       string `json:"year"`
    News       string `json:"news"`
    SafeTitle  string `json:"safe_title"`
    Transcript string `json:"transcript"`
    Alt        string `json:"alt"`
    Img        string `json:"img"`
    Title      string `json:"title"`
    Day        string `json:"day"`
}
Copy after login

You can use the JSON-to-Go tool to automatically generate it from JSON Structure.

By the way create another structure that will be used to output data from our application.

type Comic struct {
    Title       string `json:"title"`
    Number      int    `json:"number"`
    Date        string `json:"date"`
    Description string `json:"description"`
    Image       string `json:"image"`
}
Copy after login

Add the following two methods to the ComicResponse structure

// FormattedDate 函数将格式化日期元素为一个字符串
func (cr ComicResponse) FormattedDate() string {
    return fmt.Sprintf("%s-%s-%s", cr.Day, cr.Month, cr.Year)
}
// Comic 函数将从 API 接收到的 ComicResponse 转换为应用程序的输出格式, Comic 结构体
func (cr ComicResponse) Comic() Comic {
    return Comic{
        Title:       cr.Title,
        Number:      cr.Num,
        Date:        cr.FormattedDate(),
        Description: cr.Alt,
        Image:       cr.Img,
    }
}
Copy after login

Then add the following two methods to the Comic structure

// PrettyString 函数创建一个漂亮的 Comic 字符串并用于输出
func (c Comic) PrettyString() string {
    p := fmt.Sprintf(
        "Title: %s\nComic No: %d\nDate: %s\nDescription: %s\nImage: %s\n",
        c.Title, c.Number, c.Date, c.Description, c.Image)
    return p
}
// JSON 函数将 Comic 结构体转换为 JSON, 我们将使用 JSON 字符串作为输出内容
func (c Comic) JSON() string {
    cJSON, err := json.Marshal(c)
    if err != nil {
        return ""
    }
    return string(cJSON)
}
Copy after login

3: Set up the xkcd client to initiate a request, parse the response and save it to disk

Create xkcd in the client package. go file.

First define a custom type called ComicNumber, the data type is int

type ComicNumber int

Define constants

const (
    // xkcd 的 BaseURL
    BaseURL string = "https://xkcd.com"
    // DefaultClientTimeout 是取消请求之前要等待的时间
    DefaultClientTimeout time.Duration = 30 * time.Second
    // 根据 xkcd API, LatestComic 是最新的漫画编号
    LatestComic ComicNumber = 0
)
Copy after login

Create a structure XKCDClient, which will be used to make requests to the API.

// XKCDClient 是 XKCD 的客户端结构体
type XKCDClient struct {
    client  *http.Client
    baseURL string
}
// NewXKCDClient 创建一个新的 XKCDClient
func NewXKCDClient() *XKCDClient {
    return &XKCDClient{
        client: &http.Client{
            Timeout: DefaultClientTimeout,
        },
        baseURL: BaseURL,
    }
}
Copy after login

Add the following 4 methods to XKCDClient

SetTimeout()

// SetTimeout 重写了默认的 ClientTimeout
func (hc *XKCDClient) SetTimeout(d time.Duration) {
    hc.client.Timeout = d
}
Copy after login

Fetch()

// Fetch 根据提供的漫画编号检索漫画
func (hc *XKCDClient) Fetch(n ComicNumber, save bool) (model.Comic, error) {
    resp, err := hc.client.Get(hc.buildURL(n))
    if err != nil {
        return model.Comic{}, err
    }
    defer resp.Body.Close()
    var comicResp model.ComicResponse
    if err := json.NewDecoder(resp.Body).Decode(&comicResp); err != nil {
        return model.Comic{}, err
    }
    if save {
        if err := hc.SaveToDisk(comicResp.Img, "."); err != nil {
            fmt.Println("Failed to save image!")
        }
    }
    return comicResp.Comic(), nil
}
Copy after login

SaveToDisk()

// SaveToDisk 下载并保存漫画到本地磁盘
func (hc *XKCDClient) SaveToDisk(url, savePath string) error {
    resp, err := http.Get(url)
    if err != nil {
        return err
    }
    defer resp.Body.Close()
    absSavePath, _ := filepath.Abs(savePath)
    filePath := fmt.Sprintf("%s/%s", absSavePath, path.Base(url))
    file, err := os.Create(filePath)
    if err != nil {
        return err
    }
    defer file.Close()
    _, err = io.Copy(file, resp.Body)
    if err != nil {
        return err
    }
    return nil
}
Copy after login

buildURL()

func (hc *XKCDClient) buildURL(n ComicNumber) string {
    var finalURL string
    if n == LatestComic {
        finalURL = fmt.Sprintf("%s/info.0.json", hc.baseURL)
    } else {
        finalURL = fmt.Sprintf("%s/%d/info.0.json", hc.baseURL, n)
    }
    return finalURL
}
Copy after login

4: Connect all

Inside the main() function we link all the content

read Command line parameters

Instantiate XKCDClient

Use XKCDClient to pull data from the API

Output

Read command line parameters

comicNo := flag.Int(
    "n", int(client.LatestComic), "Comic number to fetch (default latest)",
)
clientTimeout := flag.Int64(
    "t", int64(client.DefaultClientTimeout.Seconds()), "Client timeout in seconds",
)
saveImage := flag.Bool(
    "s", false, "Save image to current directory",
)
outputType := flag.String(
    "o", "text", "Print output in format: text/json",
)
Copy after login

flag.Parse()

Instantiate XKCDClient

xkcdClient := client.NewXKCDClient()
xkcdClient.SetTimeout(time.Duration(*clientTimeout) * time.Second)
Copy after login

Use XKCDClient to pull data from API

comic, err := xkcdClient.Fetch(client.ComicNumber(*comicNo), *saveImage)
if err != nil {
    log.Println(err)
}
Copy after login

Output

if *outputType == "json" {
    fmt.Println(comic.JSON())
} else {
    fmt.Println(comic.PrettyString())
}
Copy after login

The program runs as follows

$ go run main.go -n 323 -o json
Copy after login

Or build it as a binary executable on your laptop and run it

$ go build .
$ ./go-grab-xkcd -n 323 -s -o json
Copy after login

The complete source code can be found in this Github repository - go-grab-xkcd

Extra bonus

You can download multiple comics in sequence by using this simple shell magic tool

$ for i in {1..10}; do ./go-grab-xkcd -n $i -s; done;
Copy after login

The above shell code simply calls go-grab-xkcd in a for loop command, since xkcd uses sequence integers, replace the i value with the comic number as the comic number/ID.

Recommended tutorials: "PHP" "Go Tutorial"

The above is the detailed content of Build a CLI program using Go. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:learnku.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!