golangのお勉強4 + apex + lambda


# 概要

swaggerで作ったコードを使うのか、別の書き方をするのか、lambdaにするのか、golangの使い方をちょっとずつ調べる。

# golang on lambda

» Apex で Go はどう実行されているのか TECHSCORE BLOG
http://www.techscore.com/blog/2016/12/08/how-does-golang-run-on-apex/

nodeで標準出力経由なので２回プロセスが立ち上がる

eawsyのaws-lambda-goを使ってみる — そこはかとなく書くよん。
http://tdoc.info/blog/2016/11/02/eawsy_lambda.html

nodeの標準出力経由じゃなく実行する手法（pythonからバイナリの拡張として実行）
よさそうだけど保留

AWS Lambdaで効率的にgoバイナリを実行する — そこはかとなく書くよん。
http://tdoc.info/blog/2016/01/07/lambda.html

> そのため、一回一回のリクエストのたびにプロセスを立ち上げるコストが掛かり、毎回500msecほどかかってしまう、という事になってしまいます。	
この問題点を解消するライブラリがlambda_procです。

lambda_procでプロセスの立ち上げを最初だけにする方法。
そのぶん、お金はかかる認識であってるかしら。

# packageをどう読み込むのか

lambdaに上がるのはバイナリで、コンパイルはローカルで実行するからどこにパッケージがあっても大丈夫。。という認識。

# 関数の戻り値の捨て方

```
_,err := hoge()
```

# 構造体について

Golang 構造体と仲良くなろう - Qiita
http://qiita.com/kkam0907/items/92d3d31c84c596eacaee

構造体とポインタとがある。
この辺まだ不安。

# Api記述のライブラリ

------------------------------------------------------------------------------------------------
	せっかくswagger使うんだしswaggerに合わせる（任せる）かなあ。。
------------------------------------------------------------------------------------------------

* swaggerのコード

	Go言語でServer作る時に必要な知識メモ - Qiita
	http://qiita.com/awakia/items/ef8978fc33ffb1d27460

	mux（ムック）というライブラリでルーティングして、各ファイルの関数を実行
	muxはデフォルトのものよりリッチなルーティングがしたいときの選択肢なのかな

	ListenAndServe()からserve()まで辿ると、serveHTTP()を実行している。
	ここでwriter,responseを受け取ってhandlerを呼び出し始める。多分。

	API Gateway + Lambdaでcatch allした処理をApex + Goでnet/httpで扱える ridge を書いた - 酒日記 はてな支店
	http://sfujiwara.hatenablog.com/entry/2016/10/03/153022
	
	環境変数でローカル実行とlambdaの両方を記述
	ルーティング処理はlambdaのridgeで行う
	こちらのコードも、writerとrequestを渡して関数を実行してるな。。
	これならswaggerのコードを流用しやすそうな気がする。

* echo

	自分で導入できるか試して動いてはいたはず。。
	ルーティング以外にも機能面でメリットがあるんだっけ。。

* 他

	Go言語でServer作る時に必要な知識メモ - Qiita
	http://qiita.com/awakia/items/ef8978fc33ffb1d27460
	
	いろいろある。。気になるけど保留。

# デバッグ

IntelliJ CE + Delve で Go 言語のデバッグ環境構築(Mac) - Qiita
http://qiita.com/mxxxxkxxxx/items/db952ddf5b13a594b55e

Go言語のデバッガをMacのIntelliJ IDEA CEで使う - くじらにっき++
http://kujira16.hateblo.jp/entry/2017/01/20/161012

# lambdaにあげてつかってみてもうまく動いてくれない

## API Gateway からCloudfrontのエラーが返ってくる

どうやら内部的に使っているらしい。
認証情報がうまく受け渡せないが理由がわからない。。

Amazon CloudFrontでAPI Gatewayの痒いところに手を届ける ｜ Developers.IO
http://dev.classmethod.jp/cloud/cache-api-gateway-by-cloudfront/

> ご存じの方もいると思いますが、そもそもAPI Gatewayは内部でCloudFrontの仕組みを利用しており、スケーラビリティやアベイラビリティの面でCloudFrontの特徴を享受しています。しかしながら、CloudFrontのフル機能をAPI Gatewayで利用できるわけではないため、場合によっては以下の図のようにAPI Gatewayの手前にCloudFrontを置く構成を取ることがあります。

