NAV Navbar
GraphQL
  • APIリファレンス
  • 1. Overview
  • 2. Authorization
  • 3. Scopes
  • 4. Errors
  • 5. Rate limiting
  • 6. GraphQL
  • APIリファレンス

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

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

    APIの利用に関する質問や要望は qnyp/qnyp.dev の 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 フィールドで、エピソードに対する視聴ログを作成し、作成された視聴ログの情報を取得する例です。