ラベル GAE の投稿を表示しています。 すべての投稿を表示
ラベル GAE の投稿を表示しています。 すべての投稿を表示

2013年10月29日火曜日

Google App Engine SDK for Go がアップデート

久しぶりにサーバのプログラムを書こうと思ったら、Google App Engine の Go SKD がアップデートされていました。Version 1.8 になってだいぶ変わっていました。

まず、ディレクトリ名が google_appengine から go_appengine に変わっていました。
今までは PHP だろうが Go だろうが同じ名前だったのですが、それぞれの言語でディレクトリ名が変わっているようです。

また、こちらは重要なのですが、
ローカルサーバ起動時に IP アドレスを指定するオプションが変わっていました。
これまでは -a オプションで
dev_appserver.py -a 192.168.0.2 myapp

という風に IP アドレスを指定していたのですが、
これが --host オプションに変更されました。
dev_appserver.py --host 192.168.0.2 my app

これまでの -a オプションは使用できなくなっているので要注意です。 またサーバのログ出力フォーマットなど細かいところも色々と変わっていました。

2013年9月7日土曜日

Google URL Shortener API を使う

Google URL Shortener API を使うと、
Web アプリから Google の URL 短縮サービスを使って、
URL を短くすることができます。

Google URL Shortener API
https://developers.google.com/url-shortener/


サービスを有効化する

画面左の Google API Console をクリック
Services -> URL Shorener API を ON に切り替えて利用規約に同意する




API キーを取得する

画面左のメニューから API Access をクリック
Simple API Access の API Key に描かれている文字列が API キー



URL を短くする

Web アプリケーションから以下のような HTTP リクエストを送信すると、
短縮された URL を含むレスポンスが帰ってきます。
データは送受信ともに JSON 形式です。

リクエスト
POST https://www.googleapis.com/urlshortener/v1/url
Content-Type: application/json

{"longUrl": "http://www.google.com/", "key": "APIキー"}

レスポンスボディ
{
 "kind": "urlshortener#url",
 "id": "http://goo.gl/fbsS",
 "longUrl": "http://www.google.com/"
}

Go 言語のサンプルです。通信は okalib を使っています。
 // 短縮URLを取得する
 key := GOOGLE_API_KEY
 longUrl := Join("http://", HOSTNAME, "/runtime?game_key=", completeKey.Encode())
 requestBody := Join(`{"key":"`, key, `","longUrl":"`, longUrl, `"}`)
 params := make(map[string]string, 1)
 params["Content-Type"] = "application/json"
 response := Request(this.c, "POST", "https://www.googleapis.com/urlshortener/v1/url", params, requestBody)

 responseBody := make([]byte, response.ContentLength)
 _, err = response.Body.Read(responseBody)
 Check(this.c, err)

 result := make(map[string]string, 3)
 err = json.Unmarshal(responseBody, &result)
 Check(this.c, err)

2013年8月21日水曜日

Google App Engine の無料で使える範囲

Google App Engine は無料で使える Web アプリをホスティングできるサービスです。
Java, Python, Go, PHP 向けの様々な API が提供されています。

GAE では各機能ごとに無料で使える範囲が決まっています。
使用できる上限については以下のページにまとめられています。

Quotas - Google App Engine


いくつか見てみると、無料で使える範囲は以下にようになっています。


ブロッブストア
5GBまで

チャネル
API使用回数 1日657,000回まで、かつ、1分3,000回まで
作成数 1日100チャネルまで、かつ、1分6チャネルまで
接続時間 1日200時間まで、かつ、1分12時間まで
送信データ量 割り当てられた帯域上限に依存、かつ、1分22MBまで

コードとデータ容量(アプリのファイルサイズ)
1GBまで

データストア
保存データ 1GB まで
インデックス数 200個まで
書き込み処理 1日50,000回まで
読み込み処理 1日50,000回まで
細かい処理(Count()とか) 1日50,000回まで

