日々ろぐ

人に優しく٩( 'ω' )و

AWS Amplify で GraphQL を使って API を作ってみる

タイトルの通り。

先日、AWS Amplify でホスティングを試してみた流れで、APIも作ってみようと思い立ったわけです。

massyuu.hatenablog.com

Amplify ではコマンド一つでAPI(REST or GraphQL)を作ることができます。
GraphQL をちゃんと触った記憶がなかったので、せっかくなので試してみました。

GraphQL?

GraphQL って何?という話はいろんなところに書かれているので、ここでは割愛します。
雑に言ってしまえば、都合のいい形でデータ構造を決めてフロントエンドとバックエンドでデータのやりとりができるクエリ、という感じで認識してます。

Amplify で GraphQL を扱う場合、AppSync を利用することになります。

aws.amazon.com

AppSync は GraphQL のバックエンドを構築するフルマネージドサービスなんですが、
・様々なデータソースへの接続
・オフライン対応
・リアルタイムアプリケーションの作成
・PubSub
などなど、かなり強力なサポートをしてくれます。

と書いていますが、難しいこと考えずに AWS でGraphQL使うんなら AppSync 使いましょうくらいの認識でいいかなと思ってます。

API の作成

ホスティングの時と同様に、amplify configureで実行ユーザーのプロファイル設定、amplify initでプロジェクトの初期設定を行います。
このあたりの記載については、先日のホスティングの記事と同様になります。

プロジェクトの初期設定が終わり、Amplify のコンソールでプロジェクトが確認できるようになったら、準備完了です。
以下のコマンドで API を追加します。

$ amplify add api

API の設定を選んでいきます。 今回は GraphQL で作るので、それに準じて選んでいます。

f:id:massyuu-d:20200917155232p:plain

途中にある

What best describes your project

の選択肢で、データベースのリレーションについて選択することになります。

f:id:massyuu-d:20200917155306p:plain

ここでは1対多を選んでいますが、この選択によって初期に作成されるスキーマの type 構成が変わってきます。
一般的に、独立したテーブルのみで作られるアプリケーションはあまりないと思うので、ここは基本的に1対多を選ぶ方がよいのかなと思ったりしました。
(もちろん、後からスキーマを変えてしまえばどちらでもいい話ではありますが。)

設定が終わると、スキーマBlogPostCommentが作成されます。

その後、

$ amplify push

を実行すると、AWS に GraphQL の API が作成されます。

スキーマの記述について

スキーマを書く上で、備忘録として残しておきたい書き方や注意などを以下にまとめます。

@model

スキーマにてテーブルの type を記載するとき、@modelディレクティブを付与することで、プッシュ時にDynamoDBのテーブルを作成してくれます。

type Blog @model {
  id: ID!
  name: String!
  posts: [Post] @connection(keyName: "byBlog", fields: ["id"])
}

と同時に、基本的な CRUD についてのquerymutationを自動生成し、input typeの定義まで行ってくれます。
正直、後から追加するテーブルの type を記述する場合、書かない手はないかなと思います。

リレーションの記述

今回作成した API では、BlogPostCommentのテーブルへのアクセスがあります。
Commentは特定のPostに対するコメントで、PostCommentは1:N
Postは特定のBlogに対する投稿で、BlogPostは1:N
という構造になっています。

この場合、各々の type を@connectionディレクティブを使って紐づけていきます。

type Blog @model {
  id: ID!
  name: String!
  posts: [Post] @connection(keyName: "byBlog", fields: ["id"])
}

type Post @model @key(name: "byBlog", fields: ["blogID"]) {
  id: ID!
  title: String!
  blogID: ID!
  blog: Blog @connection(fields: ["blogID"])
  comments: [Comment] @connection(keyName: "byPost", fields: ["id"])
}

type Comment @model @key(name: "byPost", fields: ["postID", "content"]) {
  id: ID!
  postID: ID!
  post: Post @connection(fields: ["postID"])
  content: String!
}

createdAtとupdatedAt

Amplify の仕様上、作成したテーブルにcreatedAtupdatedAtという項目が自動で作成されます。
スキーマに記述がなくとも、自動的に定義されます。

ここで少し厄介なのが、何も考えずにこれらの項目を作られると Not Null 制約がついてしまいます。
絶対的に必要な項目でもないのに Not Null が付くのは些か面倒なので、以下の方法で回避します。

■ Null を許容する

スキーマに明示的にcreatedAtupdatedAtを記載することで、Null 許容の項目にすることができます。

type Blog @model {
  id: ID!
  name: String!
  posts: [Post] @connection(keyName: "byBlog", fields: ["id"])
  createdAt: AWSDateTime
  updatedAt: AWSDateTime
}

■ createdAt と updatedAt を作らない

@modelディレクティブの記述を以下のようにしてやると、これらの項目が作られなくなります。

type Blog @model(timestamps: null)

蛇足ですが、デフォルトでは(記載がないだけで)以下のような記述として解釈されるらしいです。

type Blog @model(timestamps: {create: "createdAt", update: "updatedAt" })

このあたりで議論されてました

github.com

CRUDについてもまとめようと思いましたが、ちょっと長くなってしまった。。

とりあえず今日はここまで。