GraphQL その2 言語仕様編
今回はより詳細にGraphQLの言語仕様を見ていく
前回同様GitHubのツールを使う
引数(Arguments)
公開されているリポジトリの情報を repository
を使って取得してみる
repository
の仕様は以下の通り
repository(name: String!owner: String!): Repository
引数として、リポジトリの owner
と name
が必要であることがわかる
僕のリポジトリをターゲットにして、適当な情報を取得してみる
query {
repository(owner: "hakozaru", name: "study_JavaScript") {
description
url
stargazers {
totalCount
}
}
}
↓レスポンス
{
"data": {
"repository": {
"description": "JSを言語仕様から把握し、ライブラリに振り回されない漢を目指すリポジトリ",
"url": "https://github.com/hakozaru/study_JavaScript",
"stargazers": {
"totalCount": 20
}
}
}
}
ちゃんと取れている〜
stargazers
は引数を取るが、必須となる引数はないので省略できていることもわかる↓
stargazers(
after: String
before: String
first: Int
last: Int
orderBy: StarOrder
): StargazerConnection!
エイリアス(Aliases)
別名を付けられるアレですが、GraphQLでも使うことができる(ドキュメント)
もし2つのリポジトリの情報を同時に取得したい場合、以下のようなクエリはエラーとなる
query {
repository(owner: "hakozaru", name: "study_JavaScript") {
description
}
repository(owner: "hakozaru", name: "study_gem") {
description
}
}
レスポンスには fieldConflict
と返ってきており、重複してしまっていることがわかる
そんな時に使えるのがエイリアスで、以下のように 別名:
を先頭につけてあげるだけでよい
query {
rep1: repository(owner: "hakozaru", name: "study_JavaScript") {
description
}
rep2: repository(owner: "hakozaru", name: "study_gem") {
description
}
}
レスポンス
{
"data": {
"rep1": {
"description": "JSを言語仕様から把握し、ライブラリに振り回されない漢を目指すリポジトリ"
},
"rep2": {
"description": "gemとはなんなのか & gemのソース読んでRuby力向上を目指すリポジトリ"
}
}
}
フラグメント(Fragments)を使ってクエリをDRYに
↑のエイリアスのクエリは、同じような構造をしている箇所が複数ありちょっとDRYではない
そんな時に使えるのがフラグメントというもので、重複している箇所を共通化することができる
query {
rep1: repository(owner: "hakozaru", name: "study_JavaScript") {
...repDescription
}
rep2: repository(owner: "hakozaru", name: "study_gem") {
...repDescription
}
}
fragment repDescription on Repository {
description
url
}
レスポンス
{
"data": {
"rep1": {
"description": "JSを言語仕様から把握し、ライブラリに振り回されない漢を目指すリポジトリ",
"url": "https://github.com/hakozaru/study_JavaScript"
},
"rep2": {
"description": "gemとはなんなのか & gemのソース読んでRuby力向上を目指すリポジトリ",
"url": "https://github.com/hakozaru/study_gem"
}
}
}
あ〜いい感じですわ〜
操作名(Operation Name)
前回の記事で、 query
は省略が可能であると書きました
具体的には以下の二つのクエリは等価ということです
query {
user(login: "hakozaru") {
bio
}
}
{
user(login: "hakozaru") {
bio
}
}
下の query
が省略されているクエリは「無名操作(anonymous operation)」と呼ばれるもので
実は一回のリクエストで一つしか書くことができないという制約がある
もし二つ無名操作を書いた場合は Operation name is required when multiple operations are present
というエラーが表示される
でも俺はトップレベルに二つクエリを書きたいんじゃーという方のために、操作に名前をつけることができる(operation name)
(無名操作を二つ書くことは諦めろ)
query
の後に任意の名前をつけるだけ
query userInfo1 {
user(login: "hakozaru") {
bio
}
}
query userInfo2 {
user(login: "hogehoge-san") {
bio
}
}
こうすることでクエリを発行する際に、どちらのクエリを発行するのか尋ねられる
変数(Variables)
今までの例では hakozaru
という文字列をハードコーディングしていたが、これは変数に入れておきたい
GraphQLではちゃんと変数も使うことができる
GitHubのExplorerでは、クエリを書く欄の下にある QUERY VARIABLES
から入れることができる
定義した変数は、頭に $
をつけることで参照することができるので、 query
に型とともに渡してやればよい
(余談だけど、ちょっとクエリを書き換えるだけでvariablesが空にされるんだけど僕だけ?ハイパーストレス)
ミューテーション(Mutations)
前回の記事でルートタイプがどうのと書いたとき、 query
と mutation
があることに触れた
ここまでスルーしていたが、ここでミューテーションについてみていく
公式のドキュメントを見ると、
「サーバーのデータを変更したり、書き込んだりする操作は、明示的にミューテーションを介して送信する必要があるという規則を作っておくとよい」
ということで、何らかの副作用を発生させるクエリは mutation
に定義しておけということらしい
GitHub Explorerの mutation
のドキュメントを眺めてみても、 create_XXX
とか update_XXX
みたいな、
いかにも副作用がありそうなクエリが並んでいる
ということで何かクエリを発行してみたいんだけど、リポジトリの作成とかならお手軽かな?
ということで以下のAPIを叩いて、実際にリポジトリが作成されるか確認する
まずは必要な情報の確認
mutation
を使うcreateRepository
のAPIの仕様は以下の通り
createRepository(input: CreateRepositoryInput!): CreateRepositoryPayload
Create a new repository.
createRepository
は引数としてinput
にCreateRepositoryInput
とやらを渡す必要がある- ドキュメントを見ると、必須パラメータなのは
name
とvisibillity
だけ - 説明も入れたいので
description
も渡す
- ドキュメントを見ると、必須パラメータなのは
createRepository
が返すフィールドも確認するとrepository
のdescription
で説明が取得できるようなので、ちゃんと渡した説明が取得できるか確認する
ということで組み立てたクエリが↓
mutation createRepo {
createRepository(input: {
name: "new-repo-from-github-graphql-api",
visibility: PUBLIC,
description: "GitHubのGraphQL APIを叩いて作成したリポジトリだよ"
}) {
repository {
description
}
}
}
叩いてみると
{
"data": {
"createRepository": {
"repository": {
"description": "GitHubのGraphQL APIを叩いて作成したリポジトリだよ"
}
}
}
}
ちゃんとリポジトリが作成されて description
が設定されているっぽい
自分のリポジトリ一覧を見ると
ちゃんと作られてるー!
ということで簡単ですがGraphQLの言語仕様でした〜