Laravel 5で作成したAPIをAWS Elastic Beanstalkにデプロイし、AWS API GatewayのHTTPプロキシのバックエンドとする構成について確認したメモになります。
Swagger-PHPを利用して生成したSwaggerドキュメントをAPI Gatewayにインポートする場合、API Gateway固有の設定をSwaggerドキュメントに追加する必要があります。
ここでは、前の記事「Swagger-PHPについてLaravel 5.2で確認したメモ」で実装したAPIに、API GatewayのSwagger拡張を追加してSwaggerドキュメントを生成しなおしAPI Gatewayにインポートする流れで解説していきます。
システム構成
この記事の目的は、バックエンドのAPIをLaravelで実装した場合に、API Gatewayに統合するにはどんな感じか概要をつかむことです。
LaravelやRailsのような、フレームワークを利用してAPIのデプロイ先としては、AWSでは、マネジメントサービスを利用する場合、ElasticBeanstalkかContainer Serviceが選択肢となるかと思いますが、ここではより構成手順が少ないElastic Beanstalkを選択します。
それを踏まえ、簡単に図にすると以下のようになります。
ここでは、ネットワーク、IAMおよびセキュリティグループについては省略していますが、実運用ではこの辺りをきちんと設計する必要があります。
Laravelプロジェクトのデプロイ環境をAWSに構築
LaravelプロジェクトをElastic Beanstalkにデプロイし、データベースはRDSを参照するように環境を構築していきます。
Elastic Beanstalkのアプリケーションおよび環境を作成
Laravel 5で作成したAPIを、Elastic Beanstalkにデプロイする準備をします。
Laravel 5をBeanstalkにデプロイする方法についてはAWS公式ドキュメントの「Elastic Beanstalk への Laravel アプリケーションのデプロイ」にあります。
本ブログでも、「Laravel 5プロジェクトをElastic Beanstalkにデプロイ」にまとめていますので参照ください。
Beanstalkに、デプロイ先のアプリケーションと環境を作成しておきます。
Laravelプロジェクトのルートディレクトリで以下のコマンドを実行し、Gitリポジトリを初期化します。
$ git init
$ git add .
$ git commit -m "First commit"
次に、Beanstalkの設定をします。
$ eb init
$ eb create
環境作成時に、プロンプトEnter DNS CNAME prefix
で指定した値に.
を足した値が、Swaggerのアノテーションで指定するAPIのエンドポイントになります。
例えば、DNS CNAME prefixにlaravel-eb-dev
を指定して、us-east-1に作成した環境の場合はlaravel-eb-dev.us-east-1.elasticbeanstalk.com
になります。
RDSにデータベースを追加
MySQLのデータベースを作成します。
この手順は省略します。
Elastic Beanstalkの環境変数を定義
Elastic Beanstalkの環境変数のセットは、画面または設定ファイルが利用可能です。
ここでは、設定ファイルを利用します。
今回のLaravel 5プロジェクトを動作させるにあたって、最小限必要となる環境変数をセットする設定ファイル.ebextensions/environmentvariables.configを以下のように作成します。
// .ebextensions/environmentvariables.config
option_settings:
- option_name: APP_KEY
value: base64:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=
- option_name: DB_HOST
value: laraveldb.xxxxxxxxxxxx.us-east-1.rds.amazonaws.com
- option_name: DB_DATABASE
value: laraveldb
- option_name: DB_USERNAME
value: laraveldbusername
- option_name: DB_PASSWORD
value: laraveldbpassword
データベースマイグレーションの定義
次に、デプロイ時にマイグレーションが実行されるように.ebextensions/laravelmigrate.configを以下のように作成します。
// .ebextensions/laravelmigrate.config
container_commands:
01-migration:
command: "php artisan migrate --force"
leader_only: true
02-seed:
command: "php artisan db:seed --force"
leader_only: true
Elastic Beanstalkのソフトウェア設定 ドキュメントルート
Laravel 5は、ドキュメントルートを /public
に設定する必要があります。
これも、設定ファイルが利用できます。
// php.ini.config
option_settings:
- namespace: aws:elasticbeanstalk:container:php:phpini
option_name: document_root
value: /public
環境設定は以上です。
環境設定をデプロイ
コミットを作成して、デプロイします。
$ git add .
$ git commit -m "Add beanstalk environments."
$ eb deploy
API定義にAWS API Gateway用のアノテーションを追加
API GatewayにSwaggerドキュメントをそのままインポートしても、バックエンドとの連携について別途設定が必要になっています。
バックエンド APIとの連携については、API Gatewayの「Swagger に対する API Gateway 拡張」をアノテーションに追加します。
Swagger-PHPで、拡張オブジェクトを記述するには、以下のようにx=
を利用して指定します。
// app/Http/Controller/Api/ProductController
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Product;
class ProductController extends Controller
{
/**
* @SWG\Get(
* path="/products",
* summary="list products",
* x={"amazon-apigateway-integration"={
* "type": "HTTP",
* "httpMethod": "GET",
* "uri": "http://eb-laravel-dev.jnbm8maymt.us-east-1.elasticbeanstalk.com/api/products",
* "responses": {
* "200": {
* "statusCode": "200"
* },
* "500": {
* "statusCode": "500"
* }
* }
* }},
* @SWG\Response(
* response=200,
* description="A list with products",
* @SWG\Schema(
* type="array",
* @SWG\Items(ref="#/definitions/Product")
* )
* ),
* @SWG\Response(
* response=500,
* description="an ""unexpected"" error"
* )
* )
*/
public function index()
{
return response()->json([
'result' => [
'statistics' => [
'products' => Product::all()
],
],
'message' => '',
'type' => 'success',
'status' => 0
]);
}
}
Swaggerドキュメントを生成し直します。
$ mkdir public/api
$ ./vendor/bin/swagger ./app --output public/api/
API Gatewayにインポート
生成したSwaggerドキュメントは、awslabs/aws-apigateway-importerを利用してAPI Gatewayにインポートします。
基本的な使い方については、GETTING STARTED WITH THE AMAZON SWAGGER IMPORTERを参照ください。
前提条件
AWS CLIが利用可能。もしくは、~/.awsディレクトリに、regionとcredentialsの設定があれば、aws-apigateway-importerはそれを読み込む。
(RegionとCredentialsについては、コマンド実行オプションでも指定可能)
aws-apigateway-importerのインストール
aws-apigateway-importerはJavaのツールなのでクローン後Mavenでビルドします。
Mavenはhomebrewなどでインストールしておきます。
Gitクローンして、mvnコマンドでビルドします。
$ git clone https://github.com/awslabs/aws-apigateway-swagger-importer.git
$ cd aws-apigateway-swagger-importer
$ mvn assembly:assembly
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building aws-apigateway-importer 1.0.3-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:15 min
[INFO] Finished at: 2016-08-02T14:00:03+09:00
[INFO] Final Memory: 66M/687M
[INFO] ------------------------------------------------------------------------
aws-api-import.shを--help
オプションを指定して実行して以下の様に表示されれば、利用可能な状態です。
$ ./aws-api-import.sh --help
Usage: aws-api-import [options] Path to API definition file to import
Options:
--create, -c
Create a new API
Default: false
--deploy, -d
Stage used to deploy the API (optional)
--help
Default: false
--profile, -p
AWS CLI profile to use (optional)
Default: default
--raml-config
RAML file for API Gateway metadata (optional)
--region, -r
AWS region to use (optional)
--test, -t
Delete the API after import (create only)
Default: false
--update, -u
API ID to import swagger into an existing API
インポートを実行
以下のコマンドを実行して、生成したSwaggerドキュメントをインポートします。
$ ./aws-api-import.sh -c /path/to/project/public/api/swagger.json
2016-08-02 18:39:21,813 INFO - Using API Gateway endpoint https://apigateway.us-east-1.amazonaws.com
2016-08-02 18:39:25,730 INFO - Attempting to create API from Swagger definition. Swagger file: /Users/hrendoh/workspace/eb-laravel/public/api/swagger.json
reading from /Users/hrendoh/workspace/eb-laravel/public/api/swagger.json
2016-08-02 18:39:25,877 INFO - Parsed Swagger with 1 paths
2016-08-02 18:39:25,877 INFO - Creating API with name My first swagger documented API
2016-08-02 18:39:26,571 INFO - Created API 65x20f4pe7
2016-08-02 18:39:27,140 INFO - Removing default model Empty
2016-08-02 18:39:27,352 INFO - Removing default model Error
2016-08-02 18:39:27,579 INFO - Creating model for api id 65x20f4pe7 with name Product
2016-08-02 18:39:27,743 INFO - Generated json-schema for model Product: {"properties":{"name":{"type":"string","description":"The product name"}},"definitions":{}}
2016-08-02 18:39:28,204 INFO - Creating resource 'api' on j1pm3lwh23
2016-08-02 18:39:28,644 INFO - Creating resource 'products' on x6mc1r
2016-08-02 18:39:29,486 INFO - Creating method response for api 65x20f4pe7 and method GET and status 200
2016-08-02 18:39:29,686 INFO - Creating new model referenced from response: Alistwithproducts
2016-08-02 18:39:29,686 INFO - Creating model for api id 65x20f4pe7 with name Alistwithproducts
2016-08-02 18:39:29,699 INFO - Generated json-schema for model Alistwithproducts: {"type":"array","items":{"$ref":"#/definitions/Product"},"definitions":{"Product":{"properties":{"name":{"type":"string","description":"The product name"}}}}}
2016-08-02 18:39:30,330 INFO - Creating method response for api 65x20f4pe7 and method GET and status 500
2016-08-02 18:39:30,938 INFO - Creating integration with type HTTP
2016-08-02 18:39:32,167 INFO - Creating method for api id 65x20f4pe7 and resource id vhapyw with method get
マネジメント コンソールで確認すると以下のようにリソースが追加されています。
ステージングにデプロイ
APIをステージングにデプロイするには--deploy
オプションを指定します。
importerでデプロイのみはできないので、--update
と併せて利用します。
$ ./aws-api-import.sh --update 65x20f4pe7 --deploy v1 path/to/swagger.json
APIのURLに含まれるバージョンが、/v1/api/と言うのは微妙ですが、ひとまず以下のようにデプロイされました。
まとめ
以上で、なんとなくLaravelやRailsのようなフレームワークを利用して実装したAPIとAPI Gatewayの連携方法が確認できたと思います。
この後の検討事項としては以下のようなものが考えられます。
- 認証: API Gateway側のカスタム認証の実装でOAuth2を実装する?
- バックエンドAPIのセキュリティ: API Gatewayに認証を任せるとするとバックエンドAPIとのセキュリティをどうするか?
- スロットリング: API利用ユーザーごとにスロットリングを実装するには?
- バージョニング: APIのバージョン管理は、API Gatewayのステージを使うのが良い?
なかなか長い道のりそうですね。
参考
これから始めるエンタープライズ Web API 開発第3回 aws-apigateway-importerを使ったAmazon API Gatewayの設定
Amazon API Gateway Importer を使って Rails x Grape から API を生成する
補足
basePath問題
マネジメントコンソールからもSwaggerファイルをインポートできますが、basePathがなくなります。
Gateway API importer: Swagger basePath is ignored during import