GraphQLでの認証
GraphQLサーバーと通信するには、適切なスコープを持つOAuthトークンが必要です。
「個人用アクセス トークンの作成」のステップに従ってトークンを作成します。 必要なスコープは、リクエストしようとしているデータの種類によります。 たとえば、ユーザー データを要求する ユーザー スコープを選択します。 リポジトリ情� �にアクセスする必要がある� �合は、適切な リポジトリ スコープを選択してく� さい。
以下のスコープをおすすめします。
repo
read:packages
read:org
read:public_key
read:repo_hook
user
read:discussion
read:enterprise
read:gpg_key
リソースが特定のスコープを必要とするなら、APIは通知してくれます。
GraphQLのエンドポイント
REST APIは多数のエンドポイントを持ちますが、GraphQL APIは単一のエンドポイントを持ちます。
http(s)://HOSTNAME/api/graphql
行う操作にかかわらず、エンドポイントは一定のままです。
GraphQLでの通信
GraphQL の操作は複数行の JSON で構成されるため、GitHub は Explorer を使用して GraphQL 呼び出しを行うことをお勧めします。 cURLや、その他の任意のHTTPを使うライブラリも利用できます。
REST では、HTTP 動詞によって実行される操作が決まります。 GraphQL では、クエリまたはミューテーションを実行する� �合でも、JSON でエンコードされた本文を提供するので、HTTP 動詞は POST となります。 例外は、エンドポイントに対する単純な GET であるイントロスペクション クエリです。 GraphQL と REST の詳細については、「REST から GraphQL への移行」を参照してく� さい。
cURL を使用して GraphQL にクエリを実行するには、JSON ペイロードを使用して POST 要求を行います。 ペイロードには、query という文字列が含まれている必要があります。
curl -H "Authorization: bearer token" -X POST -d " \
{ \
\"query\": \"query { viewer { login }}\" \
} \
" http(s)://HOSTNAME/api/graphql
注: "query" の文字列値は改行文字をエスケープする必要があります。さもないと、スキーマで正しく解析されません。 POST の本文には、外側の二重引用符とエスケープされた内側の二重引用符を使用します。
クエリ及びミューテーション操作について
GitHubの GraphQL API で許可される操作の 2 種類は 、クエリ と 変更です。 GraphQL と REST を比較すると、クエリは GET 要求と同様に動作しますが、ミューテーションは POST/PATCH/DELETE のように動作します。 ミューテーション名によって、実行される変更が決まります。
レート制限の詳細については、「GraphQL リソース制限」を参照してく� さい。
クエリとミューテーションは似た形式を持っていますが、重要な違いがあります。
クエリについて
GraphQL クエリからは、指定したデータのみが返されます。 クエリを作成するには、スカラー� けを返すまで、フィールド内フィールドを指定する必要があります (入れ子になったサブフィールド とも呼ばれます)。
クエリは次のように構成されます。
query {
JSON objects to return
}
実際の例については、「クエリの例」を参照してく� さい。
ミューテーションについて
ミューテーションを作成するには、3つのことを指定しなければなりません。
- ミューテーション名。 実行したい変更の種類です。
- 入力オブジェクト。 サーバーに送信するデータ。入力フィールド で構成されます。 これはミューテーション名に引数として渡してく� さい。
- ペイロード オブジェクト。 サーバーから返すデータ。戻り値のフィールド で構成されます。 これは、ミューテーション名のボディとして渡してく� さい。
ミューテーションは以下のような構� になります。
mutation {
mutationName(input: {MutationNameInput!}) {
MutationNamePayload
}
}
この例の入力オブジェクトは MutationNameInput、ペイロード オブジェクトは MutationNamePayload です。
ミューテーション参照では、一覧表示された 入力フィールド が入力オブジェクトとして渡されます。 一覧表示されている 戻り値のフィールド は、ペイロード オブジェクトとして渡されます。
実際の例については、「ミューテーションの例」を参照してく� さい。
変数の使用
変数を使用すると、クエリをより動的かつ強力にすることができ、ミューテーションの入力オブジェクトを渡すときの複雑さを軽減できます。
注: Explorer を使用している� �合は、別の クエリ変数ペインに変数を入力し、JSON オブジェクトの前に単語 variables を含めないでく� さい。
以下は、1つの変数を持つクエリの例です。
query($number_of_repos:Int!) {
viewer {
name
repositories(last: $number_of_repos) {
nodes {
name
}
}
}
}
variables {
"number_of_repos": 3
}
変数を利用するには3つのステップがあります。
-
variablesオブジェクト内の操作の外部で変数を定義します。variables { "number_of_repos": 3 }オブジェクトは有効なJSONでなければなりません。 この例は単純な
Int変数型を示していますが、入力オブジェクトなど、より複雑な変数型を定義できます。 ここで複数の変数を定義することもできます。 -
変数を操作に引数として渡します。
query($number_of_repos:Int!){引数はキーと値のペアで、キーは 名前 (例: ) で
$始まり、$number_of_repos値は 型 (例:Int) です。 型が必要かどうかを示す!を追� します。 複数の変数を定義した� �合は、それらをここで複数の引数として含めてく� さい。 -
変数を操作の中で利用してく� さい。
repositories(last: $number_of_repos) {この例では、変数を取得するリポジトリ数に置き換えています。 GraphQLは強い型付けを強制するので、ステップ2で型を指定しています。
このプロセスでクエリの引数は動的になります。 これで、variables オブジェクト内の値を変更し、クエリの残りの部分を同じに保つことができます。
変数を引数として使用すると、クエリを変更せずに variables オブジェクト内の値を動的に更新できます。
クエリの例
もっと複雑なクエリを見ていき、これらの情� �を流れの中で捉えていきましょう。
次のクエリでは、octocat/Hello-World リポジトリを検索し、最新の 20 個の解決された issue を検索し、各 issue のタイトル、URL、最初の 5 つのラベルを返します。
query {
repository(owner:"octocat", name:"Hello-World") {
issues(last:20, states:CLOSED) {
edges {
node {
title
url
labels(first:5) {
edges {
node {
name
}
}
}
}
}
}
}
}
この構� を1行ずつ見ていきましょう。
-
query {目的はサーバーからデータを読み取ることであり、変更することではありません。
queryはルート操作です。 (操作を指定しない� �合は、queryも既定値になります。) -
repository(owner:"octocat", name:"Hello-World") {クエリを開始するには、
repositoryオブジェクトを検索します。 スキーマの検証により、このオブジェクトにownerとnameの引数が必要であることがわかります。 -
issues(last:20, states:CLOSED) {リポジトリ内のすべての issue について説明するために、
issuesオブジェクトを呼び出します。 (1 つのクエリをissue実行repositoryすることもできますが、返す問題の数を把握し、引数として指定する必要があります)。issuesオブジェクトに関するいくつかの詳細を次に示します。- このドキュメントでは、このオブジェクトに型
IssueConnectionがあることがわかります。 - スキーマの検証では、このオブジェクトでは引数として結果の
lastの数またはfirstの数が必要であることがわかるので、20を指定します。 - このドキュメントでは、このオブジェクトが
states引数を受け入れることも示しています。これはOPENまたはCLOSEDの値を受け入れるIssueState列挙型です。 解決された issue のみを見つけるには、statesキーにCLOSEDの値を指定します。
- このドキュメントでは、このオブジェクトに型
-
edges {IssueConnection型を持っているため、issuesは接続であることがわかります。 個々の問題に関するデータを取得するには、edgesを使用してノードにアクセスする必要があります。 -
node {ここで、エッジの端にあるノードを取り出します。
IssueConnectionこのドキュメントでは、IssueConnection型の末尾にあるノードがIssueオブジェクトであることが示されています。 -
Issueオブジェクトを取得することがわかっているので、ドキュメントを確認し、返すフィールドを指定できます。title url labels(first:5) { edges { node { name } } }ここで、
Issueオブジェクトのtitle、url、labelsフィールドを指定します。labelsフィールドは型LabelConnectionを持っています。issuesオブジェクトと同様に、labelsは接続であるため、そのエッジを接続されたノード (labelオブジェクト) に移動する必要があります。 ノードでは、返すlabelオブジェクト フィールドを指定できます。この� �合は、nameです。
Octocat のパブリック Hello-World リポジトリでこのクエリを実行しても、多くのラベルが返されないことに気付くかもしれません。 ラベルを使っている自分自身のリポジトリに対してこれを実行してみれば、違いがわかるでしょう。
ミューテーションの例
ミューテーションでは、まずクエリを実行して見なければ分からない情� �が必要になることがよくあります。 この例では2つの操作を示します。
- IssueのIDを取得するクエリ。
- 絵文字のリアクションをそのIssueに追� するミューテーション。
query FindIssueID {
repository(owner:"octocat", name:"Hello-World") {
issue(number:349) {
id
}
}
}
mutation AddReactionToIssue {
addReaction(input:{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}) {
reaction {
content
}
subject {
id
}
}
}
クエリとミューテーションに名前 (この例では FindIssueID と AddReactionToIssue) を付ければ、同じ Explorer ウィンドウに含めることができますが、操作は GraphQL エンドポイントへの個別の呼び出しとして実行されます。 クエリをミューテーションと同時に、あるいはミューテーションとクエリを同時に実行することはできません。
例を見ていきましょう。 このタスクはシンプルに見えます。絵文字のリアクションをIssueに� える� けです。
それでは、クエリから始めることはどのように知ることができるのでしょうか? この時点ではま� わかりません。
サーバー上のデータを変更したい(絵文字をIssueに添付する)ので、まずは役に立つミューテーションを探してスキーマを検索することから始めます。 参照ドキュメントでは、addReaction ミューテーションが、「Adds a reaction to a subject.」という説明とともに示されています。完璧です。
このミューテーションのドキュメントには、3つの入力フィールドがリストアップされています。
clientMutationId(String)subjectId(ID!)content(ReactionContent!)
! は subjectId と content が必� �フィールドであることを示します。 必� �の content は意味があります。リアクションを追� するため、使用する絵文字を指定する必要があります。
しかし、なぜ subjectId が必要なのでしょうか。 これはsubjectId、リポジトリがどの問題に対応 するかを 特定する唯一の方法であるためです。
このため、この例では ID を取得するためのクエリから始めています。
クエリを1行ずつ調べていきましょう。
-
query FindIssueID {ここではクエリを実行し、
FindIssueIDという名前を付けます。 クエリに名前を付けるのはオプション� ということに注意してく� さい。ここでは、ミューテーションと同じExplorerウィンドウに置けるように名前を付けています。 -
repository(owner:"octocat", name:"Hello-World") {リポジトリを指定するには、
repositoryオブジェクトに対してクエリを実行し、ownerおよびname引数を渡します。 -
issue(number:349) {issueオブジェクトに対してクエリを実行し、number引数を渡すことによって、対応する issue を指定します。 -
idここで、
subjectIdとして渡すhttps://github.com/octocat/Hello-World/issues/349のidを取得します。
クエリを実行すると、MDU6SXNzdWUyMzEzOTE1NTE= という id が取得されます。
注: クエリで返される id は、ミューテーションで subjectID として渡す値です。 ドキュメントも、スキーマのイントロスペクションでもこの関係は示されません。このことを理解するには、名前の背景となっている概念を理解しなければなりません。
IDが分かれば、ミューテーションで先に進むことができます。
-
mutation AddReactionToIssue {ここではミューテーションを実行し、
AddReactionToIssueという名前を付けます。 クエリと同じように、ミューテーションに名前を付けることはオプションです。ここではクエリと一緒に同じExplorerウィンドウに置けるように名前を付けています。 -
addReaction(input:{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}) {この行を調べましょう。
-
addReactionはミューテーションの名前です。 -
inputは必要な引数キーです。 ミューテーションではこれは常にinputになります。 -
{subjectId:"MDU6SXNzdWUyMzEzOTE1NTE=",content:HOORAY}は必要な引数の値です。 これは常に、ミューテーションの入力フィールド (この� �合はsubjectIdとcontent) で構成される 入力オブジェクト (したがって中かっこ) になります。どの値がcontentとして使われるのかは、どのように分かるのでしょうか?
addReactionのドキュメントでは、contentフィールドの型はReactionContentです。これは GitHub issue で特定の絵文字のリアクションのみがサポートされているため列挙型になっています。 リアクションとして使える値は以下のとおりです(いくつかの値は対応する絵文字の名前とは異なっていることに注意してく� さい)。コンテンツ 絵文字 +1👍 -1👎 laugh😄 confused😕 heart❤️ hooray🎉 rocket🚀 eyes👀
-
-
呼び出しの残りの部分は、ペイロードオブジェクトから構成されます。 ここでは、ミューテーションを行った後にサーバーから返してほしいデータを指定します。 これらの行は、
addReactionのドキュメントから取得したもので、次の 3 つの可能な戻り値フィールドがあります。clientMutationId(String)reaction(Reaction!)subject(Reactable!)
この例では、2 つの必� �フィールド (
reactionおよびsubject) を返します。両方とも必� �サブフィールド (それぞれcontentおよびid) を持っています。
このミューテーションを実行すると、レスポンスは次のようになります。
{
"data": {
"addReaction": {
"reaction": {
"content": "HOORAY"
},
"subject": {
"id": "MDU6SXNzdWUyMTc5NTQ0OTc="
}
}
}
}
これで完了です。 🎉 の上にカーソルを合わせてユーザー名を探し、issue に対する反応をチェックアウトします。
最後に一つ注意です。インプットオブジェクト中で複数のフィールドを渡す� �合、構文が扱いにくくなることがあります。 フィールドを変数に移動すると役立ちます。 以下では、オリジナルのミューテーションを変数を使って書き換えています。
mutation($myVar:AddReactionInput!) {
addReaction(input:$myVar) {
reaction {
content
}
subject {
id
}
}
}
variables {
"myVar": {
"subjectId":"MDU6SXNzdWUyMTc5NTQ0OTc=",
"content":"HOORAY"
}
}
先ほどの例では、content のフィールド値 (これはミューテーション中で直接使用されます) には HOORAY の周りに引用符がありませんが、変数で使用される� �合には引用符があることがわかります。 これには理由があります。
- ミューテーションで
contentを直接使用する� �合、スキーマはその値が文字列ではなく 列挙型 であるReactionContent型であると想定します。 スキーマ検証は、列挙値の周りにクオートを� えるとエラーを投げます。これはクオートが文字列のために予約されているからです。 contentを変数で使用する� �合、variables セクションは有効な JSON である必要があるため、引用符が必要です。 スキーマ検証では、実行中に変数がミューテーションに渡されるときに、ReactionContent型が正しく解釈されます。
列挙型と文字列型の違いの詳細については、公式の GraphQL 仕様に関するページを参照してく� さい。
参考資料
GraphQL 呼び出しを形成する� �合は、さらに 多くの ことができます。 以下は、次に見るべき� �所です。