## 試しに認証をはずしてみたがタイムアウトしてしまう

golangで相対パスでライブラリを読み込んでるせいだと思う。実行ファイルが大きくなってる。
hello worldだと問題なかったのに。。
~~たぶん、このへんはライブラリの呼び出しについて工夫すればいいのだろう。。~~
結果的には、lambda(Node.js)と実行ファイル(Golang)の間の値の受け渡し方法を
文字列に変更（構造体を渡してたわ）したら問題なかった。
標準出力でやりとりしてるからかと。。
でもまあ、Nodeが間にあるかは関係なく、webapiなのだから文字列で出力するのはあたりまえか。

この辺も、デバッグをしやすくしておかないと厳しいな。。
golangがわで、出力の手前でチェックをかければ、、それでも不測の事態がおきたらエラー箇所を探すのが大変そう。。
cloudwatchとかaws-xrayとかを理解したらいけるのかしら。。

この例は多分関係ないけどメモ。

Lambda + API Gateway で処理の実行がむちゃくちゃ遅くなるケースを調べた - Qiita
http://qiita.com/pm11op/items/eb148b23b062fe778bd1

## カスタム認証がうまくつかえない

cloudfrontを手前に配置する場合が多いらしいからそうすればいいのかもしれない。
なんかくやしい。
認証情報を渡すことはできているけど、deny判定されるのがなぜかわからない。。
デバッグの方法を理解しないと進めない。わからない。。

Amazon API Gateway で Custom Authorization を使ってクライアントの認可を行う ｜ Developers.IO
http://dev.classmethod.jp/cloud/aws/api-gateway-custom-authorization/

> ヘッダーに Authorization: deny を付けると、アクセス拒否されます。

## ユーザー認証の事例

Amazon API Gateway の Custom Authorizerを使い、User PoolsのユーザでAPI認証を行う - Qiita
http://qiita.com/horike37/items/7e0984e7729099032930

Amazon Cognito User Poolsを使って、webサイトにユーザ認証基盤を作る - Qiita
http://qiita.com/horike37/items/1d522f66452d3abe1203

> ユーザの管理機能がサーバ側のコードを1行も書くこと無く実現できちゃうのはまじでスゴイです。
しかもセキュア。

## gopathについてわからないので調べる

direnvで設定するのは悪くなさそう。。

これからGoを始める人のためのTips集 | The Wacul Blog
http://blog.wacul.co.jp/blog/2014/08/22/go/

> GOPATH には２つ役割があります。
ビルド時のインポートパスとして、GOPATH に指定したすべてのディレクトリを参照する(コロン区切り)
go get コマンドで外部パッケージを読み込んだ時、 GOPATH の先頭のディレクトリにダウンロードする

direnvで解決するGOPATHの3つの問題点 - None is None is None
http://doloopwhile.hatenablog.com/entry/2014/06/18/010449

> direnvを使うと、プロジェクトごと（ディレクトリごと）にGOPATHを分ける事ができます。
> ところで、.envrcにlayout goを書いただけでは、 ~/gocode-foo/src以下には、プロジェクト本体と依存パッケージが区別なく置かれてしまいます。
> そこで direnv edit . で .envrcに設定を追加します。

改めて、direnvを使いましょう！ - HDE BLOG
http://blog.hde.co.jp/entry/2015/02/27/182117

> direnvは他にも追加のコマンドを用意しています。
layout program_name :その言語用の開発環境をセットアップする
PATH_add path: 環境変数PATHにpathを追加
path_add envname path: 環境変数envnameにpathを追加
詳しくはdirenv-stdlib.1.mdをご覧ください。

> また、~/.direnvrcに自作コマンドを書くこともできます。 後述のuse pythonなどは~/.direnvrcへの追記が必須です。

direnv/direnv-stdlib.1.md at master · direnv/direnv
https://github.com/direnv/direnv/blob/master/man/direnv-stdlib.1.md

> layout go: Sets the GOPATH environment variable to the current directory.

他言語から来た人がGoを使い始めてすぐハマったこととその答え - Qiita
http://qiita.com/mumoshu/items/0d2f2a13c6e9fc8da2a4

> 自分がいま書いてるコードもGOPATH以下に置く、っていうのが他言語から来た人がハマるポイントだと思う。