デプロイ
アプリのアップロード 1日10,000回まで
ファイル数 1バージョン10,000ファイルまで
ファイルサイズ 1ファイル32MBまで
全バージョンの全ファイルサイズ 合計1GBまで

ログ
ログデータ(検索) 100MBまで
ログデータ 1GBまで
※ Logs data retrieva ってなんだろう・・・

メール
API使用回数 1日100回、かつ、1分32回
送信 1日100回、かつ、1分8回
管理者メール 1日5,000回、かつ、1分24回
メッセージサイズ 1日60MB、かつ、1分340KB
添付ファイル 1日2,000個、かつ、1分8個
添付ファイルサイズ 1日100MB、かつ、1分10MB

リクエスト
送信帯域 1日1GB、かつ、1分56MB
受信帯域 1日1GB; 14,400GB、かつ、1分56MB


以下省略。
詳しくは上のサイトをご覧ください。

2013年8月15日木曜日

GAE + Go で指定した時刻に処理を実行する

Google App Engine では、taskqueue パッケージを使って指定した時刻に処理を実行することができます。「メールアドレスの仮登録後、24時間経っても本登録がされなかったらデータベースから削除する」みたいなときに便利です。
Task Queue Go API Overview - Google App Engine

パッケージのインポート
import "appengine/taskqueue"


タスクの作成

タスクは taskqueue.Task 型で表され、taskqueue.NewPOSTTask() 関数で作成できます。
タスクは、指定した URL に HTTP POST を送ることで実行されます。
ユーザからのアクセスと同様に handleFunc() 関数で処理を割り振ります。
url.Values 型で POST で引き渡すデータを指定できます。
また、 time.Duration 型で現在時刻からどれくらい後に実行するのかを指定できます。
ETA を使って実行時刻を直接指定することもできます。
実行時刻の指定がない場合、即時実行されます。
// POST で渡すデータ
values := url.Values{}
values.Set("interim_key", key)

// 24時間後に実行
delay, err := time.ParseDuration("24h")
Check(c, err)

// タスクの作成("/cancel" に POST で送信)
task := taskqueue.NewPOSTTask("/cancel", values)
task.Delay = delay


キューにタスクを追加

GAE ではアプリごとに複数のタスクキューを持つことができます。それぞれのタスクキューで、タスクを実行するタイミングや、キューの容量などを設定できます。
今回は最初から準備されている default という名前のキューにタスクを入れます。
default キューは実行できるタスクが無いか 5 秒毎にチェック・実行されます。
オリジナルのキューを作成する場合は queue.yaml を作って設定してください。
Go Task Queue Configuration - Google App Engine
タスクは taskqueue.Add 関数でキューに追加できます。
// task を default キューに追加する
taskqueue.Add(c, task, "default")

これで24時間後に実行されるタスクを作成できました。


URL を管理者専用にする 

このままではユーザが /cancel にアクセスできてしまうので管理者専用にします。
GAE + Go で管理者専用機能を作る - y.okano blog
を参考に app.yaml で login: admin を指定しておきます。


開発サーバでタスクを手動実行する

ローカルの開発サーバでは、デバッグ用に手動でタスクを実行するツールも付いています。これを使わなくても自動実行はできますが、手動で実行したい場合は利用します。

http://localhost:8080/_ah/admin/queues

にアクセスすることでキューの状態や、タスクの実行が可能です。


2013年8月11日日曜日

datastore に保存できるプロパティの容量

GAE + Go ではデータストアに保存できるプロパティの大きさがデータ型によって異なります。string では 500Byte までですが、[]byte では 1MByte まで保存可能です。

ESCAPE 3DS のイベントエディタでデータが保存できなくなる問題が発生していました。調べてみると、サーバに以下のエラーログが出力されていました。
ERROR: API error 1 (datastore_v3: BAD_REQUEST): ApplicationError: 1 Property Code is too long. Maximum length is 500.

500Byte を超えるとデータが保存できないようです。
リファレンスを見てみると、[]byte であれば 1MByte まで保存できると書いてあります。
The datastore package - Google App Engine
- []byte (up to 1 megabyte in length)

