Goを始めて4日たった。仕事関係のウェブサービスで、負荷分散のためにバックエンドを冗長化する必要がでてきた。そういうとなんかすごそうだが、高負荷の外部コマンドを叩くだけのサービスを作ればいい。複雑さはない。今回はそのサービスをRESTサーバーとしてGoで作る。
この記事のゴール
Goで作ったRESTサーバーをLinuxにデプロイし、httpieで叩いてみる
準備
まず、Macで作ってLinuxにデプロイしようと思うので、Mac, Linux, Windowsにコンパイルできるように、クロスコンパイル可能な状態でGoをインストールする:
brew install go --cross-compile-common
次に、適当にフォルダを作る
mkdir ~/Desktop/gorest
cd ~/Desktop/gorest/
つぎに、service.goファイルを作る
touch service.go
それを、エディタで開く
最後に、$GOPATHをセットしてなければ、とりあえず ~/Desktop/gorest
にしておく
export GOPATH=$(pwd)
APIの仕様
名前を入力すると、Hello, <名前> で返してくる
- POST /hello
{
"Name": "Alice"
}
{
"Result": "Hello, Alice"
}
RESTサーバーを簡単に作れるライブラリを取ってくる
go get github.com/ant0ine/go-json-rest
サーバー(service.go)のコードを書く
賞味40行くらい
package main
import (
"github.com/ant0ine/go-json-rest"
"log"
"net/http"
)
// 入力の定義
type postHelloInput struct {
Name string
}
// 出力の定義
type postHelloOutput struct {
Result string
}
func postHello(w *rest.ResponseWriter, req *rest.Request) {
input := postHelloInput{}
err := req.DecodeJsonPayload(&input)
// そもそも入力の形式と違うとここでエラーになる
if err != nil {
rest.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 適当なバリデーション
if input.Name == "" {
rest.Error(w, "Name is required", 400)
return
}
log.Printf("%#v", input)
// 結果を返す部分
w.WriteJson(&postHelloOutput{
"Hello, " + input.Name,
})
}
func main() {
handler := rest.ResourceHandler{}
handler.SetRoutes(
rest.Route{"POST", "/hello", postHello},
)
log.Printf("Server started")
http.ListenAndServe(":9999", &handler) // ポート9999で立ち上がる
}
実行してみる
go run server.go
でサーバーを起動する
go run service.go
ターミナルの別タブを開いて、httpieでリクエストを投げてみる
http -v POST localhost:9999/hello "Content-Type:application/json; charset=UTF-8" Name="Suin"
POST /hello HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate, compress
Content-Length: 16
Content-Type: application/json; charset=UTF-8
Host: localhost:9999
User-Agent: HTTPie/0.6.0
{
"Name": "Suin"
}
HTTP/1.1 200 OK
Content-Length: 29
Content-Type: application/json
Date: Fri, 06 Dec 2013 16:10:15 GMT
{
"Result": "Hello, Suin"
}
うまく動いている様子。
Linux用にビルドする
Linux 64ビット用のバイナリを作る:
GOOS=linux GOARCH=amd64 go build service.go
ビルドが終わると service
という名前で7MBくらいの実行形式のバイナリができあがる。
ポート9999が開けてあるLinuxに持ってく
scpとかで転送する
scp service vagrant:
サーバにログインして、今転送したserviceを起動する
vagrant@suin:~$ ./service
2013/12/07 01:15:02 Server started
手元のMacから httpie で叩いてみる
http -v POST 11.11.11.11:9999/hello "Content-Type:application/json; charset=UTF-8" Name="Suin"
POST /hello HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate, compress
Content-Length: 16
Content-Type: application/json; charset=UTF-8
Host: 11.11.11.11:9999
User-Agent: HTTPie/0.6.0
{
"Name": "Suin"
}
HTTP/1.1 200 OK
Content-Length: 29
Content-Type: application/json
Date: Fri, 06 Dec 2013 16:16:15 GMT
{
"Result": "Hello, Suin"
}
Apacheも必要なくファイル一個だけで動くLinuxのRESTサーバーができました!