Goのディレクトリレイアウト、IntelliJ IDEAの設定、バージョン管理を考える - Qiita
http://qiita.com/kai-zoa/items/2ba5be2ddb370e9bf962

> この記事は当時どうにかプロジェクト単位でGOPATHを設定できないか試行錯誤していたときの備忘録ですが、もし同じことを考えてる人がいたらはっきり言ってそれは諦めることをオススメします。

なぜならプロジェクト単位でGOPATHを変えたり後述の方法でやっているような無茶をするとGoのエコシステムによる様々な恩恵が得られません。

------------------------------------------------------------------------------------------------
	まさにやろうとしてた。。
	具体的な恩恵ってなんのことかしら。
	プロジェクトを超えてgcする的なツールが用意されてるとかそういうことがあるのかな。
------------------------------------------------------------------------------------------------

## vendorがわからない。。

どうも読みに行ってくれない。
vendorじゃなくgopath直下で共通パッケージを読みに行くという記事もあれば、
実行してみるとhoge/srcをよみにいったりよくわからない。。

* 試して読み込んでくれた
	* パターン１
		* コードをfunctions以下にapex的に配置
		* パッケージをsrc直下に配置
	* パターン２
		* ひとまずfunctionsを無視してsrcディレクトリにいれて、srcもvendorも直下ではなくディレクトリを設けた

[golang]Go1.6で正式採用されたvendorの参照の挙動をみてみた – しゃまとんのたね
http://shamaton.orz.hm/blog/archives/223

Lambda x Apexで、Goで書いたラムダ関数を楽に動かす - きょこみのーと
http://kyokomi.hatenablog.com/entry/2016/11/03/145147

> GOPATH下にプロジェクトを置けば共通の実装とかをパッケージ化して使いまわせるので便利
下記の例だと resize パッケージと aws パッケージ

## apex+lambdaでのgoの構成

基本的にはこんぱいるしてからアップロードするから、
リモート側は気にしなくていいという理解。

» Apex で Go はどう実行されているのか TECHSCORE BLOG
http://www.techscore.com/blog/2016/12/08/how-does-golang-run-on-apex/

> Node.jsとGoが標準入出力パイプでやり取りしていることがわかりました。

## glideについて

調べるうちに出てきた、、vendoringはglideがスタンダードになっているらしい。
あくまでここ数年。

Go言語をMacにインストールしてみる（goenv + direnv + glide） - Qiita
http://qiita.com/keitaMatsuo/items/466c6eabac4538d9de71

> vendorフォルダ内に外部ライブラリをインストールでき、それをYAMLで管理する。
package.jsonのようなもの。

Glide で Go 言語のパッケージ管理と vendoring - Librabuch
https://librabuch.jp/blog/2016/04/go-lang-vendoring-glide/

> コマンドは glide up -u -s と省略できます。--strip-vcs オプションは、 go get の後に各レポジトリの .git ディレクトリを削除するという単純な動作をします。s
> vendor ディレクトリ配下にある vendor ディレクトリを除外する --strip-vendor オプションもあります。

## srcディレクトリとかvendorディレクトリをapex配下でどう配置すればいいのか

go以外の事例も参考。。
functionsをsrc扱いにできないかしら。

Apexを使ってAWS Lambdaを楽に管理しよう - 病みつきエンジニアブログ
http://yamitzky.hatenablog.com/entry/2016/06/09/235548

> functionsディレクトリはビルド用ディレクトリ(コミットしないディレクトリ)として割りきりましょう

------------------------------------------------------------------------------------------------
	apexだとvendorを使う想定の作りになってないのかも。わすれよう。
------------------------------------------------------------------------------------------------


## go言語について

無難にかけて質もいいけど、めんどくさいこともあるよってことかな。

なぜGo言語 (golang) はよい言語なのか・Goでプログラムを書くべき理由
http://www.yunabe.jp/docs/why_golang_is_good.html

> Goは言語デザインとして正しく使うのが難しい、乱用するとプログラムを無意味に複雑にしてしまう機能が排除されています(高度な型システム・継承・Generics・例外・イベントモデルによる並行処理など)。 そのため、ある意味ではGoは「知的な」プログラマにとっては面白みに欠く言語だと思います。実際、Goを勉強しても概念的には目新しいものはなくて勉強することそのもので何かが学べるとは僕は全く思いません。 一方でプログラミング言語を習得することのゴールは、それを使って何か大規模なソフトウェアをチームで作ることであるのだと思います。 チームで大規模なソフトウェアを開発することはそれ自体が非常に難しいことです。そのゴールのためにプログラミング言語自体はシンプルに保ち、それ以外の部分により多くの労力をさけるようにするというのは僕は正しい判断だと思います。

