43
How to create a Web application for Golang @yosuke_furukawa

ヒカルのGo 資料 Webアプリケーションの作り方

Embed Size (px)

Citation preview

Page 1: ヒカルのGo 資料 Webアプリケーションの作り方

How to create a Web application for Golang

@yosuke_furukawa

Page 2: ヒカルのGo 資料 Webアプリケーションの作り方

@yosuke_furukawaNode.jsユーザーグループ代表 / DeNA所属

Page 3: ヒカルのGo 資料 Webアプリケーションの作り方

Golang歴:2ヶ月くらい 作ったもの

!

- socket.io-go-emitter - golang + angularjs で chat sample

- qiita アドベントカレンダーをスクレイピングするツール

Page 4: ヒカルのGo 資料 Webアプリケーションの作り方

Webアプリの作り方

Page 5: ヒカルのGo 資料 Webアプリケーションの作り方

Webアプリの作り方

net/httpでのwebサーバの建て方

DBアクセス/ORM

Web Application Framework

Page 6: ヒカルのGo 資料 Webアプリケーションの作り方

golangの勉強会を有志の数名集めてDeNAでやってた

Page 7: ヒカルのGo 資料 Webアプリケーションの作り方

golangの勉強会をDeNAでやってた

Page 8: ヒカルのGo 資料 Webアプリケーションの作り方

今回の話はそのまとめ

Page 9: ヒカルのGo 資料 Webアプリケーションの作り方

Goでweb applicationを 作る時に知っておいた方が

良いこと

Page 10: ヒカルのGo 資料 Webアプリケーションの作り方

net/httpでWebサーバをたててみる

https://gist.github.com/yosuke-furukawa/8309096

Page 11: ヒカルのGo 資料 Webアプリケーションの作り方

