Copilotを使ってGraphQL APIをFargateにお手軽デプロイするハンズオン

![スライド7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234396/e33eb139-3f58-78a0-dea9-a1516e729bb9.png)

# 導入
AWS Copilotは2020年7月に正式にリリースしたばかりのデプロイツールです。
Live Codingをやってみたのですが、コーディングと説明を含めて30分程度でGraphQLサーバをデプロイすることができました。
今回はその資料を使ってチュートリアルを書いていこうと思います。

# 今回構築するもの
![スライド8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234396/6ead6dcb-0498-c02e-6813-b764dff03f3e.png)

GraphQLサーバをApolloで作成します。言語はNode.js(TypeScript)を使用します。
作成したサーバをDocker上で起動させ、Copilotを使ってECS(Fargate)にデプロイします。

# 構成
![スライド9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234396/04621e35-b406-a676-4cbf-8ac3a5b37564.png)

構成は３部構成で、「環境準備」「GraphQLの実装」「Copilotを使ったFargateへのデプロイ」をやります。
AWS CLI, Git, Docker, Nodeはインストール済みのものとして行います。
また、データベース連携は行わず、仮想的にリストをDBだと見立てて実装を行います。

# 環境準備
![スライド10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234396/da2134c3-39d5-f1c2-552a-c96008042702.png)

## プロジェクトの作成
ディレクトリの作成を行います。

```
mkdir test
cd test
```

必要なライブラリをインストールします。
必要なのは、graphql-serverとgraphql、そしてtypescriptだけです。

```
npm install apollo-server graphql typescript
```

ソースコードを記述するindex.tsファイルを作成します。

```
touch index.ts
```

ts-nodeで実行するスクリプトをpackage.jsonに追加します。
npxを先頭につけることでts-nodeをローカルにインストールしなくても使えます。
これで`npm run start`を実行することでindex.tsを実行できるようになりました。

```:package.json
  "scripts": {
    "start": "npx ts-node index.ts"
  },
```

## Dockerfileの作成
Dockerfileに、ライブラリのインストールとindex.tsを実行するスクリプトを記述して環境を定義します。
ポートは4000を使用します。

```docker
FROM node:latest

WORKDIR /usr/app/

COPY package.json package-lock.json ./
RUN npm install

COPY index.ts .

EXPOSE 4000
CMD ["npm", "run", "start"]
```

# GraphQLの実装
![スライド11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234396/e4992ffc-84a0-fed7-c585-cfb08c0e10c6.png)

index.tsにGraphQLを実装していきます。
コードの詳しい説明は今回は割愛しますが、Messageオブジェクトを定義し「メッセージの追加(Mutation)」「メッセージの購読(Subscription)」を実装しています。typeDefsでGraphQLのスキーマを定義し、resolversに実装を記述しています。


```typescript:index.ts

import { ApolloServer, gql, PubSub } from "apollo-server"

const pubsub = new PubSub()
const typeDefs = gql`
    type Message {
        text: String
    }

    type Query {
        message: [Message]
    }

    type Mutation {
        addMessage(text: String): Message
    }

    type Subscription {
        message: [Message]
    }
`

const messages = []
const resolvers = {
    Mutation: {
        addMessage(_: any, args: { text: String }) {
            messages.push(args)
            pubsub.publish("MESSAGE_ADDED", { message: messages })
            return args
        }
    },
    Subscription: {
        message: {
            subscribe: () => pubsub.asyncIterator("MESSAGE_ADDED")
        }
    }
}

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

server.listen().then(({ url }) => {
    console.log(`server is running on ${url} ...`)
})
```


# Copilotでデプロイする
![スライド12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234396/960bd3d9-3f52-62be-2d82-10018665fdd1.png)

## copilotのインストール

```
brew install aws/tap/copilot-cli
```

## copilot init
以下コマンドを実行すると、対話式にアプリケーション名やDockerfileの場所、ポートなどを聞かれます。

```sh
copilot init
```

対話が面倒な人は以下コマンドで一発でできます

```sh
copilot init --app test                     \
  --name test                               \
  --type 'Load Balanced Web Service'         \
  --dockerfile './Dockerfile'                \
  --port 4000                                 \
  --deploy
```

デプロイ完了するまでかなり待ちました。
完了すると、URLがコンソールに表示されるので、そこにアクセスして動作確認をしてみましょう。

## 動作確認
### Subscriptionの動作確認
URLにアクセスすると下の画像のようなAPIテスト環境(Playground)が表示されると思います。

![スクリーンショット 2020-12-12 13.19.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234396/97678472-1ac7-de2b-b3a6-f19c0da7c56a.png)

右にあるDOCSをクリックすると自動生成されたAPI仕様書を見ることができます(最高)し、エディタは補完がきく(最高)ので、下記のクエリを記述してSubscriptionをテストしてみましょう。実行するとListening...の状態になると思います。

```
subscription {
  message {
    text
  }
}
```

### Mutationの動作確認
リアルタイム通信されることがわかるように別WindowでURLを開いて、以下クエリを実行してみましょう。

```
mutation {
  addMessage(text:"Hello world!!") {
    text
  }
}
```

クエリの実行と同時に、Subscriptionしていた側にメッセージが届くことを確認できると思います。

## お掃除
この状態のままだと課金されてしまうので、リソースを削除します。

```sh
copilot app delete
```


# まとめ
待ち時間が多少あったものの、全部で30分以内にデプロイができたのは素晴らしいなと思いました。
また紹介し切れませんでしたが、CopilotにはCI/CDの作成までやってくれる機能があって、こちらもめちゃくちゃ手軽で最高でした。