データストアに保存するときに []byte に変換することで制限を 1MByte にできました。
クライアントに出力する際に、その都度 string へ変換する必要があるので注意が必要です。

2013年7月26日金曜日

GAE + Go でホスト名を取得する

サーバのホスト名を以下のように取得出来ます。
c := appengine.NewContext(r)
hostname := appengine.DefaultVersionHostName(c)
c.Debugf("HOSTNAME: %s", hostname)

詳しくはこちらのドキュメントを参照してください
The appengine package - Google App Engine

2013年7月22日月曜日

GAE + Go で Sign in with Facebook (2)

前回は Facebook にアプリを登録して Client ID と Client Secret を発行してもらいました。
GAE + Go で Sign in with Facebook

続いて実際にコードを書いていきます。
ちなみに今回は OAuth 2.0 の認証コード方式を使います。

まずログインボタンを設置します。
ボタンの画像はサードパーティから無料で提供されているものを使用しました。
リンク先を /login_facebook とします。
<a href="/login_facebook"><img src="/client/login/img/sign_in_with_facebook.png"></a>



/login_facebook に対応するハンドラを作成します。
http.HandleFunc から呼び出します。
// Facebook のログインボタンが押された時の処理
func (this *Controller) LoginFacebook(w http.ResponseWriter, r *http.Request) {
 c := appengine.NewContext(r)
 oauth := NewOAuth2(c, FACEBOOK_CLIENT_ID, FACEBOOK_CLIENT_SECRET)
 oauth.RequestAuthorizationCode(w, r, "https://www.facebook.com/dialog/oauth", url.QueryEscape("http://escape-3ds.appspot.com/callback_facebook"))
}

Facebook から発行された Client IDClient Secret を使って通信します。
最初に、アプリがユーザデータへアクセスする許可をユーザから得る必要があります。
Facebook ではユーザの許可を得る画面を OAuth Dialog と読んでいます。
OAuth Dialog の URL は http://www.facebook.com/dialog/oauth です。
ここに Client ID, Client Secret,  許可をもらった時のリダイレクト URL を GET で渡します。

詳しくはこちらをご覧ください
OAuth Dialog - Facebook Developers


上のコードでは自作のライブラリを使用しています。
中身はこんな感じになっています。
// OAuth 2.0
type OAuth2 struct {
 context appengine.Context
 clientId string
 clientSecret string
}

// OAuth2.0 インスタンスを返す
func NewOAuth2(c appengine.Context, clientId string, clientSecret string) *OAuth2 {
 oauth := new(OAuth2)
 oauth.context = c
 oauth.clientId = clientId
 
 oauth.clientSecret = clientSecret
 return oauth
}

// 認証コードをリクエストする
// 認証ページヘのリダイレクトを行いユーザに認証してもらう
// 認証が完了したらリダイレクトURIへ認証コードが返ってくる
func (this *OAuth2) RequestAuthorizationCode(w http.ResponseWriter, r *http.Request, targetUri string, redirectUri string) {
 targetUri = fmt.Sprintf("%s?client_id=%s&redirect_uri=%s&response_type=code", targetUri, this.clientId, redirectUri)
 http.Redirect(w, r, targetUri, 302)
}

今回はリダイレクト先として http://escape-3ds.appspot.com/callback_facebook を設定しました。
自分のアプリに合わせてコールバック先の URL を設定してください。
コールバックされた後の処理を書きます。
こちらも http.HandleFunc() で呼び出されるようにしましょう。
// Facebook でユーザがアクセスを許可した時に呼び出されるコールバック関数
func (this *Controller) CallbackFacebook(w http.ResponseWriter, r*http.Request) {
 c := appengine.NewContext(r)
 userInfo := this.RequestFacebookToken(w, r)
 
 model := NewModel(c)
 view := NewView(c, w)
 
 key := ""
 if model.ExistOAuthUser("Facebook", userInfo["oauth_id"]) {
  // 既存ユーザ
  params := make(map[string]string, 2)
  params["OAuthId"] = userInfo["oauth_id"]
  params["Type"] = "Facebook"
  key = model.GetUserKey(params)
 } else {
  // 新規ユーザ
  params := make(map[string]string, 4)
  params["user_type"] = "Facebook"
  params["user_name"] = userInfo["name"]
  params["user_oauth_id"] = userInfo["oauth_id"]
  params["user_pass"] = ""
  user := model.NewUser(params)
  key = model.AddUser(user)
 }
 
 if this.GetSession(c, r) == "" {
  this.StartSession(w, r, key)
 }
 view.Gamelist(key)
}

