NAV Navbar
Logo
GraphQL

APIリファレンス

このページでは、qnyp GraphQL API(以下API)の仕様について解説します。

APIを利用すると、qnypに登録されている情報を取得したり、ユーザーとしてエピソードの感想を記録することができます。

APIの利用に関する質問や要望は qnyp/developer.qnyp.com の Issues までどうぞ。

1. Overview

APIはGraphQLをベースとしています。すべてのリクエストはエンドポイント https://api.qnyp.com/graphql に対して送信します。

以下のGraphQLクライアントライブラリおよびクライアントソフトウェアでの動作を確認しています。

また、Ruby開発者向けに以下のライブラリおよびサンプルを公開しています。

2. Authorization

APIを利用するにはアクセストークンが必要となります。

アクセストークンは以下のいずれかの方法で取得します。

  1. パーソナルアクセストークンを利用する
  2. OAuth2アプリケーションをqnypに登録し、ユーザーからの許可を得てアクセストークンを取得する

それぞれの想定するユースケースは以下の通りです。

また、APIを試してみたい場合には、qnyp GraphQL Explorerを利用することでアクセストークンをあらかじめ準備することなく、APIの呼び出しやドキュメントの参照を行うことができます。

GraphQL Explorerのデモ

2.1. パーソナルアクセストークン

パーソナルアクセストークンとは、qnypのユーザーが自分で生成・破棄を行うことができるアクセストークンです。

パーソナルアクセストークンを生成するには、qnypにログインした状態で https://qnyp.com/settings/api へアクセスして、アクセストークンの生成操作を行います。

パーソナルアクセストークンの生成ページ

パーソナルアクセストークンに有効期限はありませんが、ユーザーはいつでも設定ページから自分のアクセストークンを無効化することができます。

2.2. OAuth2アプリケーション

OAuth2アプリケーションとしてユーザーの許可を得てアクセストークンを取得するには、まずqnypにログインしている状態で https://qnyp.com/oauth/applications にてアプリケーションの登録(作成)を行います。

アプリケーションの登録

アプリケーションの登録が完了すると「アプリケーションID」と「アプリケーションシークレット」が発行されるので、これを使ってOAuth2の認可フローを開始します。

アプリケーションの詳細

2.2.1 認可フロー

ここでは、qnypのユーザーからアプリケーションに対する認可を得る手順について説明します。

なお、qnypではOAunt 2.0で定義されている認可フローのうち「認可コードフロー(Authorization Code Flow)」のみをサポートしていますので、以降で説明する手順はそれに沿ったものとなります。

qnypへのリダイレクト:

ユーザーに認可を求めるには、まずあなたのアプリケーションから次ようなURLへのリダイレクトを行います。

GET https://qnyp.com/oauth/authorize?client_id={アプリケーションID}&response_type=code&scope={スコープ}&redirect_uri={コールバックURL}&state={anti-forgery-token}

qnypからのリダイレクト:

ユーザーがqnyp上で認可の要求を「認証」または「否認」すると、以下のようなURLにユーザーがリダイレクトされてきます。

GET {コールバックURL}?code={コード}&state={anti-forgery-token}

アクセストークンの取得:

$ curl -X POST https://api.qnyp.com/oauth/token \
  -d "client_id={アプリケーションID}" \
  -d "client_secret={アプリケーションシークレット}" \
  -d "code={コード}" \
  -d "grant_type=authorization_code" \
  -d "redirect_uri={コールバックURL}"
{
  "access_token": "bbfe3562bcf500fafac64397858ee9a8c1676959c9499726a4078218ec1546c9",
  "token_type": "bearer",
  "scope": "public write",
  "created_at": 1493395116
}

リダイレクトによって受け取ったcodeの値をはじめとする以下のパラメーターをAPIの /oauth/token にPOSTリクエストで送信すると、アクセストークンを取得することができます。

名前
client_id 登録したアプリケーションのアプリケーションID
client_secret 登録したアプリケーションのアプリケーションシークレット
code qnypからのリダイレクトで受け取ったコード
grant_type authorization_code
redirect_uri 登録したアプリケーションのコールバックURL

レスポンスは以下の値を含むJSONとなります。

名前
acces_token アクセストークン
token_type bearer
scope アクセストークンが持つスコープ(半角スペース区切り)
created_at アクセストークンの生成日時(UNIXタイムスタンプ)

発行されたアクセストークンに有効期限はありません。

2.3. アクセストークンによる認証

アクセストークンを使ってAPIへのリクエストを行うには、Authorization ヘッダに Bearer タイプとしてアクセストークンを指定します。

Authorization: Bearer アクセストークン

3. Scopes

アクセストークンの持つスコープによって、利用できるAPIが異なります。

API 必要なスコープ
GraphQLのQuery public
GraphQLのMutation public および write

公開情報の参照のみでよい場合は public スコープを、視聴ログの作成などの書き込み操作を行う場合は publicwrite スコープの両方を要求してください。

4. Errors

APIは、エラーが発生した際に以下のステータスコードを返します。

コード 意味
401 アクセストークンが無効である
403 アクセストークンがAPIリクエストに必要な権限を持っていない
404 無効なエンドポイントをリクエストした
429 リクエスト数が上限に達している
500 サーバー側でエラーが発生した
503 APIがメンテナンス中である

また、GraphQLリクエストに含まれるQueryおよびMutationの実行中に発生するエラー(バリデーションエラーなど)の場合のステータスコードは200となり、エラーの詳細がレスポンスボディに含まれます。

5. Rate limiting

# 通常時のレスポンス
X-RateLimit-Limit: 500
X-RateLimit-Remaining: 499
X-RateLimit-Reset: Tue, 14 Mar 2017 16:16:00 GMT
# リクエスト数が上限に達した場合のレスポンス
429 Too Many Requests

