golangのお勉強9


構造体

  • 構造体の初期化のパターンがあり、スタンダードな初期化は初期化関数がある
  • 構造体に構造体をネストしたり、メソッドを追加したりする

急いで学ぶGo lang#5 構造体 | Developers.IO
http://dev.classmethod.jp/server-side/language/golang-5/

golangのオブジェクト志向、とてもわかりやすい。

gormの事例

マイグレーションもgormでやってしまうと考えると

Go言語からGORMとECHOでJSONを返すAPIサーバー作ってみる。 - OngaLog
http://onga-tec.hatenadiary.jp/entry/2016/08/12/010938

gooseパッケージ

mattes/migrateのdirtyフラグがしっくりこなかったのでgooseを使って見る。
is_appliedのフラグの命名が若干不思議。
downだとis_appliedがfalseで履歴が追加されるみたい。

設定方法の指定が若干わかりにくかったが環境変数からURI読み込みにする。

dbconfig.yml
development:
    driver: postgres
    open: $POSTGRESQL_URI

内部では他パッケージのように"github.com/lib/pq"を使っているみたい。

Go製マイグレーションツールまとめ - Qiita
http://qiita.com/nownabe/items/1acce9f6b9f14f74c965#%E5%8F%82%E8%80%83

liamstask / goose — Bitbucket
https://bitbucket.org/liamstask/goose

goose/dbconf.go at master · letsencrypt/goose
https://github.com/letsencrypt/goose/blob/master/lib/goose/dbconf.go

インタラクティブシェル

検証に使ったりした。
printが1回しかできない制限あり。
エラーで応答不能になったりもする気がする。
こういったものではなく、goplayをつかってもいいのではという記事もあった。

mkouhei/gosh: interactive shell for Golang
https://github.com/mkouhei/gosh

pathパッケージ

path.Base()を使ってAPIのパスからidを切り出した。

path - The Go Programming Language
https://golang.org/pkg/path/

Sirupsen/logrusパッケージ

パッケージのディレクトリが大文字になってしまう問題がありそう。
あとは、ちょうどいいformaterがあればいいな。
intellijでもフラグを立てればカラーリングを矯正できた

sirupsen/logrus: Structured, pluggable logging for Go.
https://github.com/Sirupsen/logrus

x-cray/logrus-prefixed-formatter: Logrus Prefixed Log Formatter
https://github.com/x-cray/logrus-prefixed-formatter

doloopwhile/logrusltsv: LTSV Formatter for Logrus
https://github.com/doloopwhile/logrusltsv

op/go-loggingパッケージ

ひとまずこれを使って見るかな。。
カラーリングがintellijだと無効になってしまう。

op/go-logging: Golang logging library
https://github.com/op/go-logging

エラーハンドリング

エラーをどうするのがいいのか。。
Error,panic,os.Exit,returnなどありそう。。

ひとまずは下記のイメージにしておく。

  • プログラム処理の致命的なエラー
    • panic/recover
  • 例外処理的なエラー
    • return/defer
  • 想定されるエラー
    • Error構造体
  • deferを無視したい場合
    • os.Exit()

エラー・ハンドリングについて(追記あり) — プログラミング言語 Go | text.Baldanders.info
http://text.baldanders.info/golang/error-handling/

returnして必要ならdefer。

ファイル構成

シンプルな形

Go言語からGORMとECHOでJSONを返すAPIサーバー作ってみる。 - OngaLog
http://onga-tec.hatenadiary.jp/entry/2016/08/12/010938

encoding/jsonパッケージ

詳しい、、まだ理解してない。

Friday the 13th - Gopher vs JSON!! - Qiita
http://qiita.com/hogedigo/items/f914992baf7a2ed12b9c

Marshalしたのと同じ構造体なのにUnmarshalできないと思って四苦八苦した。

Goのjson.Marshal/Unmarshalの仕様を整理してみる · I Will Survive
http://blog.restartr.com/2014/08/13/golang-json-marshal-unmarshal/