ユーザからの許可が得られたら、アクセストークンを Facebook に要求します。
上のコードでは RequestFacebookToken() で要求しています。
このとき、ユーザIDとユーザ名が含まれたレスポンスが Facebook から返されます。
データベース上にユーザID が存在するかどうかを調べて、新規ユーザかどうかを判断しています。
アクセストークンの取得先 URL は https://graph.facebook.com/oauth/access_token です。

アクセストークンについてはこちら
Access Tokens - Facebook Developer

RequestFacebookToken() の中身はこんな感じ。
// Facebook へアクセストークンを要求する。
// この関数は Facebook から認証コードをリダイレクトで渡された時に呼ばれる。
// ユーザ情報を格納した map を返す。
func (this *Controller) RequestFacebookToken(w http.ResponseWriter, r *http.Request) map[string]string {
 c := appengine.NewContext(r)
 code := r.FormValue("code")
 oauth := NewOAuth2(c, FACEBOOK_CLIENT_ID, FACEBOOK_CLIENT_SECRET)
 token := oauth.RequestAccessToken(w, r, "https://graph.facebook.com/oauth/access_token", url.QueryEscape("http://escape-3ds.appspot.com/callback_facebook"), code)
 response := oauth.RequestAPI(w, "https://graph.facebook.com/me", token)
 
 // JSON を解析
 type UserInfo struct {
  Id string `json:"id"`
  Name string `json:"name"`
 }
 userInfo := new(UserInfo)
 err := json.Unmarshal(response, userInfo)
 Check(c, err)
 
 result := make(map[string]string, 2)
 result["oauth_id"] = userInfo.Id
 result["name"] = userInfo.Name
 
 return result
}

RequestAccessToken() でアクセストークンとユーザ情報を取得して、
レスポンスのユーザデータのパースしています。

RequestAccessToken() の中身はこんな感じ。
// アクセストークンをリクエストする
// 引き換えとして認証コードを渡すこと
func (this *OAuth2) RequestAccessToken(w http.ResponseWriter, r *http.Request, targetUri string, redirectUri string, code string) string {
 targetUri = fmt.Sprintf("%s?client_id=%s&redirect_uri=%s&client_secret=%s&code=%s", targetUri, this.clientId, redirectUri, this.clientSecret, code)
 
 params := make(map[string]string, 4)
 params["client_id"] = this.clientId
 params["redirect_uri"] = redirectUri
 params["client_secret"] = this.clientSecret
 params["code"] = code
 response := Request(this.context, "GET", targetUri, params, "")
 
 body := make([]byte, 1024)
 _, err := response.Body.Read(body)
 Check(this.context, err)
 
 // response: oauth_token=******&expires=******
 responseParams := strings.Split(string(body), "&")
 tokenParam := strings.Split(responseParams[0], "=")
 return tokenParam[1]
}

すべてのコードは GitHub においてあります。
https://github.com/yokano/escape3ds

OAuth 2.0 に関するコントローラは
server/controller/controller.go
server/controller/oauth.go

ライブラリは
server/lib/oauth2.go

にあります。

2013年7月20日土曜日

GAE + Go で Sign in with Facebook(1)

以前 GAE + GO で Twitter ログインの記事を書きましたが、今回は Facebook d
    GAE + Go で Sign in with Twitter - y.okano blog

Facebook ログイン関係の公式ドキュメントはこちら
    Facebook Login - facebook developers