## Apexでgolangを使うかどうか

ここまで調べてまだちゃんと実装はしていない。
まだ準備が必要そう。
NodeからGoを呼び出す仕組みがネックになるポイントか。

* 今回はgoをやめる。nodeとか。
* 標準出力での受け渡しという点を考慮する（多分大丈夫かな。。）
* lambdaをやめてgolangで実装つつ、公式にgolangが対応（すると信じる）したら移行する
* ベンチマークを思い出す、性能的には多分意味あるのだろう

もうちょっとやってみるか。

AWS LambdaでJavaとNode.jsとGoの簡易ベンチマークをしてみた。 - 谷本 心 in せろ部屋
http://d.hatena.ne.jp/cero-t/20160101/1451665326

> Goを使った場合は性能が安定しており、ウォーミングアップしても性能が変わりません。メモリ使用量が少ないのも良いですね。Node.jsから呼び出す際のオーバーヘッドがあるせいか、性能的にはウォーミングアップ後のJavaやNode.jsに一歩劣る感じでした。

## プロキシ統合

なんとか動かせるところまで行ったけど、値がわたっておらず、ルーティングの結果、301になるみたい。。
ヘッダーの値を入力に使ってるからか。。
プロキシ統合とかマッピングテンプレートとかでいけるような。。いけない。
あれ、NodeからGoに渡すところってヘッダーの値とか渡してくれるのかしら。Apexは。
表週出力を経由してやりとりしてるから気を使ってくれてなければgo側で値が取れないかのかな。。

------------------------------------------------------------------------------------------------
	このスライドは参考になるな。
------------------------------------------------------------------------------------------------

AWS Lambda in Golang
https://www.slideshare.net/KoichiroNishijima/aws-lambda-in-golang

> マッピングテンプレートって何？ 57 ๏ Integration Requestに指定できる、URLパラメータ/パス パラメータ/HTTPヘッダなどをLambda関数のコードに渡す ためのテンプレート ๏ 想定するURLパラメータとともに、APIGWのステージやHTTP ヘッダなどをLambda関数に渡すことが出来る

API Gatewayへの入力値にLambdaからアクセスする - Qiita
http://qiita.com/r7kamura/items/6420538789da95cd2f47

ridgeの意味がやっとわかった気がする。。
swagger.yamlがかなりシンプルになるな。。やってみよう。

API Gateway + Lambdaでcatch allした処理をApex + Goでnet/httpで扱える ridge を書いた - 酒日記 はてな支店
http://sfujiwara.hatenablog.com/entry/2016/10/03/153022

Configure Proxy Integration for a Proxy Resource - Amazon API Gateway
http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-set-up-simple-proxy.html


pythonの事例だけどswagger.yamlの例もあるのでよい

AWS Lambda と Python で作る動的な HTML ページ - Qiita
http://qiita.com/kimihiro_n/items/15cce90ec93625c4445a

> リソースを /{proxy+} としてあげることで、任意のパスのリクエストを同じ Lambda でさばくことが可能です。

検証の具体的な結果がみれる

Amazon API Gatewayが非常に便利なHTTPプロキシとして進化したらしいので使ってみた - Qiita
http://qiita.com/seiya_orz/items/4e9d8c62739399b076b7


## APIGateway+lambda でのデバッグ方法

* lambda(Node)
	* console.log
* lambda(golang)
	* エラー出力らしい。
		> os.Stderr.WriteString(“hoge”)
	* apex logs appname

## apexのエイリアス

apex invokeだとcurrentを参照していて$LATESTじゃない
実際のapiをたたくなら$LATEST

## ridgeを使う

とてもよさげだけど、イシューにあるようにルーターを強化したいな。。（しなくても大丈夫だった。）

```golang
router := sw.NewRouter()
router.HandleFunc("/", handleRoot)
http.Handle("/", router)
```

まずmuxを理解したい

https://github.com/gorilla/mux

Subrouter()とかr.Walkとかつかえそうな気がする。