【AWS SAM】Amazon API Gateway HTTP API と Swagger (OAS3) で最新API開発

## 記事の目的
Amazon API Gateway と Swagger の組み合わせでAPI開発する情報はいくつかありますが、どれもAPI GatewayがREST APIだったりSwaggerがOAS2だったりと、最新とは言えないため、HTTP API + OAS3のパターンでご紹介していきたいと思います。

## はじめに
### REST API と HTTP API の違い
AWSマネジメントコンソールから見ると、API Gatewayで新しいAPIを作成する際は、HTTP APIとREST APIを選択可能です。簡単に言うと、HTTP API のほうがお手軽ですが、詳細な設定が省かれています。また、HTTP APIを選択するとRESTFullAPIを作れないと思ってしまいがちですが、**HTTP APIを選択してもRESFullAPIを作成可能です。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491627/44e3afa4-6610-cc0f-731c-77e8d9ef38d5.png)

Cloud Formationのデプロイ時のログからも、HTTP APIが新しいもの(v2)だということがわかるかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491627/5445457d-6c2f-dc7a-8728-4508ed02ea7a.png)

### Swaggerとは
REST APIに関わる様々なツール、フレームワークを含むオープンソースコミュニティです。
今回はその中でも、Open API Specification 3.0に基づいて記載することでドキュメントを自動生成することのできる「Swagger Editor」を使います。 
ただし今回はドキュメントの自動生成が目的というよりも構文チェックをするという目的のほうが強いです。
https://editor.swagger.io/

参考)https://news.mynavi.jp/itsearch/article/devsoft/3854

## 作るもの
JWTオーソライザーの付いたLambda統合のAPIを1本作ります。
SAMを使っていきますが、中でもAPIの生成に関わるtemplate.yamlとswagger.yamlについて紹介していきます。

### template.yaml
ポイントは以下の通りです。

- HTTP API の生成には「AWS::Serverless::HttpApi」を使用する。
- DefinitionUriにtemplate.yamlと同じ階層に配置したswaggerファイル(後述)を参照する
- StageVariablesにswaggerファイルに渡す必要のある関数名を定義しておく
- AWS::Serverless::FunctionのEventsはHTTP APIのApiIdを参照するだけでよい

非常にスッキリまとまりますね。細かい設定は全てOpenAPIのファイルの方に書き込んでいくためです。

```template.yaml
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31

Globals:
  Function:
    Runtime: python3.8
    Handler: handler.lambda_handler

Resources:
  sampleAPI:
    Type: AWS::Serverless::HttpApi
    Properties:
      DefinitionUri: swagger.yaml
      StageVariables:
        Sample: !Ref sampleFunction

  sampleFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: lambda_source/sample
      Events:
        sampleAPI:
          Type: HttpApi
          Properties:
            ApiId: !Ref sampleAPI
```

余談)Eventsも全てのLambda関数で共通になるのでGlobalにまとめたかったのですができませんでした...。

### swagger.yaml
ポイントは以下の通りです。

- openapiは"3.0.1"を指定する。(API Gateway側とバージョンをあわせるため。)
- オーソライザーの設定は[x-amazon-apigateway-authorizer](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-swagger-extensions-authorizer.html)を使う
    - リンク先に詳細が記載されているので一読すると良いと思う。
    - この記載でCognitoIdpで発行するIdTokenを検証可能。
- Lambda統合の設定はx-amazon-apigateway-integrationを使う
    - 特にURIの設定がポイント。リージョンやアカウントIDなどは使用できる変数を使ってURIを組み立てる。関数名は、temlate.yamlであらかじめ作ったStageVariableを使う。
   - URIの設定に使える変数は https://docs.aws.amazon.com/apigateway/latest/developerguide/import-api-aws-variables.html に記載がある。
   - httpMethodはPOST固定。
- データ構造はschemasにまとめて定義する。パラメータとして使うときは必要ないけれども、返ってくるときは必要な、例えばidやtimestampのような項目はreadOnlyを指定することで、ドキュメント上もうまく解釈される。


```swagger.yaml
openapi: "3.0.1"

info:
  title: "Sample API"
  description: "サンプルのAPI"
  version: "1.0.0"

tags:
  - name: "Sample"
    description: "サンプルのグループ"

paths:
  /sample/{id}:
    get:
      tags:
        - "Sample"
      summary: "getSample"
      description: "サンプルを取得します。"
      operationId: "getSample"
      parameters:
        - name: "id"
          in: "path"
          description: "ユニークなIDを指定します。"
          required: true
          schema:
            type: "string"
      security:
        - CognitoAuth: []
      responses:
        "200":
          description: "成功"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SampleSchema"
        "404":
          description: "指定されたIDのSampleが見つかりません。"
      x-amazon-apigateway-integration:
        payloadFormatVersion: "2.0"
        type: "aws_proxy"
        httpMethod: "POST"
        uri: "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${stageVariables.SampleFunction}/invocations"

components:
  securitySchemes:
    CognitoAuth:
      type: "openIdConnect"
      openIdConnectUrl: "https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_ABCDEFGHI/.well-known/openid-configuration"
      x-amazon-apigateway-authorizer:
        type: "jwt"
        jwtConfiguration:
          audience:
            - "sample"
        identitySource: "$request.header.Authorization"

  schemas:
    SampleSchema:
      type: "object"
      required:
        - id
      properties:
        id:
          type: "string"
          description: "ユニークなIDです。"
          example: "abcd-1234"
          readOnly: true
        text:
          type: "string"
          description: "文字列が入ります。"
          example: "文字列"

x-amazon-apigateway-importexport-version: "1.0"

```

## 最後に
いかがでしたでしょうか。
HTTP API は REST API よりシンプルですし、Open API 3.0 も 2.0 よりシンプルになりました。
現状オーソライザーはAPIに一つしかアタッチできないため、今後複数のオーソライザーをアタッチすることができるようになるなどするともっと使いやすくなるなと感じています。

自動生成されるドキュメントが見てみたい場合は、swagger editorに上記yamlの中身をコピペしてみてください。

それではよいAPIライフを。