Twitter は OAuth 1.0 を採用していますが、Facebook では OAuth 2.0 になります。
    OAuth Core 1.0 Revision A - oauth.net
    OAuth 2.0 - rfc6749
    
Facebook からは JavaScript でログインが可能な SDK が提供されています。
今回はサーバサイドでログインを実装するので、JavaScript SDK は使用しません。

JavaScript SDK を使ったログイン方法についてはこちら
    The Login Flow for Web - facebook developers
    
JavaScript SDK を使わないログイン方法についてはこちら
    The Login Flow for Web (without JavaScript SDK)
    

アプリの登録

まず、Facebook に自作のアプリを登録します。
Facebook のアプリ管理ページを開きます。
    アプリ - facebook developers
    
右上の「+新しいアプリを作成」ボタンを押すと以下の様なダイアログが出ます。


Display Name,  App Category を入力します。
App Namespace は入力しなくて OK です。
Web Hosting は GAE を使うためチェックは外した状態にします。

アプリを登録したら、自動的にアプリの基本設定が表示されます。
ここに表示される App IDApp Secret をログインに使用します。


App Domains に GAE のアプリのドメイン名を入力します。
appname.appspot.com という感じです。

更に画面下の「アプリを Facebook に結合する方法を選択」部分を変更します。
「Facebook でログインするウェブサイト」のサイト URL を入力します。
http://appname.appspot.com/ という感じです。

ここまで変更できたら「変更を保存」ボタンを押して保存します。
これで Facebook でログインするためのアプリ登録が完了です。

今日はここまで。

2013年7月19日金曜日

GAE 開発サーバへ別のデバイスからアクセスする

サーバ起動時に IP アドレスを指定すれば他のデバイスからもアクセスできます
$ dev_appserver.py -a 192.168.1.5 myapp

-a オプションで渡した IP アドレスがローカル開発サーバのホストになります。
上の例の場合では、同じネットワーク内から 192.168.1.5:8080 でアクセスできます。
3DS や スマホ用のアプリを作っている時には実機で確認するのに便利です。
ちなみに localhost:8080 ではアクセスできなくなるので要注意です。


3DS上でデバッグ

開発用ローカルサーバについての詳細は公式サイトをご覧ください

    The Go Development Server - Google App Engine
    https://developers.google.com/appengine/docs/go/tools/devserver

2013年7月14日日曜日

GAE + Go で管理者専用機能を作る

GAE + Go でデバッグツールや、データの削除ツールなどをアプリ内に同梱する場合、
該当する URL パターンを管理者専用にできます。

app.yaml を開き、管理者専用にしたい URL に login: admin を指定します。
application: appname
version: 0
runtime: go
api_version: go1

handlers:
# 管理者専用の API を設定 #
- url: /debug
  login: admin
  script: _go_app

- url: /.*
  script: _go_app

login: admin に設定した URL へアクセスしようとすると、
以下のようにログインページヘ遷移され、アプリ管理者のログインを求められます。
(写真は認証方式を Google アカウントにしている場合です)



ちなみにローカル開発環境では以下の様なフォームが出力されます。
"Sign in as Administrator" にチェックを入れると認証が通ります。


デバッグ用のページは管理者専用に設定しましょう。


詳しくは公式のドキュメントをご覧ください。

    Requiring Login or Administrator Status - Google App Engine    https://developers.google.com/appengine/docs/go/config/appconfig#Requiring_Login_or_Administrator_Status

2013年7月13日土曜日

godoc で Go のドキュメントを生成する

Java には JavaDoc, JavaScript には JSDoc がありますが、
Go には公式のドキュメント生成ツールとして godoc があります。

    Godoc: documenting Go code
    http://golang.org/doc/articles/godoc_documenting_go_code.html 

GAE の SDK for Go を入れていればそのまま使えます。
$ godoc -html ./model > model.html
出力された HTML は下の写真です。


