えいのうにっき

a-knowの日記です

mercari/datastore を使った GAE datastore への基本的な CRUD を試してみた

GAE(Standard Environment)で動作するWebアプリケーションをGoで書いている。サインアップしたユーザーの情報などを永続化しようとした場合、GAE で素直にやるとすると Datastore を使うことになる。昔 Java で GAE アプリケーションを書いていたときには Slim3 というフレームワークを使って Datastore に対する操作をおこなっていたが、現代・Goで、となると「これかな」と思っていたのが、mercari/datastore。

github.com

自分の言葉で「つらい」といえるほど、標準ライブラリでの datastore 操作をやってきたわけではないし、その他のなにかと比べてみたわけでもない。......のだけど、GAEに強いあんな人やこんな人が集まるメルカリ謹製のラッパーなら大丈夫なんだろう、ということで、いったんはこれを使って開発を進めていくことに決めた。ただ、上記リポジトリのREADME内 How To Use がまだ書かれていなかったので、まずは自分で mercari/datastore を使った基本的な CRUD を試してみた。今回のエントリはそのメモ。

「GAEを始めたい」「Datastoreの操作がよくわからない」「mercari/datastore を使ってみようかな」という人はどうぞ。将来上記の How To Use に書かれるであろう内容に近いものにはなっているんじゃなかろうかと思いつつ、Best Practice ではきっとない、という気持ちもあるので、そういうつもりで見てもらえたらと。

続きを読む

GAE/Go で gomniauth を使う

最近また Google App Engine をやっている。

cloud.google.com

できるだけ面倒なことはしたくないんだけど、作ろうとしているものの性質上、ログイン機能は外せず...。。『Go言語によるWebアプリケーション開発』の学習でも使った stretchr/gomniauth を使って同じように実装してみると、http.DefaultTransport and http.DefaultClient are not available in App Engine. See https://cloud.google.com/appengine/docs/go/urlfetch/ といったエラーが。urlfetch ... あー。

GAEから外部APIへリクエストをするためには、専用パッケージである urlfetch を使う必要がある。

自分で実装してる部分の話なら素直に urlfetch を使えばいいだけなんだけど、今回のエラーは gomniauth の部分で出てるエラーなので、なんとかして gomniauth の使うクライアントを差し替えてやる必要がある。

gomniauth のリポジトリを少し漁ってみたところ、いいコミット(コミットメッセージ)があった。

Support for Google AppEngine urlfetch for OAuth2

To use http in Google AppEngine, you have to use urlfetch, not the normal default http client or RoundTripper. So similar to what one of the forks of goauth2 did, this adds the ability via the now-added common/SetRoundTripper to pass in the specific RoundTripper to use. If unset, the default net/http one will be used. However, by calling this method, you can pass in your own including one created via urlfetch. Here is sample code showing it in use:

https://github.com/stretchr/gomniauth/commit/3e2e23995b035e26bbd58a0f56cb2b2d61dbe993#diff-faa162d8416db3f39bdfe91ca8eea4de

上のコミットメッセージに付記されていた実装例は以下。

import (
  "appengine"
  "github.com/stretchr/gomniauth/common"
)

func SomeGolangFunc([...,] r *http.Request [,...]) {
  c := appengine.NewContext(r)
  t := new(urlfetch.Transport)
  t.Context = c
  common.SetRoundTripper(t)

  // Do something interesting here
}

これを参考に自分の実装も手直ししてみたところ、うまくいった。よかった。

上記のコミットメッセージには、以下のような注意点も加えて書かれていたので、この点は気をつけておいたほうがよさそう。

Note that common.SetRoundTripper may have to be called in the GAE server before every request, versus trying to do it once because of the appengine.Context being passed in. Pretty sure you cannot pass in a nil *http.Request and re-use the context, so you can't make the call during the GAE init() method.

今回の件にあたり、いろいろとググったりもしてみたところ、gomniauth に限らず、いろんな実装でこうした配慮がされてそうなので、このまま安心して実装を続けていけそう。