SAM CLI で AWS SAM と Swagger を用いた API 開発環境を構築する
追記 (2018-10-02)
!FindInMap
を AWS::Include
とともに用いると aws cloudformation deploy
で失敗することが分かったため、 SwaggerPath
をパラメータとして受け取る形に修正しました。
AWS SAM と Swagger を用いてサーバーレスで API を実装する際の開発環境を SAM CLI で構築しました。
AWS SAM と SAM CLI について
AWS SAM(AWS サーバーレスアプリケーションモデル)は API Gateway、Lambda、DynamoDB を管理することが出来る CloudFormation の拡張です。
また SAM CLI (aws-sam-cli) は AWS SAM のテンプレートをもとに、ローカルでの開発やデプロイする環境を提供してくれるツールです。
AWS SAM と Swagger
AWS SAM では API の定義に Swagger 形式を用いることが可能です。
上記の記事にある通り Swagger を用いる方法として、以下の3種類の方法があります。
今回は、AWS SAM のテンプレートファイルから AWS:Include
で swagger.yml を読み込む方法のアプリケーションの開発環境を SAM CLI で構築します。
ローカル開発環境の構築
まずは SAM CLI をインストールします。
SAM CLI は Python 製のため pip
を使います。
$ pip install aws-sam-cli
続いて、サンプルリポジトリを git clone
します。
$ git clone https://github.com/yami-beta/aws-sam-swagger-sample.git
template.yml
が AWS SAM のテンプレートで swagger.yml
が Swagger Spec になります。
API を起動する場合は以下のコマンドを実行します。
$ sam local start-api
開発環境構築のポイント
開発環境を構築する上でのポイントが以下の部分です。
DefinitionBody
での swagger.yml の指定に SwaggerPath
というパラメータを用いています。
開発環境( Stage
パラメータが dev
)の場合はローカルのパスを、ステージング環境( Stage
パラメータが stg
)の場合は S3 バケットとなるように SwaggerPath
を指定します。
Parameters: SwaggerPath: Type: String Default: swagger.yml Resources: HelloApi: Type: AWS::Serverless::Api Properties: StageName: !Ref Stage DefinitionBody: Fn::Transform: Name: AWS::Include Parameters: Location: !Ref SwaggerPath
以下の Mappings
の例はデプロイできない古い情報です。
DefinitionBody
で swagger.yml を指定しているのですが、開発環境( Stage
パラメータが dev
)の場合はローカルのパスを、ステージング環境( Stage
パラメータが stg
)の場合は S3 バケットとなるように、Mappings を用いています。
Mappings: StageConf: dev: ArtifactBucket: swagger.yml stg: ArtifactBucket: !Sub s3://${ArtifactBucket}/swagger.yml Resources: HelloApi: Type: AWS::serverless::Api Properties: StageName: !Ref Stage DefinitionBody: Fn::Transform: Name: AWS::Include Parameters: Location: !FindInMap [StageConf, !Ref Stage, "ArtifactBucket"]
AWS:Include
はローカルのファイルを指定することが現時点では出来ません。
しかし SAM CLI ではローカルのパスを指定すると読み込んでくれます。
これを利用して、開発環境ではローカルの swagger.yml を用いて sam local start-api
を実行し、デプロイ時には S3 バケット名とすることで、開発環境と実際に AWS にデプロイする場合で共通のテンプレートを利用できます。
def _download_swagger(self, location): """ Download the file from given local or remote location and return it Parameters ---------- location : str or dict Local path or S3 path to Swagger file to download. Consult the ``__init__.py`` documentation for specifics on structure of this property. Returns ------- dict or None Downloaded and parsed Swagger document. None, if unable to download """ if not location: return bucket, key, version = self._parse_s3_location(location) if bucket and key: LOG.debug("Downloading Swagger document from Bucket=%s, Key=%s, Version=%s", bucket, key, version) swagger_str = self._download_from_s3(bucket, key, version) return yaml_parse(swagger_str) if not isinstance(location, string_types): # This is not a string and not a S3 Location dictionary. Probably something invalid LOG.debug("Unable to download Swagger file. Invalid location: %s", location) return # ``location`` is a string and not a S3 path. It is probably a local path. Let's resolve relative path if any filepath = location if self.working_dir: # Resolve relative paths, if any, with respect to working directory filepath = os.path.join(self.working_dir, location) if not os.path.exists(filepath): LOG.debug("Unable to download Swagger file. File not found at location %s", filepath) return LOG.debug("Reading Swagger document from local file at %s", filepath) with open(filepath, "r") as fp: return yaml_parse(fp.read())
aws-sam-cli/reader.py at 6164d6d2e7351a849ad3d79973ac18b8d3d1d371 · awslabs/aws-sam-cli · GitHub
まとめ
SAM CLI を用いて AWS SAM と Swagger で構成された API の開発環境を構築しました。
現在は AWS:Include
がローカルパスを指定できないため、Mappings パラメータ でローカルパスと S3 バケットを切り替えることで、テンプレートを共通化することができます。
AWS:Include
がローカルパスを指定できるようになると、更にシンプルなテンプレートに出来るため、今後に期待したいところです。