しかし、このままではスタイルや JavaScript が参照されていません。
デフォルトの HTML テンプレート内で CSS や JS を参照していないためです。

テンプレートはSDK 内の goroot/lib/godoc/godoc.html が使われます。
CSS と JS は以下にあります。

    goroot/doc/style.css
    goroot/doc/godoc.js 

テンプレートのHTMLからこれらのファイルを参照すると、
公式サイトと同じデザインになります。
あとは、必要に応じてスタイルを編集すれば OK です。

私の場合は、 <frameset> を使ってこんな感じのテンプレートを作りました。


godoc はファイルの先頭部分や、関数名の直前に書かれたコメントを拾ってくれます。
/* */ ではなく // を使うのが一般的なようです。

ついでに、godoc を生成するシェルスクリプトを書いておき、
コミット前に実行すると常に最新のドキュメントがプログラムに同梱できて便利です。

godoc.sh
#!/bin/sh
godoc -html ./server > ./document/server/server.html
godoc -html ./server/config > ./document/server/config.html
godoc -html ./server/controller > ./document/server/controller.html
godoc -html ./server/model > ./document/server/model.html
godoc -html ./server/view > ./document/server/view.html
godoc -html ./server/lib > ./document/server/lib.html
実行
$ sh godoc.sh



ちなみに、godoc とは別に GitHub のリポジトリの URL を貼り付けると、
自動的にドキュメントを生成してくれる Web サービスなどもあるようです。
自分でテンプレートを作るのが面倒なときはこっちのほうがいいかも。

   GoDoc
   http://godoc.org


2013年7月9日火曜日

GAE + Go で他ディレクトリの go ファイルを読み込む

GAE + Go では import 文で他のディレクトリ内の go ファイルを読み込むことができます。

import 文でアプリケーションルートディレクトリから、
読み込みたい go ファイルが置いてあるディレクトリまでを指定することで、
対象ディレクトリ内のすべての go ファイルを読み込むことができます。

例えば以下の様な分割をしていたとします。




view 内の go ファイルから model 内の go ファイルを参照するとします。
以下のように import 文を書きます。

view/hoge.go
package gae

// approot 直下の model ディレクトリ内のすべての go ファイルを読み込む
import "model"  

func showModel() {
    data := model.GetData()
    fmt.Fprintf("Data is %s", data.ToString())
}

package をインポートしたときと同様に、
関数や変数を使うときには読み込んだディレクトリ名を先頭に付けます。
data := model.GetData()

先頭にディレクトリ名を付けたくない場合は、以下のように読みこめばOKです。
package gae

import . "model"

func showModel() {
    data := GetData()
    fmt.Fprintf("Data is %s", ToString())
}

また、パッケージと同様で、
関数名や変数名は大文字で始まるものだけが外部から参照できます。
小文字で始まる関数を別のファイルから使うことはできないので注意が必要です。

2013年7月5日金曜日

Go + GAE で HTML テンプレート内に変数を展開

HTML テンプレート内に以下のような {{}} 構文を書くと変数を展開することができます。
昨日のコードをそのまま編集します。

html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello Template!</title>
  </head>
  <body>
    <h1>Hello Template!</h1>
    <div>
      私の名前は {{.Name}} です。
    </div>
  </body>
</html>

go
package helloworld

import (
    "net/http"
    "html/template"
)

func init() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    t, err := template.ParseFiles("app/template.html")
    if err == nil {
            contents := make(map[string]string, 1)
            contents["Name"] = "y.okano"
            t.Execute(w, contents)
        }
    })
}
構造体やマップを作って template.Execute() に渡すと該当する変数を探して展開してくれます。

2013年7月4日木曜日

Go + GAE で HTML ファイルを表示

Go + GAE で HTML ファイルを表示する方法です。

環境構築は昨日の記事をご覧ください。
http://yokano-jp.blogspot.jp/2013/07/google-app-engine-go.html


HTML ファイルを作成

