kazu22002の技術覚書

PHPer, Golang, AWS エンジニアの日々

golangとWEB APIを作る際に気にすること

golangでWEB APIを作る際に詰まったことや、事前に対策をしておいたほうがいいことを書いてみます。

受信用構造体と返却用構造体を作成

APIの受信用に構造体を作り、返却用に構造体を作る方が個人的にはいいと思います。

コード量は増えますが、さぼらずに書いたほうがいいです。

理由としては、パラメータを受け取った際にmapに格納することも可能ですが、golangとして書いているのに変数が可変になるため、書き間違いでのエラーやコード補完が出ないなどせっかくのビルド型の言語のいいところが活かせなくなります。

個人的なアンチパターンは、DBの定義を作成して、そのまま使用したりすることですね。

作り人により、画面での入力値と必要内容だけを渡せばいいはずなのに、DBに登録する内容をフロントに全て任せようとするケースなど発生したりするので、必要な内容のみにしてほしいです。

型を意識

個人的にはまずPHPから入ったこともあり、型を意識するところから始まりました。

基本は数値は「int64」、文字列は「string」、小数点ありは「float64」だと思います。

型を意識する理由としては、int64定義のパラメータに「"1"」のような文字列が渡ってくる場合にエラーになります。

正直、ここが一番画面を作る人からすると手間になる部分になってしまうので、ぜひgolang側で吸収できるようにしたほうがいいです。

日付でtime型を使用することもできますが、個人的にはStringで受け取ってからGolangでParseするほうが柔軟性があると思っています。

他にはJsonのmarshalをカスタマイズして、入力値をtime型にする方法もありますね。

また意識することとして、NULLも意識する必要があります。

数値にNULLを渡してもエラーになります。このあたりはNULL値のライブラリを使うと便利になります。

型について、marshalをカスタマイズし型の違いを吸収する

型の違いで落ちるケースはよくないため、独自の型を定義して、JSONのUnmarshalをカスタマイズしたほうがいいです。

「入力はInterfaceで、返却は型」がgolangのお作法ですね。

type MyInt struct {
    Int Int64
}

// 拡張
func (m MyInt) UnmarshalJSON(data []byte) error {
        var err error
    var v interface{}
    if err = json.Unmarshal(data, &v); err != nil {
        return err
    }
    switch x := v.(type) {
    case float64:
        // Unmarshal again, directly to int64, to avoid intermediate float64
        err = json.Unmarshal(data, &m.Int)
    case string:
        str := string(x)
        m.Int, err = strconv.ParseInt(str, 10, 64)
    default:
        err = fmt.Error("json: cannot unmarshal ")
    }
    return err
}

Nullライブラリを参考にして知った内容です。NULLのパラメータを渡すこともあるため、APIの入力にはNULLライブラリの使用をお勧めします。

github.com

次はJavascript側で困ったことを中心に

APIを作成した後、呼び出しはWeb側になるため、Javascriptになります。

Typescriptで描く場合に、型を指定することもできますが、Typescript自体がかなり曖昧な型だと痛感してAPIとの相性がものすごく悪いと実感しています。

ぜひAPIの言語側でいろいろと吸収することで開発も楽になり、想定していないバグなども減らせると思います。

golangAPIを作成する場合の参考になれば、幸いです。

頑張りましょう。

いま読んでいるところですが、golangでのWEBアプリ開発のサンプルがいくつか書いてあります。golang面白いです。

Go言語によるWebアプリケーション開発

Go言語によるWebアプリケーション開発