goの構造体につけるタグは、フォーマットが不正だと読み込まれない(当然)
json.Marshalは、構造体のjsonタグがあればその値をキーとしてJSON文字列を生成する
json.Unmarshalは、構造体のjsonタグがあればその値を対応するフィールドにマッピングする
jsonタグがなければ、完全一致もしくはcase-insensitiveなフィールドにマッピングする

結局、new()を使うとStructタグがコピーされない(アノーテーション)ために、復元ができなかったらしい。
Swaggerが生成してくれたコードだったのだがそのままつかえればよかったのに。。
(json文字には小文字を使うのが多分よい。構造体のスコープの指定が頭文字の大文字小文字。)

type InlineResponse200 struct {
    Name string `json:"name"`
    Contents string `json:"contents"`
}

okString := "[{\"Name\":\"なまえだよ\",\"Contents\":\"こんてんつだよ\"}]"
fmt.Fprintln(w, okString)

//元に戻すチェック
var successPayload = new([]swagger.InlineResponse200)
err = json.Unmarshal([]byte(okString), &successPayload)
applog.Info(err)
applog.Info(successPayload)

//元に戻すチェック(小文字で復元してくれた)
okString = "{\"name\":\"なまえだよ\",\"contents\":\"こんてんつだよ\"}"
var successPayload2 swagger.InlineResponse200
err = json.Unmarshal([]byte(okString), &successPayload2)
applog.Info(err)
applog.Info(successPayload2)

//元に戻すチェック
okString = "[{\"Name\":\"なまえだよ\",\"Contents\":\"こんてんつだよ\"}]"
var successPayload3 []swagger.InlineResponse200
err = json.Unmarshal([]byte(okString), &successPayload3)
applog.Info(err)
applog.Info(successPayload3)

//元に戻すチェック
okString = "[{\"Name\":\"なまえだよ\",\"Contents\":\"こんてんつだよ\"}]"
var successPayload4 = make([]swagger.InlineResponse200, 2)
err = json.Unmarshal([]byte(okString), &successPayload4)
applog.Info(err)
applog.Info(successPayload4)

使い分けがわからない。。
そもそも、newとかmakeとかわかってない。。

どうやら、encoding/jsonの内部ではreflectパッケージが使われてstructタグの情報を取得している。

Struct タグについて — プログラミング言語 Go | text.Baldanders.info
http://text.baldanders.info/golang/struct-tag/

go-swaggerとswagger codegen

swagger codegenで生成したコードをいじっているがいろいろ見つかって困りつつ勉強になる。

go-swaggerというパッケージでも生成ができてこちらのほうが完成度は高いらしい。
ただ、調整しづらい部分もいくつかあったのかな??いまさらだけど。

Goa: Design-First API Generation | Hacker News
https://news.ycombinator.com/item?id=12004218

Overall the default swagger codegen is very simplistic and the alternative go-swagger code is better but has a few rough edges that are difficult to fix.

下記のイメージ。

go-swagger: より良いが癖がある
swagger codegen: 最低限のサンプルレベルだがシンプル

codegenをカスタマイズする方法もあるらしい。。へー。。Groovyかあ。

こんなに簡単! Swagger Codegenのカスタマイズ - Qiita
http://qiita.com/Quramy/items/c583f3213f0b77ff1bac

そうです、こんなときこそGroovyの出番です。

swagger-codegen/modules/swagger-codegen/src/main/resources at master · swagger-api/swagger-codegen
https://github.com/swagger-api/swagger-codegen/tree/master/modules/swagger-codegen/src/main/resources

goa

うーん、やってみようかなあ。。
コードが綺麗なら乗り換えた方が効率的かも。。
まだロジックの実装はほとんど進んでないし。。

これからMicroservicesな開発をするならgoaがおすすめという話 - Qiita
http://qiita.com/y_matsuwitter/items/1298adfcd26c84f7d20b#_reference-f9e0db65923c64c50061

goa でデザイン・ファーストをシュッとする - Qiita
http://qiita.com/ikawaha/items/6638ee8b6978aef50d65#_reference-1585e09173db4b55de96

お、定義から生成できるのすごい。

Swagger 定義から goa の design を生成する ago という CLI を作りはじめた - tchsskのブログ
http://tchssk.hatenablog.com/entry/2016/12/17/211443