以前の記事(GAE(Google App Engine) で Golang 使った REST API)を作りましたが、プロジェクト(ディレクトリ)の構成について見直してみました。
Golang 用のプロジェクト構成については、ルールなどあると思いますが今回は Google App Engine の部分だけにフォーカスして考えてみます。
プロジェクト(ディレクトリ)の構成の変更
変更内容
- appengine ディレクトリを作成
- GAE 用のプログラム(hello.go)を移動
- app.yaml(設定ファイル)を移動
- 細かい修正(ファイル名の変更など)
- ルートディレクトリに main.go を追加
- 既存のプログラムに初期化用の function を追加
今までのプロジェクト(ディレクトリ)の構成
$ tree
.
├── README.md
├── app.yaml
└── hello.go
色々なサイトを参考にしたプロジェクト(ディレクトリ)の構成
$ tree
.
├── README.md
├── appengine
│ ├── app.yaml
│ └── init.go
└── main.go
ルートディレクトリに main.go を追加
今までの構成だと GAE の go plugin がインストールされた環境じゃないとサービスを起動することができないため、開発時の動作確認を行うことができませんでした。
そこで、appengine ディレクトリを作成して GAE 用の処理を全て appengine パッケージ内で管理するようにし、 main.go からは HTTP サーバを起動するだけの構成にします。
main.go
package main
import (
"os"
"log"
"net/http"
"github.com/ynozue/hellow-gae-go/appengine"
"fmt"
)
func main() {
log.Printf("start pid %d\n", os.Getpid())
// appengine package をロード
fmt.Println(appengine.New)
http.ListenAndServe(":8080", nil)
}
「appengine.New」を呼び出していますが、これは appengine パッケージの特定の処理を呼び出さないと init 関数が動作しないために苦肉の策として実行しています。
うまい方法があれば知りたい。。。
既存のプログラムに初期化用の function を追加
init.go
package appengine
import (
"net/http"
"encoding/json"
"fmt"
)
// Response 用の構造体
type Result struct {
Status int
Description string
}
func New() {
fmt.Println("new")
}
// package 読み込み時に実行される
func init() {
http.HandleFunc("/hello", handler)
}
// hello に binding された function
func handler(w http.ResponseWriter, r *http.Request) {
var result Result
switch r.Method {
case http.MethodGet:
v := r.FormValue("get_value")
result = Result{http.StatusOK, "http get result [" + v + "]"}
case http.MethodPost:
v := r.FormValue("post_value")
result = Result{http.StatusOK, "http post result [" + v + "]"}
default:
result = Result{http.StatusNotImplemented, "not implemented http mehtod"}
}
res, err := json.Marshal(result)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
} else {
w.Header().Set("Content-Type", "application/json")
w.Write(res)
}
}
※ New 関数を追加しています。
動作確認
go コマンドからの起動
$ go run main.go
2017/10/13 09:24:59 start pid 9036
0x1224f80
$ curl http://localhost:8080/hello | python -m json.tool
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 49 100 49 0 0 7762 0 --:--:-- --:--:-- --:--:-- 8166
{
"Description": "http get result []",
"Status": 200
}
GAE go plugin からの起動
$ goapp serve appengine/app.yaml
INFO 2017-10-13 00:26:15,907 devappserver2.py:115] Skipping SDK update check.
INFO 2017-10-13 00:26:16,037 api_server.py:299] Starting API server at: http://localhost:51927
INFO 2017-10-13 00:26:16,044 dispatcher.py:224] Starting module "default" running at: http://localhost:8080
INFO 2017-10-13 00:26:16,049 admin_server.py:116] Starting admin server at: http://localhost:8000
$ curl http://localhost:8080/hello | python -m json.tool
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 49 100 49 0 0 1080 0 --:--:-- --:--:-- --:--:-- 1088
{
"Description": "http get result []",
"Status": 200
}
まとめ
go コマンドで実行したケースも GAE の go plungin を利用して実行したケースも同じ結果になりました。
これで go plungin をインストールしていない環境でも開発環境を動かすことができるようになりました。