Retry-After: 3600
X-RateLimit-Limit: 500
X-RateLimit-Remaining: 0
X-RateLimit-Reset: Tue, 14 Mar 2017 16:16:00 GMT

APIへのリクエスト数の上限は、アクセストークン毎に1時間あたり500回までとなっています。

リクエスト数の残数や回数がリセットされる日時などの情報は、APIのレスポンスヘッダに以下のような形で含まれています。

ヘッダ
X-RateLimit-Limit リクエスト数の上限
X-RateLimit-Remaining リクエスト数の残り回数
X-RateLimit-Reset リクエスト数がリセットされる日時

リクエスト数が上限に達した場合は、ステータスコード429のレスポンスが返されます。また、その際にリクエスト数がリセットされるまでの秒数が Retry-After レスポンスヘッダで返されます。

6. GraphQL

6.1. Objects

GraphQL APIではqnyp上の主要なデータが以下のようなオブジェクトとして表現されます。

意味
Title タイトル。
TVシリーズやOVAなどのアニメ作品。
Episode エピソード。
タイトルに属する1つのエピソード。
User ユーザー。
qnypのユーザーアカウント。
Log 視聴ログ。
ユーザーがエピソードに対して記録した感想。

各オブジェクトの関係はおおまかに以下のようになります。

各オブジェクトの詳細な仕様に関しては GraphQL Explorer の Docs および GraphQL Schema document を参照してください。

6.2. ID

GraphQL APIにおける各オブジェクトは識別子として id (String)databaseId (Int) の2種類のIDを持ちます。

属性 説明
id すべてのオブジェクトにおいて一意な文字列
例: "VGl0bGUtMzUwMQ"
databaseId データベースにおけるプライマリキー
同一のオブジェクトにおいて一意な数値
例: 3501

GraphQL APIの操作においては基本的に id を使います。databaseId は「既にqnypのサイト上でIDがわかっているオブジェクトを取得する」場合の利便性のために用意されています。

6.2. Queries

情報を取得する場合は、 Query ルートタイプが持つ以下のフィールドに対するクエリをAPIに送ります。

フィールド 機能
episode idでエピソードを取得
episodeByDatabaseId databaseIdでエピソードを取得
log idで視聴ログを取得
logByDatabaseId databaseIdで視聴ログを取得
node idでオブジェクトを取得
nodes idでオブジェクトを一括取得
searchTitles タイトルを検索
title idでタイトルを取得
titleByDatabaseId databaseIdでタイトルを取得
user ユーザー名でユーザーを取得
viewer 認証したユーザーを取得

6.2.1 Query の例

query {
  viewer {
    id
    databaseId
    username
    profileImageURL
    recentlyWatchedTitles(first: 1) {
      edges {
        node {
          name
        }
      }
    }
    logs(first: 1) {
      edges {
        node {
          id
          channel
          rating
          episode {
            numberText
            title {
              name
            }
          }
        }
      }
    }
  }
}
{
  "data": {
    "viewer": {
      "id": "VXNlci0x",
      "databaseId": 1,
      "username": "junya",
      "profileImageURL": "//qnyp.global.ssl.fastly.net/attachments/05da1bf0b79769073ad0a2543f411521da298fa0/store/fill/80/80/1a63fa09379efe7e52335cfa74ecda8106585f6cb4ca6a91641f8ef6df0c/profile_image.png",
      "recentlyWatchedTitles": {
        "edges": [
          {
            "node": {
              "name": "月刊少女野崎くん"
            }
          }
        ]
      },
      "logs": {
        "edges": [
          {
            "node": {
              "id": "TG9nLTIxNDk2",
              "channel": "NET",
              "rating": "GREAT",
              "episode": {
                "numberText": "最終号",
                "title": {
                  "name": "月刊少女野崎くん"
                }
              }
            }
          }
        ]
      }
    }
  }
}

viewer フィールドから、「アクセストークンで認証したユーザー」の

を取得する例です。

6.2.2. Connection

一部のオブジェクトは Connection で終わる型名のフィールドを持っています(例えば User オブジェクトの logs フィールドは LogConnection 型)。

これらのコネクション表現はオブジェクト間の1対多関係を表現しており、カーソルを使ったページングをシンプルに実現するためのものとなっています。

その実装は Relay Cursor Connections Specification に沿ったものとなっていますので、詳細についてはそれらのドキュメントを参照してください。

6.3. Mutations

情報を更新する場合は、 Mutation ルートタイプが持つ以下のmutationフィールドに対するクエリをAPIに送ります。

フィールド 機能
createLog 視聴ログを作成する
deleteLog 視聴ログを削除する
updateLog 視聴ログを更新する

Mutation を実行するには、アクセストークンに public および write スコープが与えられている必要があります。

6.3.1 Mutation の例

mutation ($input: CreateLogInput!) {
  createLog(input: $input) {
    log {
      id
      databaseId
      createdAt
      url
    }
  }
}
// Query Variables
{
  "input": {
    "body": "楽しめるエピソードでした。",
    "channel": "TV",
    "episodeId": "RXBpc29kZS03NTY1OQ",
    "rating": "GREAT",
    "spoiler": false
  }
}
// Response
{
  "data": {
    "createLog": {
      "log": {
        "id": "TG9nLTIxMjE3",
        "databaseId": 99999,
        "createdAt": "2017-04-29T11:17:22Z",
        "url": "https://qnyp.com/junya/logs/99999"
      }
    }
  }
}

createLog フィールドで、エピソードに対する視聴ログを作成し、作成された視聴ログの情報を取得する例です。