How to create a Web
application for Golang
@yosuke_furukawa
@yosuke_furukawa
Node.jsユーザーグループ代表 / DeNA所属
Golang歴:2ヶ月くらい
作ったもの
!
- socket.io-go-emitter
- golang + angularjs で chat sample
- qiita アドベントカレンダーをスクレイピングす
るツール
Webアプリの作り方
Webアプリの作り方
net/httpでのwebサーバの建て方
DBアクセス/ORM
Web Application Framework
golangの勉強会を有志の数名
集めてDeNAでやってた
golangの勉強会をDeNAで
やってた
今回の話はそのまとめ
Goでweb applicationを
作る時に知っておいた方が
良いこと
net/httpでWebサーバをたててみる
https://gist.github.com/yosuke-furukawa/8309096
net/httpでWebサーバをたてる
package main	
!
import (	
"fmt"	
"net/http"	
"log"	
)	
!
func hello(w http.ResponseWriter, r *http.Req...
net/httpでWebサーバをたてる
package main	
!
import (	
"fmt"	
"net/http"	
"log"	
)	
!
func hello(w http.ResponseWriter, r *http.Req...
ListenAndServeの動き
func (srv *Server) Serve(l net.Listener) error {	
defer l.Close()	
var tempDelay time.Duration // how lo...
ListenAndServeの動き
func (srv *Server) Serve(l net.Listener) error {	
defer l.Close()	
var tempDelay time.Duration // how lo...
GoでRESTFul APIを作る
RESTFul APIおさらい
各URIがリソースを表す
このリソースを操作するため4つの
HTTPのメソッドを扱う
RESTFul APIおさらい
/users/:id
ユーザーを表現するためのリソース
GET, POST, PUT, DELETE
HTTP methodを使って操作する
RESTFul APIを作る
package main	
!
import (	
"fmt"	
"github.com/drone/routes"	
"net/http"	
)	
!
// GET用のHandler	
func getuser(...
RESTFul APIを作る
package main	
!
import (	
"fmt"	
"github.com/drone/routes"	
"net/http"	
)	
!
// GET用のHandler	
func getuser(...
これだけで簡単なREST APIは作れる
DBアクセス
https://gist.github.com/yosuke-furukawa/8552841
DBアクセス
package main	
!
import (	
"database/sql"	
_ "github.com/go-sql-driver/mysql"	
"log"	
)	
!
func main() {	
  // sql.O...
DBアクセス
package main	
!
import (	
"database/sql"	
_ "github.com/go-sql-driver/mysql"	
"log"	
)	
!
func main() {	
  // sql.O...
SELECT操作
var (	
id int	
name string	
)	
// db.PrepareでPreparedStatement実行	
stmt, err := db.Prepare("select id, name from u...
SELECT操作
var (	
id int	
name string	
)	
// db.PrepareでPreparedStatement実行	
stmt, err := db.Prepare("select id, name from u...
INSERTとかUPDATEとかDELETEとか
!
stmt, err := db.Prepare("INSERT INTO users(id, name) VALUES(?, ?)")	
if err != nil {	
log.Fatal...
INSERTとかUPDATEとかDELETEとか
!
stmt, err := db.Prepare("INSERT INTO users(id, name) VALUES(?, ?)")	
if err != nil {	
log.Fatal...
ここまでで簡単なDBアクセスと永続化はできる
ORM
こんだけある…
http://present.go-steel-programmers.org/talk-review-orms/gsp-go-orms.slide#1
あんまり試せてない…
シンプルでquery builderっぽいgorpか
gormが良さそうだけど、API的には
どれも有意差はない
Web Application Frameworks
https://gist.github.com/yosuke-furukawa/8816249
TL;DR
net/http
martini, beego
revel, falcore
goweb,
drone/routes
gorilla/negroni
need simple
REST Framework
toolkit/compat...
martini
!
• フルスタックフレームワーク
• martiniがsinatraならこっちはRoR, Play
Framework、ちなみに初期ページすごくPlayっぽい
• 中にmail senderやwebsocketも組み込まれてる...
Falcore
• 我らがngmoco製、最近はメンテをfitstarさんに
譲っている様子
• フルスタックフレームワーク
• HUPを送ったら自動でprocessをforkして子プロ
セスがreadyになったら自分を殺す動きをする
• これに...
beego
• revelほど高機能ではないが、一応フルスタックフレームワーク
• ドキュメントが超親切
• beego/ORMをサポートし、MVCに

特化している
• 中国では採用実績あり?
!
!
!
!
!
martini
!
!
• 人気がある(github/star的な意味で)
• すごくSinatra/Expressライク
• 基本的な機能しかコアには存在せず、ミドル
ウェアで機能拡張する
• 豊富なミドルウェアが存在している。
• ただし、...
martini
!
!
• Martiniの作者がHTTP serverをより簡易的に、イディ
オム的に扱えるようにするために開発したライブラリ
• 正確にはフレームワークではなく、ライブラリ群
• 今後Martiniの代わりにスタンダードにな...
martini
!
!
• こちらも正確にはツールキット
• router, secure session, websocket等、まぁWebアプリ作
るには使うよねっていうのが ってる。
• isucon っていうweb アプリ高速化チューニ...
WAFまとめ
net/http
martini, beego
revel, falcore
goweb,
drone/routes
gorilla/negroni
need simple
REST Framework
toolkit/compa...
まとめ
• Webサーバの建て方とnet/httpの

基礎的な話
• DBアクセスの方法
• Web Application Framework

まとめ
今後やりたい事
今後やりたい事
Go + socket.io で死ぬ予定
Upcoming SlideShare
Loading in …5
×

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

18,382 views

Published on

Published in: Engineering
  • Be the first to comment

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

  1. 1. How to create a Web application for Golang @yosuke_furukawa
  2. 2. @yosuke_furukawa Node.jsユーザーグループ代表 / DeNA所属
  3. 3. Golang歴:2ヶ月くらい 作ったもの ! - socket.io-go-emitter - golang + angularjs で chat sample - qiita アドベントカレンダーをスクレイピングす るツール
  4. 4. Webアプリの作り方
  5. 5. Webアプリの作り方 net/httpでのwebサーバの建て方 DBアクセス/ORM Web Application Framework
  6. 6. golangの勉強会を有志の数名 集めてDeNAでやってた
  7. 7. golangの勉強会をDeNAで やってた
  8. 8. 今回の話はそのまとめ
  9. 9. Goでweb applicationを 作る時に知っておいた方が 良いこと
  10. 10. net/httpでWebサーバをたててみる https://gist.github.com/yosuke-furukawa/8309096
  11. 11. 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) } }
  12. 12. 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を指定して起動
  13. 13. 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() } }
  14. 14. 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 で行われ、互いに影響しない作りになっている
  15. 15. GoでRESTFul APIを作る
  16. 16. RESTFul APIおさらい 各URIがリソースを表す このリソースを操作するため4つの HTTPのメソッドを扱う
  17. 17. RESTFul APIおさらい /users/:id ユーザーを表現するためのリソース GET, POST, PUT, DELETE HTTP methodを使って操作する
  18. 18. RESTFul APIを作る package main ! import ( "fmt" "github.com/drone/routes" "net/http" ) ! // GET用のHandler func 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) }
  19. 19. RESTFul APIを作る package main ! import ( "fmt" "github.com/drone/routes" "net/http" ) ! // GET用のHandler func 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処理が面倒なら こういうモジュール使うのもあり。
  20. 20. これだけで簡単なREST APIは作れる
  21. 21. DBアクセス https://gist.github.com/yosuke-furukawa/8552841
  22. 22. 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() }
  23. 23. 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アクセス開始
  24. 24. 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();
  25. 25. 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を実行
  26. 26. 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) }
  27. 27. 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を発行する
  28. 28. ここまでで簡単なDBアクセスと永続化はできる
  29. 29. ORM
  30. 30. こんだけある… http://present.go-steel-programmers.org/talk-review-orms/gsp-go-orms.slide#1
  31. 31. あんまり試せてない… シンプルでquery builderっぽいgorpか gormが良さそうだけど、API的には どれも有意差はない
  32. 32. Web Application Frameworks https://gist.github.com/yosuke-furukawa/8816249
  33. 33. 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
  34. 34. martini ! • フルスタックフレームワーク • martiniがsinatraならこっちはRoR, Play Framework、ちなみに初期ページすごくPlayっぽい • 中にmail senderやwebsocketも組み込まれてる • ミドルウェアもフィルターという概念を使うことで使 える • コード変更を検知して自動リロード/テストフレーム ワークが中にある、など開発にも便利
  35. 35. Falcore • 我らがngmoco製、最近はメンテをfitstarさんに 譲っている様子 • フルスタックフレームワーク • HUPを送ったら自動でprocessをforkして子プロ セスがreadyになったら自分を殺す動きをする • これにより、hot restartが可能になっている
  36. 36. beego • revelほど高機能ではないが、一応フルスタックフレームワーク • ドキュメントが超親切 • beego/ORMをサポートし、MVCに
 特化している • 中国では採用実績あり? ! ! ! ! !
  37. 37. martini ! ! • 人気がある(github/star的な意味で) • すごくSinatra/Expressライク • 基本的な機能しかコアには存在せず、ミドル ウェアで機能拡張する • 豊富なミドルウェアが存在している。 • ただし、作者はあんまり推してない。
  38. 38. martini ! ! • Martiniの作者がHTTP serverをより簡易的に、イディ オム的に扱えるようにするために開発したライブラリ • 正確にはフレームワークではなく、ライブラリ群 • 今後Martiniの代わりにスタンダードになる可能性があ るかも。 ! !
  39. 39. martini ! ! • こちらも正確にはツールキット • router, secure session, websocket等、まぁWebアプリ作 るには使うよねっていうのが ってる。 • isucon っていうweb アプリ高速化チューニングコンテスト で使われてる。 • 他にも実はrevelの中で使われてたりと汎用性高い。 !
  40. 40. 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
  41. 41. まとめ • Webサーバの建て方とnet/httpの
 基礎的な話 • DBアクセスの方法 • Web Application Framework
 まとめ
  42. 42. 今後やりたい事
  43. 43. 今後やりたい事 Go + socket.io で死ぬ予定

×