GoでWebアプリケーションを作ってみる_雛形を作ってみる
前回の続きで、GoでTwitterライクなWebアプリケーションを作ってみる。
もろもろライブラリを取得
WAFにはechoを使うことにしたのでechoを取得
go get -u github.com/labstack/echo/...
公式サイトの通りにやったらサンプル動いた。
次にecho-scaffoldを取得
プロジェクトの雛形を作る。
echo-scaffold init my-go-microblog-sample cd my-go-microblog-sample export PROJECT_ROOT=`pwd` // $PROJECT_ROOTとする
$PROJECT_ROOT/my-go-microblog-sample.goを動かしてみると「github.com/globalsign/mgoがねーぞ」というエラーになる。 github.com/globalsign/mgoをgetして、再実行。
go get github.com/globalsign/mgo go run my-go-microblog-sample.go ____ __ / __/___/ / ___ / _// __/ _ \/ _ \ /___/\__/_//_/\___/ v3.3.dev High performance, minimalist Go web framework https://echo.labstack.com ____________________________________O/_______ O\ ⇨ http server started on [::]:4000
動いた。 確認:http://localhost:4000/
Tweetエンティティを生成してみる
tweetを作ってみる。microblogってアプリケーションにしたのでarticleの方が正しいかもしれないけど、まあいいや。
echo-scaffold scaffold tweet body:string postAt:time create models/tweet.go panic: 23:10: expected ';', found 'IDENT' int64 (and 3 more errors) goroutine 1 [running]: github.com/mattn/echo-scaffold/template.(*Builder).Write(0xc42009a3c0, 0x11e9ac0, 0xc4200946c0, 0x11985e0, 0xc4200ec4d0) /Users/masahiro/go/src/github.com/mattn/echo-scaffold/template/builder.go:104 +0x2ce github.com/mattn/echo-scaffold/template.(*Builder).WriteToPath(0xc42009a3c0, 0xc4200865a0, 0xf, 0x11985e0, 0xc4200ec4d0) /Users/masahiro/go/src/github.com/mattn/echo-scaffold/template/builder.go:126 +0x15c github.com/mattn/echo-scaffold/command.(*ModelCommand).Execute(0xc4200ec4d0, 0xc420096110, 0x3, 0x3) /Users/masahiro/go/src/github.com/mattn/echo-scaffold/command/model_command.go:90 +0x3a0 github.com/mattn/echo-scaffold/command.(*ScaffoldCommand).Execute(0x12d4140, 0xc420096110, 0x3, 0x3) /Users/masahiro/go/src/github.com/mattn/echo-scaffold/command/scaffold_command.go:41 +0x17e main.main() /Users/masahiro/go/src/github.com/mattn/echo-scaffold/echo-scaffold.go:61 +0x10c
ん?これはうまくいったのか?もう一回叩いてみる。
echo-scaffold scaffold tweet body:string postAt:time create models/tweet.go skip models/tweet.go create models/tweet_dbsession.go create controllers/tweets.go create controllers/tweets_helpers.go create controllers/suite_test.go skip controllers/suite_test.go insert controllers/router.go
生成されたコードをちょっと読んでみる。
func Setup(router *echo.Router) { tweets := TweetsController{Router: router} tweets.Setup() }
router.goでnewしてるTweetsControllerの定義
type TweetsController struct { // 埋め込み型。TweetsControllerがRouter型を内包 Router *echo.Router }
routerから呼ばれているSetup
func (controller *TweetsController) Setup() { controller.Router.Add("POST", "/tweets", controller.createTweet) controller.Router.Add("GET", "/tweets", controller.listTweets) controller.Router.Add("GET", "/tweets/:tweet_id", controller.getTweet) controller.Router.Add("PUT", "/tweets/:tweet_id", controller.updateTweet) controller.Router.Add("DELETE", "/tweets/:tweet_id", controller.deleteTweet) }
createTweetメソッド
func (controller *TweetsController) createTweet(c echo.Context) error { c.Request().ParseForm() tweet := &models.Tweet{} tweet.SetAttributes(c.Request().Form) tweet.Save() if len(tweet.ErrorMessages()) == 0 { return helpers.JSONResponseObject(c, 200, tweet) } return helpers.JSONResponse(c, 400, tweet.ErrorMessages()) }
なぜかgoland先生が&models.Tweet{}
のところで警告出してると思ったら、models/tweet.goは空かい。
config/database.goにはデータストアの定義がある。 デフォルトはmongodbらしい。
func DBSession() *mgo.Session { if mongodbSession != nil { return mongodbSession } uri := os.Getenv("MONGODB_URI") if uri == "" { uri = "mongodb://localhost" } ...
config/environment.goには環境に関する設定があって、デフォルトはdevelopment環境とな。
func Setup(e *echo.Echo) { if Environment == "" { Environment = "development" } DefaultDBName = dbPrefix + "-" + Environment ...
最後に、この状態でgo runしようとすると「github.com/sirupsen/logrusがねーぞ」というエラーになるのでgetする。
go get github.com/sirupsen/logrus
再度go runしようとするとエラーになる。 まあ、そらそうね。
go run my-go-microblog-sample.go controllers/tweets.go:7:2: models/tweet.go:1:1: expected 'package', found 'EOF'
一旦ここまで、次回に続く。
追記
tweet.goが空だったのはscaffoldコマンドをミスっているんじゃないかという気がした。 postAtのところは、うまくいけばCreatedAtという属性値ができるので、bodyだけでいい気がした。 以下参考。
scaffoldを再実行する。
echo-scaffold scaffold tweet body:string create models/tweet.go create models/tweet_dbsession.go create controllers/tweets.go create controllers/tweets_helpers.go create controllers/suite_test.go skip controllers/suite_test.go insert controllers/router.go
tweet.goが空じゃない。
... type Tweet struct { ID bson.ObjectId `bson:"_id,omitempty"` Body string `bson:"body"` CreatedAt int64 `bson:"created_at"` UpdatedAt int64 `bson:"updated_at"` Errors helpers.Errors `bson:"-"` } ...
日時はint64で表現するのか??
go runしてみると起動した。でもきっとmongodbに繋がらないのでエラーになるはず。
go run my-go-microblog-sample.go ____ __ / __/___/ / ___ / _// __/ _ \/ _ \ /___/\__/_//_/\___/ v3.3.dev High performance, minimalist Go web framework https://echo.labstack.com ____________________________________O/_______ O\ ⇨ http server started on [::]:4000
うん、なんの応答もない。
curl http://localhost:4000/tweets/565edd868bc93d268a13bc02
ちなみにIDの指定の仕方で地味にハマった。
さらに追記
mongo立てるのめんどくせーのでdockerで
https://hub.docker.com/r/_/mongo/
docker pull mongo docker run --name my-mongo -p 27017:27017 mongo
参考:telnetでポートの解放確認
telnet telnet> open localhost 27017 Trying ::1... Connected to localhost.
この状態でgo runしPOSTしてみる
curl -F "body=hello" http://localhost:4000/tweets {"body":"","id":"5aea96a541d1c2812b7daadf","success":true}
いい感じ。 mongodbの中を見てみる。
docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f33be02d0309 mongo "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 0.0.0.0:27017->27017/tcp my-mongo docker exec -it f33be02d0309 /bin/bash root@f33be02d0309:/# mongo > show dbs; admin 0.000GB config 0.000GB local 0.000GB my-go-microblog-sample-development 0.000GB > use my-go-microblog-sample-development switched to db my-go-microblog-sample-development > show collections; tweets > db.tweets.find() { "_id" : ObjectId("5aea96a541d1c2812b7daadf"), "body" : "", "created_at" : NumberLong(1525323429), "updated_at" : NumberLong(0) }
あれ?body入ってない??
curl http://localhost:4000/tweets/5aea96a541d1c2812b7daadf {"body":"","id":"5aea96a541d1c2812b7daadf","success":true}
Loggerを仕込んでみる
func (controller *TweetsController) createTweet(c echo.Context) error { c.Request().ParseForm() // logging form log.Print(c.Request().Form) tweet := &models.Tweet{} tweet.SetAttributes(c.Request().Form) tweet.Save() if len(tweet.ErrorMessages()) == 0 { return helpers.JSONResponseObject(c, 200, tweet) } return helpers.JSONResponse(c, 400, tweet.ErrorMessages()) }
空だった
2018/05/03 14:20:19 map[]
となるとcurlコマンドが間違ってんじゃね?とこうしてみる
curl http://localhost:4000/tweets -X POST -d "body=hello" {"body":"hello","id":"5aea9ca941d1c2832559a2fe","success":true}
ログ
2018/05/03 14:22:49 map[body:[hello]]
DB
> db.tweets.find() { "_id" : ObjectId("5aea96a541d1c2812b7daadf"), "body" : "", "created_at" : NumberLong(1525323429), "updated_at" : NumberLong(0) } { "_id" : ObjectId("5aea9c1341d1c2832559a2fd"), "body" : "", "created_at" : NumberLong(1525324819), "updated_at" : NumberLong(0) } { "_id" : ObjectId("5aea9ca941d1c2832559a2fe"), "body" : "hello", "created_at" : NumberLong(1525324969), "updated_at" : NumberLong(0) }
うまくいったっぽい。最後にGET
curl http://localhost:4000/tweets/5aea9ca941d1c2832559a2fe {"body":"hello","id":"5aea9ca941d1c2832559a2fe","success":true}
イイね