-
Go
->Python
差し替え編 - クライアント(
Vue.js
)編
執筆中です。
価格・安全性など重要事項は随時ご自分で調べ、自己責任で作業をしてください。
筆者はいかなる損害について責任を負いかねます。
はじめに
低予算(規模が十分小さければ無料)でREST APIサーバーを作りましょう。
DBあるよ!
概要
まず、低予算で推奨されるのが サーバーレス です。
厳密性を無視して簡単に言うと、 常時待機するのではなく、必要な時だけ動作するサーバー というイメージです。低予算でいける理由がこれでわかりますね。
思ったよりやること、というよりかは扱わないといけない機能が多いです。
-
Cognito
ユーザー管理を全部代行してくれる神機能の王、神機能キングです。
ログイン画面 のフロントエンドすら用意してくれます。めっちゃ安いというかだいたい無料です。もしユーザー認証が必要なければ、Cognitoを使わず、一個下に書いてある
API Gateway
で全員共通のAPIキーを作り、それで認証することもできます。 -
API Gateway
その名の通り、API通信の「門」です。
アクセス負荷, アクセス制限, バリデーション など防衛的なお話はだいたいここの機能で行います。 -
AWS Lambda
サーバーレスAWSの肝要です
Lambdaという名の通り、ラムダ関数を用意するというコンセプトです。
Go
なりPython
なりC#
なり各々の言語で、- 引数: リクエスト
- 返り値: レスポンス
の関数を作るというわけです。
-
Dynamo DB
AWSが用意しているDBの中で唯一無料枠が提供されている種類です。非リレーショナルで、データは
JSON
で扱われ、SQL
は使えません。
実装
Lambda関数をGolangで書く
中級以上のプログラマー向けにコーディングの概形や雰囲気を把握してもらうための記述をしていまして、各記述の詳細は各自お調べください。
まずは、通常のGolang書きと同じように、モジュール作るべくgo mod init
などをしてください。
POSTリクエストを受け取り、レスポンスを返す
下記のパッケージが必要になります。
go get "github.com/aws/aws-lambda-go/events"
go get "github.com/aws/aws-lambda-go/lambda"
まず、大枠から。
package main
import (
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
//リクエストJSON
type Request struct {
vari string `json:"vari"`
}
//レスポンスJSON
type Response struct {
vari string `json:"vari"`
}
func requestHandler(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
// リクエストを受け取る
request := Request{}
err := json.Unmarshal([]byte(req.Body), &request)
if err != nil {
//エラーログ
fmt.Println("Error parsing request: ", err, "; ", req.Body)
//HTTPステータス400のレスポンスを返す
return events.APIGatewayProxyResponse{StatusCode: 400}, fmt.Errorf("error parsing request: %v", err)
}
//...いろいろな、処理...
// レスポンス作成
response := Response{Token: token}
responseJson, err := json.Marshal(response)
if err != nil {
// エラーログ
fmt.Println("Error marshalling response: ", err)
//HTTPステータス500のレスポンスを返す
return events.APIGatewayProxyResponse{StatusCode: 500}, fmt.Errorf("error marshalling response: %v", err)
}
return events.APIGatewayProxyResponse{StatusCode: 200, Body: string(responseJson)}, nil
}
func main() {
lambda.Start(requestHandler)
}
こうやってリクエストを受け取り、レスポンスを返します。(不親切な説明)
CognitoユーザーID取得
もしCognito
のユーザーIDを取得したい場合は、
func getUserId(req events.APIGatewayProxyRequest) (string, error) {
cognitoAttributes, ok := req.RequestContext.Authorizer["claims"].(map[string]interface{})
if !ok {
return "", fmt.Errorf("couldn't get cognito attributes")
}
userId, ok := cognitoAttributes["sub"].(string)
if !ok {
return "", fmt.Errorf("couldn't get userId")
} else {
return userId, nil
}
}
ちょっと大変ですがこんな感じ。
(要するにAuthorizer
-> claims
-> sub
からCognito IDを取得できます)
Dynamo DBとのデータ出し入れ
github.com/guregu/dynamoを使うととても便利です。
こちら参照(パッケージ作成者本人による解説記事): 気楽にDynamoDBを使おう
Zipにする
AWS Lambdaに投稿するには、zipにしなければなりません。
筆者はWindowsのPower Shellを使っておりますが、こちらの呪文をコピペして
cd (main.goがあるディレクトリ)
$env:GOOS = "linux"
$env:GOARCH = "amd64"
$env:CGO_ENABLED = "0"
go build -o bootstrap main.go
当該ディレクトリに生成されたbootstrap
ファイル 一つだけ を.zip
に圧縮しています。
このzip
ファイルをAWS Lambdaにアップロードします
いよいよマウスでカチカチするノーコードタイムです。この設定作業が楽しい人がいるか分かりませんが、プログラミングだけが好きな筆者にとっては苦痛ですね。
もちろんですが、AWSのユーザー登録をして、AWSコンソールにアクセスしてくださいね。
Cognito設定
ユーザープール を作ります。IDプールは使えなかったです(泣)
サインインオプション。ログイン画面で入力するアレを指定できます。
次のステップに移りましてセキュリティ要件。
デフォルトのパスワード要件がけっこうガッチリしていますので、必要にあわせて調整。
二段階認証の可否も必要に合わせて調整(デフォルトは「必須」になっています)
次のステップに移りましてサインアップエクスペリエンス
- 自己登録とは ユーザー登録機能 を指します。 オフにすると、管理者が一人ひとり手動で登録する、という仕様になります
-
検証と確認 とは、ユーザー登録の際のメアド認証ないし電話番号認証のメールを飛ばすやつです。必要に応じて。
次のステップに移りましてアプリケーション設定
- ホストされたUI は Cognitoがログイン画面を代わりに提供してくれる神機能 です。後述参照。
- 身内だけでユーザー管理をする場合は クライアントシークレット を設定するべきだそうですが、公開APIを作成する場合は 生成しない に設定。
ホストされたUI にチェック入れると、こんな設定画面が。
そのCognitoドメインってのが、Cognitoが提供してくれるログイン画面になります。
これでCognitoの設定完了です。
Dynamo DB
テーブル作成の設定はこれだけ。
パーティションキー は、RDBでいうところの「 主キー 」です。
まあ各データのどの項目を「ID」にするか、ということです。だいたい。
これでDB設定は終わりです。
JSON管理DBですので(?)、パーティションキー以外に 列名などの事前登録はせず、Lambda側に委ねられています
IAM
現状のままでは、 LambdaがDynamo DBを編集する権限がありません
AWSのサービス一覧に「IAM」というのがありまして、そこから設定しないといけません。
具体的な権限を付与します。
「dynamo」と検索すると4つ出てきますね。
- AmazonDynamoDBFullAcccess
- AmazonDynamoDBExecution
これでDynamoDBデータ出し入れロールが作成できました。
Lambda
「関数を作成」を選択。
- 「一から作成」
- Golang の場合は、ランタイム を 「Amazon Linux」 に
- 実行ロール は、IAMで作成したDynamoアクセスロール をセット。
Zipをアップロード。
Golangのところで作成したzipファイルをドラッグアンドドロップでアップロード。
終わりです。
テストしたい場合は、「テスト」から テンプレート から 「apigateway-aws-proxy」を選択。
リクエストボディはどうしてかこんな感じでJSONをエスケープ付きの文字列にしないといけないようです。
文字列化はこのサイトが便利
API Gateway
ここの設定が複雑で苦痛です。
APIを作成
「リソース」を作成でURIの末端部分を指定できます。
話によると、/
自体にメソッド(機能)を持たせるとDDos攻撃を受けやすくなるらしいです。
Webサイトからのアクセスを想定する場合、 CORS にチェックつけるのをオススメします、というかチェックしないとCORS制限にひっかかります。
「メソッドを作成します」
OPTIONはそのまま にしましょう。それはCORSに使われるのでいじらない方がいいです。「プリフライトリクエスト」ってやつです[参考]
メソッド作成はこれで完了
認証機能をつける
Cognitoの認証機能を付与します。
さあ「リソース」へ戻って「メソッドリクエストの設定」から「編集」
これで、リクエストヘッダーにCognitoから与えられたトークンを入れてないと弾かれる、という ユーザー認証 ができます。
バリデーション
モデルの記法はこんな感じ。AWS 開発者ガイドより引用。
{
"type" : "object",
"required" : [ "name", "price", "type" ],
"properties" : {
"id" : {
"type" : "integer"
},
"type" : {
"type" : "string",
"enum" : [ "dog", "cat", "fish" ]
},
"name" : {
"type" : "string"
},
"price" : {
"type" : "number",
"minimum" : 25.0,
"maximum" : 500.0
}
}
}
デプロイ
ステージは、(ドメイン)/(ステージ名)/(リソース名)
というような感じでURIに現れます。
慣習的には、テスト段階ではbeta
、本番ではv1
と指定します。
デプロイ完了!!
URIを確認するには
末筆
以上です。
あまり丁寧に記述しなかった点は多々ありますが(というか全部?)、情報不足などあれば積極的にコメントに書いていただければ、随時追記します。
この記事に「いいね」をくだされば、泣いて喜びます!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!