Claudia.jsで簡単サーバレスアーキテクチャー
サーバレスアーキテクチャと聞いて、どのようなアーキテクチャを思い浮かべるでしょうか。Martin Fowler.comのサーバレスアーキテクチャの解説記事ではいくつかのサーバレスアーキテクチャの実装例がリストアップされています。
ここでは、最もよく使われると思われるフロントエンドアプリのためのサーバレスアーキテクチャを考えてみます。
フロントエンドアプリのためのサーバレスアーキテクチャ
API Gateway、Lambdaを中心とした標準的な構成です。
- フロントエンド(SPA/Native)
- 認証認可API
- API Gateway
- FaaS (Function as a Service)
- 代表的なサービス: AWS Lambda
- 役割: BaaS連携、業務ロジック実行
- BaaS (Backend as a Service)
- 代表的なサービス: AWS DynamoDB, S3
しかしながら、実際にAWS上で一から実装しようとするとAPI GatewayとLambdaの連携、認証認可の実装、Lambdaの管理、デプロイや更新処理など面倒極まりない作業に直面します。何らかの抽象化レイヤーやツール無しにAWS上でサーバレスアーキテクチャを実現するのは困難だと実感しています。
ここでは、Claudia.jsというNode.js製のフレームワークを用いてこれらの課題を解決し、フロントエンドアプリのためのサーバレスアーキテクチャーを簡単に実現してみます。
Claudia.jsとは
AWS上でサーバレスアーキテクチャを実現するためのフレームワークの一つです。同様のフレームワークとしてServerlessやApex等が知られています。
- Apex: Lambdaにフォーカス。作者のTJがAPI Gatewayをの1st citizenで無いと言っており連携が煩雑。
- Serverless: YamlにAWSの設定を大量に記述するスタイル。抽象化度合いが低い。
Claudia.jsはこれらと比較した際に、API Gatewayや外部認証までをも含めたサーバレスアーキテクチャ全体を通して実装するのが簡単です。Node.jsでExpressを用いたAPIサーバを書いていくようなイメージで、設定ファイルを記述していくServerless等と比較して柔軟な処理が行えます。
準備
1. Claudia.jsをインストールします。
npm install -g claudia
2. プロジェクトを作成します。
mkdir [Proj Name] && cd [Proj Name] npm init npm install --save claudia-api-builder npm install --save aws-sdk npm install --save axios
実装
以下のようなフロントエンドアプリを実装してみます。エラー処理や詳細は割愛します。また、Hello World的なものはCloudia.jsのTutorialをみた方が手っ取り早いです。
- フロントエンドアプリがSNSの認証認可APIからOAuthのアクセストークンを取得する。(略)
- フロントエンドアプリがアクセストークンを付与してAWS API Gatewayにリクエストを投げる。(略)
- AWS API GatewayがSNSの認証認可APIを用いてアクセストークンを検証する。
- AWS API GatewayがFaaSの関数を呼び出す。
- AWS Lambdaの関数がAWS DynamoDBのテーブルからデータを取得してフロントに返す。
1. カスタム認証の作成
1. カスタム認証用のLambda関数を作成します。
authorizer.js
を作成します。Access Token検証APIを呼び出して有効な場合にAPI実行権限を付与しています。
var axios = require('axios'); //API実行ポリシーの生成 var generatePolicy = function(authToken, methodArn, context) { var awsInfo = methodArn.split(':'); var region = awsInfo[3]; var accountId = awsInfo[4]; var apiInfo = awsInfo[5].split('/'); var restApiId = apiInfo[0]; var stage = apiInfo[1]; var method = apiInfo[2]; //アクセスさせたいリソース var resource = 'arn:aws:execute-api:' + region + ':' + accountId + ':' + restApiId + '/' + stage +'/' + method + '/*'; return { 'principalId': authToken.split('-')[0], 'policyDocument': { 'Version': '2012-10-17', 'Statement': [{ 'Effect': 'Allow', 'Action': ['execute-api:Invoke'], 'Resource': [resource] }] } }; }; var url = "Access TokenのValidateを行うAPIのURL"; //Tokenの検証とポリシーの付与 exports.auth = function auth(event, context, cb) { axios.get(url, { params: { access_token: event.authorizationToken //HTTP headerのAuthorizationキーの値 } }).then(function (res) { var is_valid = true|false; //Tokenの有効性を検証して結果を格納 if (is_valid) { cb(null, generatePolicy(event.authorizationToken, event.methodArn)); } else { cb("Invalid Access Token"); } }); };
2. デプロイ
claudia
コマンドでカスタム認証用のLambda関数をAWSにデプロイします。
claudia create --name custom-authorizer --region us-east-1 --handler authorizer.auth --config claudia-auth.json
--name
: AWS Lambda上の関数名--region
: AWSのリージョン名--handler
: カスタム認証の関数名--config
: Claudia.js用の設定ファイル名(自動作成されるので任意)
{ "lambda": { "role": "custom-authorizer-executor", "name": "custom-authorizer", "region": "us-east-1" } }
2. APIとLambda関数の作成
1. APIとLambda関数を作成します。
app.js
という名前にします。
var ApiBuilder = require('claudia-api-builder'); var api = new ApiBuilder(); var AWS = require('aws-sdk'); var dynamodb = new AWS.DynamoDB.DocumentClient({region: 'us-east-1'}); api.registerAuthorizer('apiGatewayAuthorizer', { lambdaName: 'custom-authorizer', //AWS Labmda上のカスタム認証の名前 headerName: 'Authorization' //Tokenを格納するHTTP headerのKey名 }); api.get('/news', function (req) { return dynamodb.get({ TableName:'news', Key:{ "id": req.headers.id } }).promise().then(function(res) { return res.Item; }); },{ customAuthorizer: 'apiGatewayAuthorizer' }); module.exports = api;
2. デプロイ
claudia
コマンドでAWSにデプロイします。設定ファイルclaudia.json
が自動で作られます。
claudia create --region us-east-1 --api-module app
{ "lambda": { "role": "myproj-executor", "name": "myproj-proj", "region": "us-east-1" }, "api": { "id": "[PID]", "module": "app", "url": "[エンドポイントのベースURL]" } }
3. AWS上の設定
AWS DynamoDBのテーブル作成
news
テーブルを作成するaws dynamodb create-table --table-name news --attribute-definitions AttributeName=id,AttributeType=S --key-schema AttributeName=id,KeyType=HASH --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1
id
キーで検索できるようにレコードを追加。aws dynamodb put-item --table-name news --item '{"id":{"S":"id001"}, "content":{"S":"News content 001"}}' aws dynamodb put-item --table-name news --item '{"id":{"S":"id002"}, "content":{"S":"News content 002"}}' :
AWS Lambdaのrole設定
- IAM > Roles > [作成したRole名]
- Attach Pollicy >
AmazonDynamoDBFullAccess
- 強すぎるので実際は適当なPolicyを作成
4. API実行
PostmanなどでHTTPヘッダの
Authorization
キーにAccess Tokenを、id
キーに存在するidを付与して投げます。Claudia.jsでAPIを作成した際にはCORSはデフォルトでONになっていますが制限することもできます。
5. アップデート
- スクリプトを修正します。
claudia
コマンドを実行します。
claudia update --config claudia-auth.json claudia update --config claudia.json
まとめ
Claudia.jsを利用すれば、外部の認証認可APIを用いたフロントエンドアプリのためのサーバレスアーキテクチャを簡単に実装できます。
以上