echoでmiddlewareを挟もうとしてハマった話
echoでエンドポイントにmiddlewareをはさもうとしていろいろハマったのでメモ。
echoでルーティングする場合は以下のようにecho.Echo
のGET、POSTであったり、Addだったりを呼ぶわけなんですが、それとは別に直接echo.Router
のAddを使ってルーティングしたりもできます。
echo.Echoを使う場合
e.GET("/", func (c echo.Context) error { return c.String(http.StatusOK, "HelloWorld") })
echo.Routerを使う場合
r := e.Router() r.Add("GET", "/", func(c echo.Context) error { return c.String(http.StatusOK, "HelloWorld") })
私の場合はecho.Router
を使っていてmiddlewareをどうやって挟もうかと考えていたのですが、ドキュメントを見ても見てもやり方が分からず諦めてソースを眺めていたら面倒くさくなりそうなことが発覚。以下がそのソース。
// Add registers a new route for an HTTP method and path with matching handler // in the router with optional route-level middleware. func (e *Echo) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route { name := handlerName(handler) e.router.Add(method, path, func(c Context) error { h := handler // Chain middleware for i := len(middleware) - 1; i >= 0; i-- { h = middleware[i](h) } return h(c) }) r := &Route{ Method: method, Path: path, Name: name, } e.router.routes[method+path] = r return r }
単純な話、echo.Echo
を使ってルーティングをする際にecho.Router
を内部で使っていて、そこのHandleFuncにmiddlewareを挟む処理を入れているようでした。さすがにライブラリで隠蔽されている部分を自分で実装する気にはならないので諦めてecho.Echo
を使うようにしました。。。
haskellでfizzbuzz
だいぶ昔に少しだけhaskellで遊んでたけど、すでに文法すら頭から消し飛んでたので最初からやり直してて、復習にちょうどいいかと思いfizzbuzzをサクッと書いてみました。
ソースは以下。Integerを引数にStringで返す関数を作って、mapでリストの値を適用してるだけです。普通だと配列ごと渡してやろうのだろうけど、めんどくさかったのでこんな感じ。
fizzbuzz :: Integer -> String fizzbuzz n | n `mod` 15 == 0 = "fizzbuzz" | n `mod` 5 == 0 = "buzz" | n `mod` 3 == 0 = "fizz" fizzbuzz n = show n main :: IO() main = do print $ map fizzbuzz [1..10]
haskellで数値から文字列へのcastがよくわからなかったけど、普通にshowを使えばよかったっぽい。showってもっとごちゃごちゃしてた気がするけど、今はとりあえずcastってことだけ覚えとく。
http://hackage.haskell.org/package/base-4.0.0.0/docs/Prelude.html#22
Google SpreadSheetからGASでSlackに定期的に投稿する
ちょっとしたことを勉強している時に、単語とかすぐ忘れるので単語帳代わりにSpreadSheetに書いてたまに見たりしてるのですが、それでも忘れるのでGASでslackに定期的に投稿するようにしました。
やったことは以下。
- slackのアプリ登録
- GASでslackに投稿するようにする
- トリガーの登録
slackのアプリ登録
他のアプリ連携でもそうですが、Slackに投稿するためのアプリケーションを作成します。
Slack API: Applications | Slack
Create NewAppからアプリケーションを作成して、Bot Userに追加します。
GASでslackに投稿するようにする
GASからslackに投稿するためのライブラリみたいなのは多いと思いますが、やりたいことは定期的に投稿するだけなので、incoming webhookを使ってpostリクエストを投げるだけにします。
slackで作成したアプリケーションの画面でFeatures > Incoming Webhooks
に行って、webhookを使えるようにします。
webhookを使えるようにすると、Workspaceに追加できるようになるので追加します。追加すると、webhookのURLが表示されるので、そちらにpostリクエストを送ればslackに投稿できるようになります。
GASからhttpリクエストを送るためには、UrlFetchAppのfetchを使えばいいです。
Class UrlFetchApp | Apps Script | Google Developers
トリガーの登録
あとは定期的に実行するために、トリガーに登録します。
編集 > 現状のプロジェクトのトリガー
を選択して、トリガーを追加します。分単位・時間単位などで指定できるので大変便利です。
まとめ
さっくりGASを使って、slackに定期的に投稿できるようにしました。GAS自体はjavascriptとほとんど同じでかつ、googleのアプリケーションに接続するライブラリが内包されていてすぐに呼べるので実際ほとんど処理を書く必要がなくて大変楽です。ただ、ブラウザでコード書くのは大変なので、githubにpushしたら反映されるようにしたいなーと思ったので、次回はそのへんをやりましょうかね。
angularの勉強にTour of Heroesをやった
仕事でangularを使うことになりそうなので、入門がてらに、Tour of Heroesをやってみました。
Tour of Heroes は、Angularの基礎を学ぶためのチュートリアルで、angular-cliを使ってプロジェクトを作成するところから、最終的にはangularに付属しているhttpライブラリを使用して、APIを叩くところまでやります。その間にもcomponentを追加したり、分離するためにServiceを挟んだりと色々勉強になります。
まだ入門なので、大したことはわかりませんが、React、vueと違って全部入りのフレームワークなので、頻繁にyarnで何がしかのライブラリを引っ張ってこなくていいというのは個人的には楽だなーという印象ですが、Angular自体が半年ごとにメジャーバージョンがあがるので、破壊的な変更が複数あった場合に関連する箇所を一気に変更しないといけないのは少々怖いなーと思ったりします(にわかなので間違ってたらすいません)。
一通り入門は終わったので次は自分で何か作ってみようかと思います。
追記
終わったあとに気づいた、Tour of Heroesの日本語訳。
goでDBのテストを書くときに、go-sqlmockを使ってみた
goでDB周りのテストをするときに、毎度テスト用のDBにデータを流し込んで終わったら削除する、みたいなことをしていたのだけれど、若干面倒だなーと思い始めたのでgo-sqlmockを使ってみました。
go-sqlmockはgo用のmockライブラリです。
公式のサンプルではそのままdatabase/sql
を使っていますが、普通にgormでも使えて以下のような感じで使えます。
func main() { db, mock, err := sqlmock.New() if err != nil { log.Fatal(err) } gdb, err := gorm.Open("sqlmock", db) if err != nil { log.Fatal(err) } // 後は、gorm.Openの返り値を使って色々やる }
gorm.Openの引数にsqlmock
を使っていますが、内部でそれに対する値があるわけではないのでwarningが出ますが、特に問題なく使えます。
具体的な使い方ですが、リポジトリのexampleがあるのでそちらを参考にするといいと思います。
加えて、微妙にハマった点ですが、go-sqlmockではクエリを正規表現でマッチングしている都合上、テストコードに正規表現混じりのSQLを書くか各メタ文字をエスケープする必要があります。そのせいでテストがなかなか通らなかったりしたのですが、regexpのQuoteMetaを使うと、一括でメタ文字をエスケープしてくれるので大変便利です。
regexp - The Go Programming Language
QuoteMetaを使うとだいたい以下のような形で書き換えられます。
// regexp.QuoteMetaを使わないもの mock.ExpectQuery("^SELECT (.+) FROM samples$") // regexp.QuoteMetaを使ったもの mock.ExpectQuery(regexp.QuoteMeta("SELECT * FROM samples"))
感想
goのDBのテストにgo-sqlmockを使ってみました。テスト用のDBから読み出すことに比べて事前に何のデータは入っているかを意識しなくていいので心持ち的にはだいぶ楽になったように思います。加えて、regexp.QuoteMetaを使えば細かいこと意識しなくてもよくなるのでこちらも楽になりました。ただ、細かい速度比較はしていないので、大規模なアプリケーションで使う場合は確認したほうがよいかと思います。
nuxtでRESTっぽい感じに重複したルーティングをする
特に難しいことを考えなくても色々できるので、最近はよくnuxtを触っているのですが、RESTっぽい感じに階層的なURLで動的なルーティングはどうするんだろうって思ったので、試してみた。
公式のリンクは以下。
上のリンクをたどればわかりますが、単純にidなどでルーティングしたいのであれば、pagesで以下のような形にします。ここの_id.vue
では、params.id
という形でidを受けることができます。
pages - users - _id.vue
次に、階層的なルーティングは以下のような形でできました。下の例はユーザの趣味の一つを表示する的な意味合いでやっています。特徴的なのは上の例では、vueファイルに対して、_id
という名前をつけましたが、階層的にルーティングをする場合は、ディレクトリに対して名前をつけています。
pages - users - _user_id - hobby - _hobby_id
werckerでs3にdeployしてみた
個人プロダクトをnuxt.jsを使ってSPAを書いているのですが、楽にデプロイしたいと思って、werckerを使ってみました。
werckerはTravis CIなどと同様のCIのサービスで、フリープランでもprivateリポジトリに対して導入できるという特徴があります。
wercker自体の導入は簡単で、wercker側でリポジトリの登録をして、登録したリポジトリに対して、wercker.ymlを入れるだけです。wercker.ymlはシンプルなものであれば、導入時にテンプレートが用意されているので、それを軽く修正する形で問題ないと思います。私の場合は、nuxt.jsで書いたアプリをbuildしたかったので、node環境のテンプレートを修正する形にしました。
以下が私が書いたものの一部です。本来はbuild stepを分けるべきなんですが、werckerのworkflowがうまく組めなかったので、諦めてdeploy stepに全部書いてます。
deploy: steps: - npm-install - script: name: build nuxt code: | npm run build - s3sync: key_id: $AWS_ACCESS_KEY key_secret: $AWS_SECRET_KEY bucket_url: $AWS_BUCKET_URL source_dir: dist/
s3にデプロイしている部分はs3sync
です。s3syncには、deploy用に作成したIAMユーザーのaccess keyとaccess secret keyを設定します。bucket_urlは配置するバケットのurlを乗っければいいです。例えば、hogehoge
というバケット名であれば、s3://hogehoge
でいけます。source_dirはs3に送るディレクトリになります。
ここで変数で指定している部分については、wercker側で設定する値になります。あとは、wercker側でpush時にpipelineが走るようにすれば概ね完了です。
あとは、pushしてしまえば、wercker側でpipelineが走って、上記だとs3にdistが配布されることになります。