画面に表示される HTML ファイルを作成します。
今回は ApplicationRoot/app/template.html として作成しました。
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello Template!</title>
  </head>
  <body>
    <h1>Hello Template!</h1>
    <div>
      HTML ファイルを出力するテストです
    </div>
  </body>
</html>


HTML ファイルを表示

Go のスクリプトを以下のように編集します
package helloworld

import (
    "net/http"
    "html/template"
)

func init() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        t, err := template.ParseFiles("app/template.html")
        if err == nil {
            t.Execute(w, nil)
        }
    })
}

これで localhost:8080 へアクセスすると HTML ファイルが表示されます。


2013年7月3日水曜日

Google App Engine + Go の開発環境構築

Google App Engine では無料でウェブアプリをホスティングすることができます。
また、データベースやユーザ管理など便利な機能が色々と付いています。

サーバサイドとして使える言語は Java, Python, Go, PHP です。
今回は Go を使った場合の開発環境の整え方です。


Python のインストール

まず、Python をインストールします。
GAE の SDK に Python スクリプトが含まれているため必要となります。
Mac OS X の場合はデフォルトでインストールされているので不用です。
Windows を使っている場合は以下からダウンロード、インストールしてください。

    Python.org


SDK のインストール

GAE の開発キットをインストールします。
公式サイトの Downloads をクリックして SDK のダウンロードをしてください。

    Google App Engine - Google Developers


PHP, Python, Java, Go 用の4種類があるので Go を落とします。
また、OS 毎に SDK が異なるので自分の OS に合わせてダウンロードして下さい。

zip を展開すると google_appengine というフォルダが出来ます。
フォルダを好きな場所に置き、パスを通しておいてください。
Mac なら Application ディレクトリに入れておけば OK です。

ターミナルを開いて以下のコマンドが実行できるか確認します。
何かしら表示されれば OK です。
$ dev_appserver.py


Hello World!

GAE の開発用ローカルサーバを立てて Go から Hello World! します。
好きな場所に GAE フォルダを作成し、その中に helloworld フォルダを作成します。
helloworld フォルダの中身が Web アプリになります。
GAE フォルダは Web アプリをまとめておくために作っています。

helloworld フォルダ内に app.yaml という名前のファイルを作成します。
これは Web アプリの設定ファイルです。
app.yaml 内に以下をコピペします。
application: helloworld
version: 1
runtime: go
api_version: go1

handlers:
- url: /.*
  script: _go_app

helloworld フォルダ内に app フォルダを作成します。
app フォルダの中に helloworld.go を作成します。
go スクリプトはサブディレクトリ内に置かなければならないので、appフォルダを作成しました。
helloworld.go に以下をコピペします。
package helloworld

import (
 "net/http"
 "fmt"
)

func init() {
 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hello World!")
 })
}

ターミナルを開きます。
GAE/ フォルダまで移動して、以下を実行します。
$ dev_appserver.py helloworld

エラーがなければ開発サーバが起動します。
ターミナルにはサーバのログが表示され続けます。
⌘ + C でサーバを終了出来ます。

サーバが起動している状態で Web ブラウザで

http://localhost:8080/

にアクセスすると Hello World! と表示されます。



これで開発環境の構築は完了です。

2013年7月1日月曜日

Go の template パッケージと AngularJS の共存

AngularJS では HTML 内に {{}} で囲まれた部分を Angular 文として処理します。
一方、Go の template パッケージも {{}} で囲まれた部分を Go のコードとして処理します。
この2つが衝突してエラーが起きます。

GAE + Go では予め作っておいた HTML テンプレートに変数を展開するのが基本です。
このとき、HTML 内の変数が入る部分に {{.変数名}} という形式で表現します。

一方、AngularJS でも同様に HTML 内に Model の変数を当てはめて出力します。
書式も同じで HTML に {{変数名}} という形式で表現します。

AngularJS の変数を出力するために {{変数名}} を HTML テンプレートに埋め込むと、
Go が「これは Go の変数名だ」と勘違いして変数を探しに行きます。
Go 内で定義されていない変数を参照しようとするため nil pointer エラーが発生します。
runtime error: invalid memory address or nil pointer dereference

