https://d226lax1qjow5r.cloudfront.net/blog/blogposts/using-apollo-to-query-graphql-from-node-js/apollo_graphql.png

Apolloを使ってNode.jsからGraphQLをクエリする

最終更新日 November 3, 2020

所要時間:2 分

素早くプロトタイプを作成し、それがうまくいったのに、経営陣が昨日中に本番稼動させたいと望んでいる。もしかしたら、サードパーティのGraphQLエンドポイントにアクセスしていたかもしれない。障害のひとつは?そのエンドポイントはCORSヘッダーを提供していない。もうフロントエンドのJavaScriptアプリから直接呼び出すことはできません。

必要なデータセットごとにルートを持つExpressアプリを作成する必要がありますか?そんなことはない!このチュートリアルでは ApolloクライアントライブラリをNode.js Expressアプリ内で使用して、GraphQLクエリやミューテーションを書き換えることなく、サードパーティエンドポイントへのミドルマンを提供します。

Apolloに加えて、以下のようないくつかのNPMライブラリがある。 lokkaexpress-graphqlなどのNPMライブラリがあります。これらのライブラリにはそれぞれ長所と短所がある。Apolloは人気があり、Apollo Data Graph Platformの一部としてサポートされているため、Apolloを使用することにします。 Apolloデータグラフプラットフォーム.

最後まで読み飛ばしたいですか?このチュートリアルのソースコードはすべて GitHub.

はじめに

まず、すべてのファイルと依存関係を整えよう。というフォルダを作成し nodejs-apollo-clientというフォルダを作成し、お好みのターミナルで開いてください。

ターミナルで npm initを実行し、ディレクトリ内のNPMを初期化する。次に、以下のスクリプトを実行して依存関係をインストールします。

npm install --save npm i apollo-cache-inmemory apollo-client apollo-link-http express graphql graphql-tag node-fetch

GraphQLミドルマンを構築する

という名前の新しいファイルを作成する。 apollo.js.このファイルには、私たちのソリューションの本当の「肉」が含まれています。ExpressアプリケーションとサードパーティのGraphQLエンドポイント間のリクエストを仲介します。

そのファイルに次のスニペットをコピーすることから始めよう。

const gql = require("graphql-tag");
const ApolloClient = require("apollo-client").ApolloClient;
const fetch = require("node-fetch");
const createHttpLink = require("apollo-link-http").createHttpLink;
const setContext = require("apollo-link-context").setContext;
const InMemoryCache = require("apollo-cache-inmemory").InMemoryCache;

const httpLink = createHttpLink({
  uri: "https://insights.opentok.com/graphql",
  fetch: fetch
});

const client = new ApolloClient({
  link: httpLink,
  cache: new InMemoryCache()
});

この clientオブジェクトはApolloクライアントです。このコードはサーバーサイドで実行しているため fetchは使用できません。そこで、まず HttpLinkを手動で作成します。 node-fetchをブラウザ組み込みのフェッチの代わりに注入できるようにします。

ここでは InMemoryCacheオブジェクトを使いますが、本番環境ではこれをお好みのキャッシュ・ソリューションに置き換えることになるでしょう。

次に、以下のスニペットを apollo.jsファイルにコピーする。

const query = async (req, res) => {
  if (!req.body || !req.body.query) {
    res.sendStatus(500);
    return;
  }

  const query = gql(req.body.query);
  let variables = undefined;
  if (req.body.variables) {
    variables = JSON.parse(decodeURIComponent(req.body.variables));
  }

  try {
    const result = await client.query({
      query,
      variables
    });
    res.json(result);
  } catch (err) {
    console.log(err);
    res.sendStatus(500).send(JSON.stringify(err));
  }
};

const mutate = async (req, res) => {
  if (!req.body || !req.body.query) {
    res.sendStatus(500);
    return;
  }

  const query = gql(req.body.query);
  let variables = undefined;
  if (req.body.variables) {
    variables = JSON.parse(decodeURIComponent(req.body.variables));
  }

  try {
    const result = await client.mutate({
      query,
      variables
    });
    res.json(result);
  } catch (err) {
    console.log(err);
    res.sendStatus(500).send(JSON.stringify(err));
  }
};

これらの関数(queryとmutate)はリクエストを受け取り、ボディからquery/mutateと変数情報を取り出し、それらのパラメータを clientオブジェクトを使って転送します。

最後に apolloメソッドを作成し、後でExpressワークフローで使えるようにエクスポートします。この関数は、送られてきたリクエストを検査し、適切な(mutateまたはquery)関数に転送します。

const apollo = async (req, res, next) => {
  switch (req.method) {
    case "POST":
    case "PUT":
      await mutate(req, res);
      break;

    case "GET":
    default:
      await query(req, res);
  }

  next();
};


module.exports = apollo;

エクスプレス・レーンを利用する

ミドルマンができたので、それをExpressアプリケーションに接続してみよう。まず index.jsファイルを作成し、以下をコピーする:

const express = require("express");
const app = express();
const port = 3000;

const apollo = require("./apollo");

app.use(express.json());
app.use(apollo);

app.listen(port, () => console.log(`Example app listening on port ${port}!`));

このスニペットは、ExpressにJSONを使いたいことを伝え、リクエストのライフサイクルに私たちの apollo関数をリクエストのライフサイクルに挿入します。基本的に、このExpressアプリケーションへのすべてのリクエストは、ミドルマンによって処理されます。したがって、すべてのGraphQLクエリーと変異はサードパーティのエンドポイントに転送され、ローカルサーバーから選択したクライアントに返されます。

認証処理

