かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Go プログラミング実践入門を読みながら Go での Web App のハローワールドをしようとして脱線した話し

Go には標準で Web アプリを作るための機能が入ってるらしい!? 他の言語でいうところの Web アプリ開発のためのフレームワークというのは、あるんだろうなぁと思って調べてみたら凄く素敵なまとめをみつけました。

github.com

いいね。本読み終わったら次に手を出してみようかなぁ。

Go での Web アプリ

とりあえず net/http をインポートしてたら簡単なハローワールドは出来上がる。 ドキュメントはここみたい。

http - The Go Programming Language

書籍の最初では、Web アプリを作るための書籍なので HandleFunc でリクエスト受け取るのに使ってますがドキュメントを見ると以下のようになってる。

Package http provides HTTP client and server implementations. 

なるほど、クライアントとサーバー兼ね備えてるんですね。じゃぁ早速クライアント側試してみようと思います。 試すのはこれ。

zipcloud.ibsnet.co.jp

http://zipcloud.ibsnet.co.jp/api/search に対して zipcode パラメータつけて GET するだけで OK。とても直感的ですね。 早速

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func main() {
    res, err := http.Get("http://zipcloud.ibsnet.co.jp/api/search?zipcode=7830060")
    if err != nil {
        fmt.Println(err.Error())
        return
    }

    defer res.Body.Close()
    body, err := ioutil.ReadAll(res.Body)

    if err != nil {
        fmt.Println(err.Error())
        return
    }

    fmt.Print(string(body))
}

実行するとこんな感じ。

{
        "message": null,
        "results": [
                {
                        "address1": "高知県",
                        "address2": "南国市",
                        "address3": "蛍が丘",
                        "kana1": "コウチケン",
                        "kana2": "ナンコクシ",
                        "kana3": "ホタルガオカ",
                        "prefcode": "39",
                        "zipcode": "7830060"
                }
        ],
        "status": 200
}

いいね!せっかくなので JSON もパースしておきたいですね。愛用している https://quicktype.io で上記 JSON を張り付けて Go 言語用の構造体とかを作ります。サクッと出来ていいですね。コピペして完了。

// To parse and unparse this JSON data, add this code to your project and do:
//
//    zipCodeResult, err := UnmarshalZipCodeResult(bytes)
//    bytes, err = zipCodeResult.Marshal()

package main

import "encoding/json"

func UnmarshalZipCodeResult(data []byte) (ZipCodeResult, error) {
    var r ZipCodeResult
    err := json.Unmarshal(data, &r)
    return r, err
}

func (r *ZipCodeResult) Marshal() ([]byte, error) {
    return json.Marshal(r)
}

type ZipCodeResult struct {
    Message interface{} `json:"message"`
    Results []Result    `json:"results"`
    Status  int64       `json:"status"`
}

type Result struct {
    Address1 string `json:"address1"`
    Address2 string `json:"address2"`
    Address3 string `json:"address3"`
    Kana1    string `json:"kana1"`
    Kana2    string `json:"kana2"`
    Kana3    string `json:"kana3"`
    Prefcode string `json:"prefcode"`
    Zipcode  string `json:"zipcode"`
}

そして、これを使って main 関数を書いて

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func main() {
    res, err := http.Get("http://zipcloud.ibsnet.co.jp/api/search?zipcode=7830060")
    if err != nil {
        fmt.Println(err.Error())
        return
    }

    defer res.Body.Close()
    body, err := ioutil.ReadAll(res.Body)

    if err != nil {
        fmt.Println(err.Error())
        return
    }

    r, err := UnmarshalZipCodeResult(body)
    if err != nil {
        fmt.Println(err.Error())
        return
    }

    fmt.Printf("status code: %v, address1: %v, address2: %v, address3: %v\n", r.Status, r.Results[0].Address1, r.Results[0].Address2, r.Results[0].Address3)
}

実行するとこうなりました。

status code: 200, address1: 高知県, address2: 南国市, address3: 蛍が丘

うん。ばっちり。あれ?本読んでたけど違うことしちゃってた。まぁいっか。