net/httpでWebサーバをたてるpackage main!import ( "fmt" "net/http" "log")!func hello(w http.ResponseWriter, r *http.Request) { //fmt.Fprintfでwに入るものがクライアントに出力される fmt.Fprintf(w, "Hello World!")}!func main() { // アクセスのルーティングを設定する http.HandleFunc("/", hello) // portを指定して起動 err := http.ListenAndServe(":9090", nil) if err != nil { log.Fatal("ListenAndServe: ", err) }}

Page 12: ヒカルのGo 資料 Webアプリケーションの作り方

net/httpでWebサーバをたてるpackage main!import ( "fmt" "net/http" "log")!func hello(w http.ResponseWriter, r *http.Request) { //fmt.Fprintfでwに入るものがクライアントに出力される fmt.Fprintf(w, "Hello World!")}!func main() { // アクセスのルーティングを設定する http.HandleFunc("/", hello) // portを指定して起動 err := http.ListenAndServe(":9090", nil) if err != nil { log.Fatal("ListenAndServe: ", err) }}

HandleFuncでrouting

ListenAndServeでportを指定して起動

Page 13: ヒカルのGo 資料 Webアプリケーションの作り方

ListenAndServeの動きfunc (srv *Server) Serve(l net.Listener) error { defer l.Close() var tempDelay time.Duration // how long to sleep on accept failure for { rw, e := l.Accept() if e != nil { if ne, ok := e.(net.Error); ok && ne.Temporary() { if tempDelay == 0 { tempDelay = 5 * time.Millisecond } else { tempDelay *= 2 } if max := 1 * time.Second; tempDelay > max { tempDelay = max } log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay) time.Sleep(tempDelay) continue } return e } tempDelay = 0 c, err := srv.newConn(rw) if err != nil { continue } go c.serve() }}

Page 14: ヒカルのGo 資料 Webアプリケーションの作り方

ListenAndServeの動きfunc (srv *Server) Serve(l net.Listener) error { defer l.Close() var tempDelay time.Duration // how long to sleep on accept failure for { rw, e := l.Accept() if e != nil { if ne, ok := e.(net.Error); ok && ne.Temporary() { if tempDelay == 0 { tempDelay = 5 * time.Millisecond } else { tempDelay *= 2 } if max := 1 * time.Second; tempDelay > max { tempDelay = max } log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay) time.Sleep(tempDelay) continue } return e } tempDelay = 0 c, err := srv.newConn(rw) if err != nil { continue } go c.serve() }}

リスナーを通じてリクエストを受け取る

新しくコネクションのinstanceを作る

goroutineを起動し、リクエストを処理 ユーザーからのリクエストは全て新しいgoroutine で行われ、互いに影響しない作りになっている

Page 15: ヒカルのGo 資料 Webアプリケーションの作り方

GoでRESTFul APIを作る

Page 16: ヒカルのGo 資料 Webアプリケーションの作り方

RESTFul APIおさらい

各URIがリソースを表す

このリソースを操作するため4つのHTTPのメソッドを扱う

Page 17: ヒカルのGo 資料 Webアプリケーションの作り方

RESTFul APIおさらい

/users/:id

ユーザーを表現するためのリソース

GET, POST, PUT, DELETE

HTTP methodを使って操作する

Page 18: ヒカルのGo 資料 Webアプリケーションの作り方

RESTFul APIを作るpackage main!import ( "fmt" "github.com/drone/routes" "net/http")!// GET用のHandlerfunc getuser(w http.ResponseWriter, r *http.Request) { params := r.URL.Query() id := params.Get(":id") fmt.Fprintf(w, "you are get user %s", id)}// PUT, DELETE, POST用の…!func main() { mux := routes.New() // GET, PUT, DELETE, POST 用のハンドラー関数をroutingする mux.Get("/users/:id", getuser) mux.Put("/users/:id", modifyuser) mux.Del("/users/:id", deleteuser) mux.Post("/users/", adduser) http.Handle("/", mux) http.ListenAndServe(":9090", nil)}

Page 19: ヒカルのGo 資料 Webアプリケーションの作り方

RESTFul APIを作るpackage main!import ( "fmt" "github.com/drone/routes" "net/http")!// GET用のHandlerfunc getuser(w http.ResponseWriter, r *http.Request) { params := r.URL.Query() id := params.Get(":id") fmt.Fprintf(w, "you are get user %s", id)}// PUT, DELETE, POST用の…!func main() { mux := routes.New() // GET, PUT, DELETE, POST 用のハンドラー関数をroutingする mux.Get("/users/:id", getuser) mux.Put("/users/:id", modifyuser) mux.Del("/users/:id", deleteuser) mux.Post("/users/", adduser) http.Handle("/", mux) http.ListenAndServe(":9090", nil)}

drone/routesとかgowebとかの ルーティング用の 3rd modulesを使う

大したことはやってないので、 net/httpだけで頑張る事も可能だが、

:idから始まる文字のパースと methodによるrouting処理が面倒なら こういうモジュール使うのもあり。

Page 20: ヒカルのGo 資料 Webアプリケーションの作り方

これだけで簡単なREST APIは作れる

Page 21: ヒカルのGo 資料 Webアプリケーションの作り方

DBアクセス

https://gist.github.com/yosuke-furukawa/8552841

Page 22: ヒカルのGo 資料 Webアプリケーションの作り方

DBアクセスpackage main!import ( "database/sql" _ "github.com/go-sql-driver/mysql" "log")!func main() {  // sql.Open 第一引数にdriverの種類、第二引数に接続アドレスを指定、ここではhelloに接続することを宣言。 db, err := sql.Open("mysql", "root@tcp(127.0.0.1:3306)/hello") // errがあればそれを表示 if err != nil { log.Fatal(err) } // deferで関数の終わりにそれをclose defer db.Close()}

Page 23: ヒカルのGo 資料 Webアプリケーションの作り方

DBアクセスpackage main!import ( "database/sql" _ "github.com/go-sql-driver/mysql" "log")!func main() {  // sql.Open 第一引数にdriverの種類、第二引数に接続アドレスを指定、ここではhelloに接続することを宣言。 db, err := sql.Open("mysql", "root@tcp(127.0.0.1:3306)/hello") // errがあればそれを表示 if err != nil { log.Fatal(err) } // deferで関数の終わりにそれをclose defer db.Close()}

sql.OpenでDBアクセス開始

Page 24: ヒカルのGo 資料 Webアプリケーションの作り方

SELECT操作 var ( id int name string ) // db.PrepareでPreparedStatement実行 stmt, err := db.Prepare("select id, name from users where id = ?") if err != nil { log.Fatal(err) } // statementのClose忘れずに。 defer stmt.Close() // stmt.QueryでQueryを実行 rows, err := stmt.Query(1); for rows.Next() { err := rows.Scan(&id, &name) if err != nil { log.Fatal(err) } log.Println(id, name) } defer rows.Close();

Page 25: ヒカルのGo 資料 Webアプリケーションの作り方

SELECT操作 var ( id int name string ) // db.PrepareでPreparedStatement実行 stmt, err := db.Prepare("select id, name from users where id = ?") if err != nil { log.Fatal(err) } // statementのClose忘れずに。 defer stmt.Close() // stmt.QueryでQueryを実行 rows, err := stmt.Query(1); for rows.Next() { err := rows.Scan(&id, &name) if err != nil { log.Fatal(err) } log.Println(id, name) } defer rows.Close();

db.PrepareでSQL実行する

stmt.QueryでQueryを実行 ここでは、id=1を実行

Page 26: ヒカルのGo 資料 Webアプリケーションの作り方

INSERTとかUPDATEとかDELETEとか! stmt, err := db.Prepare("INSERT INTO users(id, name) VALUES(?, ?)") if err != nil { log.Fatal(err) } res, err := stmt.Exec(2, "haruyama") if err != nil { log.Fatal(err) }

Page 27: ヒカルのGo 資料 Webアプリケーションの作り方

INSERTとかUPDATEとかDELETEとか! stmt, err := db.Prepare("INSERT INTO users(id, name) VALUES(?, ?)") if err != nil { log.Fatal(err) } res, err := stmt.Exec(2, "gopher") if err != nil { log.Fatal(err) }

stmt.Execで更新系のQueryを発行する

Page 28: ヒカルのGo 資料 Webアプリケーションの作り方

ここまでで簡単なDBアクセスと永続化はできる

Page 29: ヒカルのGo 資料 Webアプリケーションの作り方

ORM

Page 30: ヒカルのGo 資料 Webアプリケーションの作り方

こんだけある…

http://present.go-steel-programmers.org/talk-review-orms/gsp-go-orms.slide#1

Page 31: ヒカルのGo 資料 Webアプリケーションの作り方

あんまり試せてない…シンプルでquery builderっぽいgorpか

gormが良さそうだけど、API的には どれも有意差はない

Page 32: ヒカルのGo 資料 Webアプリケーションの作り方

Web Application Frameworks

https://gist.github.com/yosuke-furukawa/8816249

Page 33: ヒカルのGo 資料 Webアプリケーションの作り方

TL;DR

net/http

martini, beego

revel, falcore

goweb, drone/routes

gorilla/negroni

need simple

REST Framework

toolkit/compatible with net/http

Sinatra/Express like

Fullstack RoR like

Page 34: ヒカルのGo 資料 Webアプリケーションの作り方

martini!

• フルスタックフレームワーク • martiniがsinatraならこっちはRoR, Play

Framework、ちなみに初期ページすごくPlayっぽい

• 中にmail senderやwebsocketも組み込まれてる • ミドルウェアもフィルターという概念を使うことで使える

• コード変更を検知して自動リロード/テストフレームワークが中にある、など開発にも便利

Page 35: ヒカルのGo 資料 Webアプリケーションの作り方

Falcore

• 我らがngmoco製、最近はメンテをfitstarさんに譲っている様子

• フルスタックフレームワーク • HUPを送ったら自動でprocessをforkして子プロセスがreadyになったら自分を殺す動きをする

• これにより、hot restartが可能になっている

Page 36: ヒカルのGo 資料 Webアプリケーションの作り方

beego• revelほど高機能ではないが、一応フルスタックフレームワーク • ドキュメントが超親切 • beego/ORMをサポートし、MVCに特化している

• 中国では採用実績あり?

!!!!!

Page 37: ヒカルのGo 資料 Webアプリケーションの作り方

martini

!

!

• 人気がある(github/star的な意味で)

• すごくSinatra/Expressライク • 基本的な機能しかコアには存在せず、ミドルウェアで機能拡張する

• 豊富なミドルウェアが存在している。 • ただし、作者はあんまり推してない。

Page 38: ヒカルのGo 資料 Webアプリケーションの作り方

martini!!

• Martiniの作者がHTTP serverをより簡易的に、イディオム的に扱えるようにするために開発したライブラリ

• 正確にはフレームワークではなく、ライブラリ群 • 今後Martiniの代わりにスタンダードになる可能性があるかも。

!!

Page 39: ヒカルのGo 資料 Webアプリケーションの作り方

martini!!

• こちらも正確にはツールキット • router, secure session, websocket等、まぁWebアプリ作るには使うよねっていうのが揃ってる。

• isucon っていうweb アプリ高速化チューニングコンテストで使われてる。

• 他にも実はrevelの中で使われてたりと汎用性高い。

!

Page 40: ヒカルのGo 資料 Webアプリケーションの作り方

WAFまとめ

net/http

martini, beego

revel, falcore

goweb, drone/routes

gorilla/negroni

need simple

REST Framework

toolkit/compatible with net/http

Sinatra/Express like

Fullstack RoR like

Page 41: ヒカルのGo 資料 Webアプリケーションの作り方

まとめ• Webサーバの建て方とnet/httpの基礎的な話

• DBアクセスの方法

• Web Application Frameworkまとめ

Page 42: ヒカルのGo 資料 Webアプリケーションの作り方

今後やりたい事

Page 43: ヒカルのGo 資料 Webアプリケーションの作り方

今後やりたい事

Go + socket.io で死ぬ予定