【GraphQL】基礎的な書き方から、AniList API用のMutationクエリ(複数レコード更新)まで。

2115 語
11 分
【GraphQL】基礎的な書き方から、AniList API用のMutationクエリ(複数レコード更新)まで。

はじまり#

リサちゃん avatar
リサちゃん
あぁぁ、目が回りそうだぁ!
135ml avatar
135ml
GraphQLを組み立てているね
リサちゃん avatar
リサちゃん
これって、()なの? {}なの?
135ml avatar
135ml
おさらいしてみましょうか

GraphQLを触ってみました#

なので、今回はGraphQLに関する記事を書いてみます。 本記事では、GraphQLの基礎的な書き方をから、初心者でも迷わずにクエリを構築できるように、基本的なQueryとMutationの書き方を紹介します。 後の方では、実際にAniListというサービスで叩いた結果を紹介します。

GraphQLの基本的な部分#

まず、GraphQLとは?

スゴイざっくり言うと、「APIにアクセスするための仕組み」です。

LinuxでおなじみのRed Hatさんの記事ではこう書いてあります。(会社の業務で触ったLinuxなつかしい・・・)

GraphQL (グラフキューエル、グラフQL) とは、API (アプリケーション・プログラミング・インタフェース向けのクエリ言語とサーバーサイドのランタイムの両方を指します。GraphQL は、クライアントがリクエストしたデータのみを返すことを優先します。

ここから引用

なるほど、クエリだけじゃなくてランタイムも引っくるめて「GraphQL」なんだな。 GraphQLは、同じAPIの仕組みの一つである「Rest API」と比べて、としては、データの取得や更新が行いやすいクエリ言語を備えています。

クエリを書く前に#

クエリを書く前に、以下の2点を確認する必要があります。

1. GraphQLスキーマ#

GraphQLスキーマは、GraphQLサーバーで提供されているデータの種類と構造を定義するものです。スキーマは、SDL(Schema Definition Language)と呼ばれる言語で記述されます。

2. 取得したいデータ#

どのようなデータを取得したいかを明確にしましょう。具体的な項目名や関連データなども考慮する必要があります。

クエリの書き方#

基本構文#

GraphQLクエリの基本構文は次のとおりです。

query {
# 取得したいデータのフィールドを記述
}

例えば、ユーザー情報と投稿情報を取得するクエリは次のようになります。

query {
user {
id
name
birthDate
}
posts {
id
title
content
}
}

このクエリは、userフィールドとpostsフィールドを指定しています。userフィールドではIDとユーザー名を取得し、postsフィールドではID、題名、内容を取得します。

Arguments#

取得する情報に条件を付けることが出来ます。

query {
users(name: "Tom") {
id
name
age
birthDate
}
}

この場合は、名前が「Tom」だけのユーザーを取得することになります。

Nest#

ときどき、取得する情報が細分化されて、さらに属性を持っていたりもします。

query {
users(name: "Tom") {
id
name
age
birthDate {
year
month
day
}
}
}

この場合は、ユーザーの誕生日が、さらに年、月、日に分かれているパターンとなります。

Variables#

そして、属性のパラメータ値は、まとめて別の場所で宣言することが出来ます。 例えば、こんなクエリに対して、

query {
users(name: "Tom") {
id
name
age
birthDate(year: 2023) {
year
month
day
}
}
}

queryフィールドとは別に、variablesフィールドとして、パラメータを一括に宣言できます。 宣言方法は次の節で・・・

{
userName: "Tom"
birthYear: 2023
}
query ($username: String, $birthYear: Int) {
users(name: $userName) {
id
name
age
birthDate(year: $birthYear) {
year
month
day
}
}
}

パラメータに使える型は、String、Int、Float、Booleanなど、色々あります。

JavaScriptとかでJSON.stringifyすれば・・・#

JavaScritpなどでクエリを作る際に、JSON.stringify()を使えば、クエリとは別にvariablesを宣言できます。 例えば、JavaScriptライクな言語「Google Apps Script」からGraphQLを打つ場合は、こんな感じでAPIにアクセスする記述が出来ます。

let variables = {
userName: "Tom"
birthYear: 2023
}
let query = `query ($username: String, $birthYear: Int) {
users(name: $userName) {
id
name
age
birthDate(year: $birthYear) {
year
month
day
}
}
}
`;
let options = {
method: "POST"
, headers: {
"Content-Type": "application/json",
"Accept": "application/json"
}, payload: JSON.stringify({
query: query
, variables: variables
})
};
let response = UrlFetchApp.fetch(url, options);

Mutation#

さて、queryフィールドでは、データを参照するのが主な用途ですが、データを書き換えたりもしたくなります。 そこで使うのが、mutationフィールドです。

mutation {
createUser(input: { name: "Mary", age: 94 }) {
id
name
age
}
}

mutationフィールドでは、編集する属性を指定して、どの属性をレスポンスとして受け取るかを指定することが出来ます。上記のクエリの場合だと、IDがアッチ側で自動採番だとしてこんな風に返ってきます。

{"data":{"createUser":{"id":3,"name":"Mary,"age":94}}}

Mutationでvariables#

mutationフィールドでも、もちろんvariablesが利用できます。 宣言方法は、「JavaScriptとかでJSON.stringifyすれば・・・」の節と同様。

variables = {
userName: "Mary"
age: 94
}
mutation ($userName: String, $age: Int) {
createUser(input: { name: $userName, age: $age }) {
id
name
age
}
}

Mutation内のNestにvariablesを使う#

mutationフィールド内で入れ子になっている部分にvariablesを使いたい場合に、こんがらがってしまうかもしれません。(実際に僕はこんがらがりました。) こんな風にします。

variables = {
userName: "Mary"
age: 94
birthYear: 2005
}
mutation ($userName: String, $age: Int) {
createUser(input: { name: $userName, age: $age, birthDate: {year: $birthYear}) {
id
name
age
birthDate {
year
month
day
}
}
}

あくまで、createUserの「{}」の中身は「参照」したい属性なので、「()」の引数に変数を「設定」しましょう。

variables = {
userName: "Mary"
age: 94
birthYear: 2005
}
mutation ($userName: String, $age: Int) { // <- 変数を設定したい
createUser(input: { name: $userName, age: $age, birthDate: {year: $birthYear}) { // <- 対象を設定したい
id // <- 参照したい
name // <- 参照したい
age // <- 参照したい
birthDate {
year // <- 参照したい
month // <- 参照したい
day // <- 参照したい
}
}
}

そして、実際にAniList APIで叩いてみた#

「AniList」というのは、自分が今までに見たアニメや、これから見たいアニメ、読みたいマンガなどを登録、管理できるサービスです。

APIのリファレンスのGetting-Startedはここで、GraphQLの属性のリファレンスはここです。

その管理しているデータベースには、「AniList API」を使って参照することができて、編集することも出来ます。 こんな風に打ち込みます。まずはqueryでデータ取得です。

variables = {
username: "anilistUserName"
, userid: "anilistUserId"
}
query ($username: String, $id: Int) {
MediaListCollection(userName: $username, userId: $id, type: ANIME) {
lists {
entries {
media {
id
title {
native
}
coverImage {
extraLarge
}
siteUrl
studios (isMain: true, sort: FAVOURITES) {
nodes {
name
}
}
}
score (format: POINT_100)
status
progress
completedAt {
year
month
day
}
notes
updatedAt
}
}
}
}

次で、mutationでデータの編集をしています。

variables = {
mediaId: 21127
, status: "CURRENT"
, score: 100
, progress: 13
, completedAtYear: 2022
, completedAtMonth: 1
, completedAtDay: 13
, notes: "エル・プサイ・コングルゥ。"
}
mutation ($mediaId: Int, $status: MediaListStatus, $score: Float, $progress: Int, $completedAtYear: Int, $completedAtMonth: Int, $completedAtDay: Int, $notes: String) {
SaveMediaListEntry (mediaId: $mediaId, status: $status, score: $score, progress: $progress, notes: $notes, completedAt: {year: $completedAtYear, month: $completedAtMonth, day: $completedAtDay}) {
id
mediaId
status
score (format: POINT_100)
progress
completedAt {
year
month
day
}
notes
}
}

レスポンス:

{"data":{"SaveMediaListEntry":{"id":246757832,"mediaId":21127,"status":"CURRENT","score":100,"progress":13,"completedAt":{"year":2022,"month":1,"day":13},"notes":"\u30a8\u30eb\u30fb\u30d7\u30b5\u30a4\u30fb\u30b3\u30f3\u30b0\u30eb\u30a5\u3002"}}}

複数レコードを編集したいときは?#

AniList APIでは、「1分間に90リクエストまで」のレート制限が設けられています。 そのため、複数のアニメを編集したいときは、クエリをまとめて送りたいですよね。 Google Apps Scriptで組むと、こんな風に複数レコードに対する1クエリが作成できます。

let variableses = [
{
"mediaId": 21127
, "status": "CURRENT"
, "score": 100
, "progress": 13
, "completedAtYear": 2021
, "completedAtMonth": 1
, "completedAtDay": 13
, "notes": "エル・プサイ・コングルゥ。"
}
, {
"mediaId": 9253
, "status": "PLANNING"
, "score": 90
, "progress": 13
, "completedAtYear": 2017
, "completedAtMonth": 3
, "completedAtDay": 15
, "notes": "ファーーーハッハッハッハ"
}
];
console.log(variableses.length);
console.log(`getRequestOptionsAnilist: 3333333333333333333333333333333333333333333333`);
for(let i = 0; i < variableses.length; i++){
query = `
${query}
saveMedia${i}: SaveMediaListEntry (mediaId: ${variableses[i]["mediaId"]}, status: ${variableses[i]["status"]}, score: ${variableses[i]["score"]}, progress: ${variableses[i]["progress"]}, notes: "${variableses[i]["notes"]}", completedAt: {year: ${variableses[i]["completedAtYear"]}, month: ${variableses[i]["completedAtMonth"]}, day: ${variableses[i]["completedAtDay"]}}) {
id
mediaId
status
score (format: POINT_100)
progress
completedAt {
year
month
day
}
notes
}
`;
}
query = `mutation {${query}}`;
console.log(query);
console.log(`getRequestOptionsAnilist: 44444444444444444444444444444444444444444444`);
options = {
method: "POST",
headers: {
"Authorization": `Bearer ${access_token}`,
"Content-Type": `application/json`,
"Accept": `application/json`,
}
, payload: JSON.stringify({
query: query
})
, muteHttpExceptions : true
}

上記でミソなのは、SaveMediaListEntryの前に、saveMedia${i}:という風にフィールドに名前を付けている点です。

少し脱線しますが、1つのリクエストに付きのクエリの長さのレート制限は、確認することが出来ませんでした。まあ程々にでしょうか。

まとめ#

以上がGraphQLの基礎的なクエリの書き方と少し応用といった感じでした。 querymutationを使いこなして、効果的にデータを取得・変更できるようになると、GraphQLの真価がより体感できるでしょう。 ぜひこれを参考に、日々の活動でGraphQLを活用してみてください。

おしまい#

リサちゃん avatar
リサちゃん
ほぁぁ、こう書くのか!
135ml avatar
135ml
一回書けてしまえばなぁ。

以上になります!

記事を共有

この記事が役に立ったなら、ぜひ他の人と共有してください!

【GraphQL】基礎的な書き方から、AniList API用のMutationクエリ(複数レコード更新)まで。
https://endorphinbath.com/posts/graphql-base-to-anilist-mutation/
著者
kinkinbeer135ml
公開日
2024-01-16
ライセンス
CC BY-NC-SA 4.0
ランダム記事 ランダム
Profile Image of the Author
kinkinbeer135ml
SIerをやめて、プログラミングを勉強しています。※Amazonアソシエイトに参加しています。
お知らせ
私のブログへようこそ!これはサンプルのお知らせです。
音楽
カバー

音楽

再生中なし

0:00 0:00
歌詞なし
カテゴリ
タグ
サイト統計
記事
287
カテゴリー
8
タグ
93
総文字数
486,174
運用日数
0
最終活動
0 日前

目次