Apollo ServerをAWS Lambdaで動かす

## やりたいこと

- Apolloで作ったGraphQLサーバをAWS Lambdaで動かしサーバーレスで使いたい

## 手順

- [Apollo公式サイトの手順](https://www.apollographql.com/docs/apollo-server/deployment/lambda.html)通りにやっただけではあるが日本語化も兼ねて記事にする

### AWS周りのセットアップ

#### AWS CLIのインスール

- AWS CLIをインスールする
- 以下のページの手順に沿って実施する
    - https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/installing.html
- 自分の場合はMacなのでこのようなコマンドでインスールした

```bash
curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "awscli-bundle.zip"
unzip awscli-bundle.zip
sudo ./awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws
aws --version
# aws-cli/1.16.67 Python/2.7.10 Darwin/18.0.0 botocore/1.12.57
```

#### AWSのユーザ設定

- コマンドラインからAWSにアクセスするためのユーザ設定をする
- 以下のページの手順に沿って実施する
    - https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-getting-started.html
- 手順
    1. [IAMコンソール](https://console.aws.amazon.com/iam/home#/home)へアクセス
    2. 「ユーザ」 -> 「ユーザ追加」
    3. ユーザー詳細の設定
        - 「ユーザ名」： 適当な名前
        - 「アクセスの種類」： 「プログラムによるアクセス」にチェック
        - 「次のステップ：アクセス権限」を押す
    4. アクセス許可の設定（※とりあえず動かしただけでこの内容は過剰すぎるので注意）
        - 検索に「AWSLambdaFullAccess」を入力し出てきたものにチェック
        - 「ポリシーを作成」を押し以下の3つのアクセス許可を持ったポリシーを作成する
            - CloudFormationの設定追加
                - サービス：CloudFormation
                - アクション：すべての CloudFormation アクション (cloudformation:*)
                - リソース：すべてのリソース
            - API Gatewayの設定追加
                - サービス：API Gateway
                - アクション：すべての API Gateway アクション (apigateway:*)
                - リソース：すべてのリソース
            - IAMの設定追加
                - サービス：IAM
                - アクション：すべての IAM アクション (iam:*)
                - リソース：すべてのリソース
            - 「Review policy」ボタンを押して次のページへ
            - 名前に適当な値を入れて「Create policy」を押してポリシー作成完了
        - 「ポリシーのフィルタ」で「ユーザーによる管理」を選択すると作成したポリシーが出てくるのでチェックを入れる
            - 出てこない場合画面右にある更新ボタンを押すと出てくる
        - 「次のステップ：タグ」を押す
    5. タグの追加 (オプション)
        - タグの設定は必須ではないので何もせずに「次のステップ：確認」を押す
    6. 確認
        - 「ユーザの作成」を押すとユーザが作成される
    7. アクセスキーの保存
        - 作成が完了するとアクセスキーが表示されるので以下の2つをメモしておく
            - アクセスキー ID
            - シークレットアクセスキー
    8. アクセスキーの登録
        - ターミナルで以下のコマンドを実行しメモしたアクセスキーを登録する

```bash
aws configure
# AWS Access Key ID [None]: アクセスキー IDを入力
# AWS Secret Access Key [None]: シークレットアクセスキー
# Default region name [None]: ap-northeast-1
# Default output format [None]: json
```

### アプリの作成

- Lambdaで動作させるアプリケーションを作成する

#### 事前準備

- Serverless Frameworkをグローバルにインストールしておく

```bash
npm i -g serverless
serverless -v
# 1.34.1
```

#### セットアップ

- 以下のコマンドを実行
    - npm の人は適宜yarnをnpmに読み替えてください

```bash
mkdir apollo-lambda-sample && cd apollo-lambda-sample
yarn init -y
yarn add apollo-server-lambda graphql
```

#### ファイルの作成

- graphql.jsを作成する

```js:graphql.js
const { ApolloServer, gql } = require('apollo-server-lambda');

const typeDefs = gql`
  type Query {
    hello: String
  }
`;

const resolvers = {
  Query: {
    hello: () => 'Hello world!',
  },
};

const server = new ApolloServer({ typeDefs, resolvers });

exports.graphqlHandler = server.createHandler({
  cors: {
    origin: '*',
    credentials: true,
  },
});
```

- serverless.ymlを作成する

```yaml:serverless.yml
service: apollo-lambda
provider:
  name: aws
  runtime: nodejs8.10
  region: ap-northeast-1
functions:
  graphql:
    # this is formatted as <FILENAME>.<HANDLER>
    handler: graphql.graphqlHandler
    events:
      - http:
          path: graphql
          method: post
          cors: true
```

- ファイル内のコメントにもあるように`handler: graphql.graphqlHandler`の部分が`handler: jsのファイル名.export名`のように紐付いている

### デプロイ

- 以下のコマンド一つでデプロイできる！すごい！

```bash
serverless deploy
```

- 完了するとエンドポイント等の情報が出てくる
    - これらの情報は[Lambdaのコンソール](https://ap-northeast-1.console.aws.amazon.com/lambda/home)からも確認できる

```
Service Information
service: apollo-lambda
stage: dev
region: ap-northeast-1
stack: apollo-lambda-dev
api keys:
  None
endpoints:
  POST - https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/graphql
functions:
  graphql: apollo-lambda-dev-graphql
layers:
  None
```

- 自分が試した時はawsアカウントの権限が足りずにエラーがたくさん出たが、上記の手順通りであれば問題なく実行できるはず
- ちなみにリソースを削除する時は以下のコマンド

```bash
serverless remove
```

### 動作確認

- アクセスして動作確認する
- ここでは[GraphiQL](https://electronjs.org/apps/graphiql)を使う
    - [ここ](https://github.com/skevy/graphiql-app/releases/download/v0.7.2/GraphiQL-0.7.2.dmg)からインストールできる
- GraphQL EndpointにエンドポイントのURLを設定
- 左のフィールドに以下の内容を入力し実行ボタンを押すとHelloWorld！のレスポンスを取得できる

```
query {
  hello
}
```

<img width="501" alt="graphiql.png" src="https://qiita-image-store.s3.amazonaws.com/0/175213/e3a271df-398b-f0e2-35d3-15a96b51e393.png">