What's 「Gin」?
- golangのフレームワークのひとつ
- martiniという別のgolang frameworkのような感じですが、martiniよりも早いそう
- contributors/star/fork/watchがechoやirisよりも多い (2019.01中旬時点)
- HTTP2.0にも対応している
- router がgroup化できる
[参照]
https://github.com/gin-gonic/gin
What's 「sqlx」?
- golangの「database/sql」ライブラリを拡張したライブラリ
- NamedQueryとかが簡単にできるようになってるので便利
[参照]
https://github.com/jmoiron/sqlx/
What did you do?
- 「Gin」フレームワークで簡単なAPIを作ってみました
- テーマは「本の管理システム」です
- 基本的なCURDができるようにはなっています
Structure
├── Dockerfile // API実行用 Docker image
├── api
│ ├── main.go // API Server
│ └── scope
│ ├── book.go // URI「/book」以下の処理
│ └── router.go // HTTP Request Method毎に呼び出すメソッドを振り分ける
├── docker-compose.yml
└── mysql
├── Dockerfile // mysql image
├── db-data
├── initdb.d
│ ├── 1_init.sh
│ ├── 1_schema.sql_ // mysql schema
│ └── 2_testdata.sql_ // 初期データ
└── my.cnf
Contents
※ コードや実行方法は github に上げましたので、興味ある方はそちらを御覧ください
以下、URIになります。
- 検索
- [GET] /book/list
- [GET] /book/search/:title
- 追加
- [POST] /book/insert
- 更新
- [PATCH] /book/:id
- 削除
- [DELETE] /book/:id
Document
以下、ハマった箇所だけ簡単に解決法を紹介します。
(初心者なのでコードのあれこれ担保できないのであしからず)
■ argsを利用してselectする
[問題]
↓のようにargsを指定しなければstructsに結果を引き渡せるのですが、公式のように「$1」を指定するとまくいかなかった
func getBookList(c *gin.Context) {
db := dbConnect("mysql", "api", "api", "password")
books := []Book{}
db.Select(&books, "select * from book")
c.String(200, "getBookList : %v", books)
[解決法]
-
「?」を指定する
err := db.Get(&book, "select * from book where id=?", id);
-
メモ:like検索のように「%」などの特殊文字を指定する時上手く行かなかった
-
Namedを利用する
m := map[string]interface{}{"title": "%" + title + "%"} nstmt, err := db.PrepareNamed("select * from book where title like :title")
;
err = nstmt.Select(&books, m)
```
- メモ:「%」は事前に文字連結しておかないとエラーになってしまい、ハマった
■ HTTP Request Bodyを利用してパラメータを受け渡しする場合
[問題]
- request bodyをどんなメソッドで引き取ればいいかがわからなかった
[誤答]
-
gin.Context.Resuest.Bodyを直接読み込もうとすること
-
これでやると、折角のフレームワークの旨味がまったく活かせない
-
しかもそのまま表示すると↓のようになる
$ curl -X PATCH -d "title=RESTful web service&label=architecture" http://localhost:9000/book/st.sol.18 updateBookInfo st.sol.18 : &{0xc000216140 <nil> <nil> false true {0 0} false false false 0x6a2030}
[解決法]
-
Bind() を使う
// update target info format is JSON var target Book if err := c.ShouldBind(&target); err != nil { c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) return }