📺

Annict の GraphQL API β を触ってみて詰まったところまとめ

2023/02/25に公開

Annict とは

Annict は shimbaco さんが開発・運営されている、アニメの視聴記録サービスです。
昔に見た作品を忘れてしまいがちな自分にとって、とても重宝しています 🙏

https://annict.com/

GraphQL API

GraphQL にあまり馴染みがなかったので勉強ついでに触ってみたところ、いくつか詰まったところがあったので備忘録を兼ねて書き残しておこうと思います。

seasons に渡す文字列の書式がわからない

結論

YYYY-(spring|summer|autumn|winter) でした。

例: 2005 年 秋 -> "2005-autumn"

背景

seasonssearchWorks() などの作品を取得するクエリで、放送シーズンを指定する際に渡す引数です。

例えば、以下のようなクエリで使用します。

# 2005年 秋に放送された作品を視聴者数降順で5件取得する
query {
  searchWorks(
    seasons: ["2005-autumn"]
    orderBy: { direction: DESC, field: WATCHERS_COUNT }
    first: 5
  ) {
    nodes {
      title
    }
  }
}

定数とかではなく文字列なのでドキュメント上での型は [String!] となっており、ぱっと見では形式がわかりませんでした。

色々見て回った後、Annict のシーズン毎のページ URL

https://annict.com/works/2005-autumn

を見てやっと気づいたのですが、今確認したところ ドキュメント内の Query のページ に使用例が載っていました…。

将来的に Input Objects に変更する構想もあるようです。
https://github.com/annict/annict/issues/3690

Annict の「記録する」ページに表示されている未視聴エピソードを取得したい

記録するページ
「記録する」ページはこんな感じです

結論

以下のクエリで取得できました。

# 「見たい」に設定している作品の未視聴エピソードとその作品名を取得する
query {
  viewer {
    libraryEntries(states: [WATCHING]) {
      nodes {
        work {
          title
        }
        nextEpisode {
          title
        }
      }
    }
  }
}
レスポンス
{
  "data": {
    "viewer": {
      "libraryEntries": {
        "nodes": [
          {
            "work": {
              "title": "あやかしトライアングル"
            },
            "nextEpisode": null
          },
          {
            "work": {
              "title": "ちいかわ"
            },
            "nextEpisode": null
          },
          {
            "work": {
              "title": "うる星やつら (2022)"
            },
            "nextEpisode": {
              "title": "失われたモノを求めて"
            }
          },
          {
            "work": {
              "title": "お兄ちゃんはおしまい!"
            },
            "nextEpisode": null
          }
        ]
      }
    }
  }
}

背景

初めは viewerprograms.unwatched というフィールドがあったので、以下のようなクエリを書いていました。

query {
  viewer {
    programs(unwatched: true) {
      nodes {
        episode {
          title
        }
      }
    }
  }
}

programs という名前だったので未視聴の放送予定が取得できるのかなと思ったのですが、中身の無いレスポンスが返ってきました…。

{
  "data": {
    "viewer": {
      "programs": {
        "nodes": []
      }
    }
  }
}

こちらも色々探したところ、Annict の公式ブログにぴったり該当する記事がありました。

https://developers.annict.com/blog/2021-10-24-library-entries-on-graphql-api

searchCharacters でキャラクターと登場作品名を同時に取得できない

以下のようなクエリでキャラクターとその登場作品名を取得しようとすると

# "後藤" を名前に含むキャラクターとその登場作品名をお気に入り数降順で5件取得する
query {
  searchCharacters(
    names: ["後藤"]
    orderBy: { field: FAVORITE_CHARACTERS_COUNT, direction: DESC }
    first: 5
  ) {
    nodes {
      name
      series {
        name
      }
    }
  }
}

一部のキャラクターのレスポンスが null になってしまうというものです。

レスポンス
{
  "data": {
    "searchCharacters": {
      "nodes": [
        {
          "name": "後藤ひとり",
          "series": {
            "name": "ぼっち・ざ・ろっく!"
          }
        },
        null,
        {
          "name": "後藤姫",
          "series": {
            "name": "かくしごと"
          }
        },
        {
          "name": "後藤可久士",
          "series": {
            "name": "かくしごと"
          }
        },
        null
      ]
    }
  },
  "errors": [
    {
      "message": "Cannot return null for non-nullable field Character.series"
    },
    {
      "message": "Cannot return null for non-nullable field Character.series"
    }
  ]
}

結論

こちらに関しては既に公式 Discord の api チャンネルにて似た事例が挙がっていました。

https://discord.com/channels/371121195619450881/371663377271095318/867272623363588127

API 側の不具合とのことなので、修正されるまでは REST API の /v1/characters エンドポイント と併用すると良いかもしれません。

原因

レスポンスの errors にもありますが、non-nullとして定義されているフィールドに対応するデータが DB に無く null が返っているのが原因のようです。

最後に

勉強の副産物として Annict での視聴記録を行える CLI ツールを作りました 📺
これでアニメの視聴記録 & ターミナル引きこもり生活がより捗るかもしれません…。

デモ
https://github.com/arrow2nd/anct

Discussion