衝突を回避するために AngularJS で {{}} を別の記号に変更できます。
app.config(function($interpolateProvider) {
 $interpolateProvider.startSymbol('{[{');
 $interpolateProvider.endSymbol('}]}');
});

これで {{変数名}} が Go の変数を、 {[{変数名}]} が JS の変数を指すようになります。

2013年6月30日日曜日

Go の template パッケージで map の key を参照する

GAE + Go では HTML を html/template パッケージで出力することが基本になります。
このとき {{}} 構文によって Go 内の変数を HTML 内に展開することができます。

array や map や slice の中身を順次取り出しながら表示する場合は
{{range}}{{end}} 構文を使って書くことができます。
<ul>
  {{range .}}
    <li>{{.Name}}さんこんにちは</li>
  {{end}}
</ul>

ただ中身を表示するだけならこれでよいのですが、
map を使っている場合、どうしても key を埋め込みたい時があるでしょう。
(クリックした要素の key をサーバへ返したいときなど)

この場合は以下のように for each 文っぽく key とvalue を変数に入れることができます。
<ul id="gamelist">
  {{range $key, $val := .}}
    <li class="game" key="{{$key}}">
      <div class="title">{{$val.Name}}</div>
      <div class="description">{{$val.Description}}</div>
      <div class="thumbnail"><img width="200" src="/client/img/living.png"></div>
      <a href="/editor?game_key={{$key}}"><button class="edit">作る</button></a>
      <button class="copy">コピー</button>
      <button class="delete">消す</button>
    </li>
  {{end}}
</ul>

ちなみに $val は無くても同じように動きます。



地味に 100 本目の投稿です。

2013年6月28日金曜日

GAE + Go でログを取る

GAE + Go では appengine パッケージにログを取る命令が入っています。

The appengine package - Google App Engine
https://developers.google.com/appengine/docs/go/reference

import (
    "appengine"
    "net/http"
)
func init() {
    http.HandleFunc("/", debug)
}
func debug(w http.ResponseWriter, r *http.Request) {
    c := appengine.NewContext(r)
    c.Debugf("Debug")
    c.Infof("Infomation")
    c.Warningf("Warning")
    c.Criticalf("Critical")
}

c.Infof() や Debugf() でログを取ることができます。
ローカル開発よサーバの場合、コマンドプロンプトにログが出力されます。
本番環境の場合はアプリ管理画面にログが出力されます。
Debug だけ表示、Error だけ表示などのように絞込みも可能です。


2013年6月26日水曜日

GAE + Go でメールを送る

Google App Engine ではメールの送信もできます。
ユーザ新規登録時の確認メールなどに使えます。

送信元になるメールアドレスはデフォルトで

  • アプリ管理者のGmailアドレス
  • string@appid.appspotmail.com

が使えます。
string は任意の文字列、appid はアプリURLの ***.appspot.com と同じ文字列です。

メールを使うには app.yaml に以下を追加する必要があります。
inbound_services:
- mail

以下のように送信します。
message := new(mail.Message)
message.Sender = "infomartion@appid.appspotmail.com"
message.To = []string{"who@example.com"}
message.Subject = "タイトル"
message.Body = `

メールの本文です。
複数人にも送ることができます。

`

c := appengine.NewContext(r)
err := mail.Send(c, message)
if err != nil {
    c.Errorf(err.Error())
}

2013年6月24日月曜日

datastore の String にバイナリをいれてしまったら

GAE + Go で datastore の String 要素にバイナリデータを入れると、

localhost:8080/_ah/admin

のデータストア管理画面がエラーを吐くようになります。


これでは中身が見れないのでデータストアをクリアしなければなりません。
GAE のローカルサーバを起動するときに -c または --clear_datastore オプションを付けます。
$ dev_appserver.py --clear_datastore myapp

これでデータストアをクリアすることができ、エラーが出なくなります。
バイナリデータを保存するときには必ず []byte を設定するように注意しましょう。