上記の例では、サードパーティのエンドポイントで認証する必要がないシナリオを扱うことができますが、各リクエストでカスタムヘッダを送信する必要がある場合はどうなるでしょうか?例として、Vonage Video インサイト APIGraphQL エンドポイントを使用してみましょう。

Insights APIは、プロジェクトおよびセッションレベルでセッションメタデータを探索できるGraphQL APIです。リクエストには X-OPENTOK-AUTHのカスタムヘッダを JWT とともに含める必要があります。

前提条件

まず、Vonage Video Accountが必要です。まだお持ちでない場合は 無料で作成.

Vonage Video Accountで、'Projects' メニューをクリックし、'Create New Project' をクリックします。次に'Create Custom Project'ボタンをクリックします。新しいプロジェクトに名前を付け、'Create'ボタンを押してください。優先コーデックは'VP8'のままでかまいません。

Screenshot of the "project created" dialog within a Vonage Video accountProject Created

この画面のAPI KeyとSecretをコピーする。後で認証の設定に使います。

完全な体験をするには、Vonage Videoアカウントのデータが必要です。数分かけて ハロー・ワールド・クイック・スタートをご覧ください。

構成

という名前の新しいファイルを作成し config.jsという名前の新しいファイルを作成し、そこに以下のコードを貼り付ける。定数の値は、前回コピーしたAPI KeyとSecretに置き換えてください。

// Replace these values with those generated in your Vonage Video Account
const OPENTOK_API_KEY = "";
const OPENTOK_API_SECRET = "";

module.exports = { OPENTOK_API_KEY, OPENTOK_API_SECRET };

カスタムヘッダーの生成

次に、各リクエストのヘッダーに送信する有効なJWTを生成したい。そのためには、NPMパッケージを追加する必要がある。ターミナルから jsonwebtokenパッケージをインストールします。

npm install --save jsonwebtoken

次に auth.jsという新しいファイルを作成し、以下を貼り付ける:

const JWT = require("jsonwebtoken");
const SECRETS = require("./config");

var now = Math.round(new Date().getTime() / 1000);
var later = now + 120;
const payload = {
  iss: SECRETS.OPENTOK_API_KEY,
  ist: "project",
  iat: now,
  exp: later
};

const getHeaders = () => {
  const token = JWT.sign(payload, SECRETS.OPENTOK_API_SECRET);
  const headers = {
    "X-OPENTOK-AUTH": token
  };
  return headers;
};

module.exports = getHeaders;

このコードは、必要なパラメータを持つカスタムヘッダーオブジェクトを作成するメソッドをエクスポートします。 X-OPENTOK-AUTHパラメータと JWT トークンを付加したカスタムヘッダーオブジェクトを作成するメソッドをエクスポートします。

すべてをまとめる

ヘッダーを適切に生成できるようになったので、次はそれを使うために apollo.jsコードを更新する必要がある。ファイルを開き apollo.jsファイルを開き、以下のスニペットを追加する:

const getHeaders = require("./auth");

const authLink = setContext((_, { headers }) => {
  const authHeaders = getHeaders();
  // return the headers to the context so httpLink can read them
  return {
    headers: authHeaders
  };
});

次に client定数のコンストラクタを次のように置き換える:

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
});

クエリーを実行しよう

ターミナルで次のように実行すれば、アプリを起動できる。 node index.js.次に、GraphQLクエリーを http://localhost:3000.以下のクエリと変数を送信して、先ほど作成したセッションに関する情報を取得します。

クエリー

query ($PROJECT_ID: Int!, $START_TIME: Date!) {
    project(projectId: $PROJECT_ID) {
      projectData(
      start: $START_TIME,
      interval: AUTO,
      sdkType: [JS, IOS, ANDROID],
      groupBy: [SDK_TYPE]
          ) {
        resources {
          sdkType
          intervalStart
          intervalEnd
          usage {
            streamedPublishedMinutes
            streamedSubscribedMinutes
          }
        }
      }
    }
}

変数

{
    "PROJECT_ID": {OPENTOK API KEY},
    "START_TIME": "2020-01-01T08:00:00.000Z"
}

上記の {OPENTOK API KEY}を実際のAPI Keyに置き換えてください。

以下のような結果が表示されるはずだ。

{
    "data": {
        "project": {
            "projectData": {
                "resources": [
                    {
                        "sdkType": "JS",
                        "intervalStart": "2020-02-01T08:00:00.000Z",
                        "intervalEnd": "2020-02-29T08:00:00.000Z",
                        "usage": {
                            "streamedPublishedMinutes": 898.6833333333332,
                            "streamedSubscribedMinutes": 1121.0166666666664,
                            "__typename": "Usage"
                        },
                        "__typename": "Metric"
                    },
                    {
                        "sdkType": "JS",
                        "intervalStart": "2020-03-01T08:00:00.000Z",
                        "intervalEnd": "2020-03-08T08:00:00.000Z",
                        "usage": {
                            "streamedPublishedMinutes": 97.11666666666667,
                            "streamedSubscribedMinutes": 12.766666666666666,
                            "__typename": "Usage"
                        },
                        "__typename": "Metric"
                    }
                ],
                "__typename": "ProjectData"
            },
            "__typename": "Project"
        }
    },
    "loading": false,
    "networkStatus": 7,
    "stale": false
}

ぜひ Video APIエクスプローラ(Vonage Videoアカウントにログインする必要があります)で、Insights APIスキーマを確認し、利用可能なその他のデータについて学んでください。

シェア:

https://a.storyblok.com/f/270183/225x225/b0360f94ad/michaeljolley.png
Michael Jolleyヴォネージの卒業生

マイケルはハゲでヒゲのビルダー。ソフトウェア開発とDevOpsにおける20年の経験を生かし、他人の成功を助けることに集中する日々を送っている。