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

Verwendung von Apollo zur Abfrage von GraphQL aus Node.js

Zuletzt aktualisiert am November 3, 2020

Lesedauer: 6 Minuten

Das ist ein häufiges Szenario: Sie haben einen schnellen Prototyp erstellt, der großartig funktioniert hat, und jetzt will die Geschäftsleitung, dass er gestern live geht. Vielleicht haben Sie auf einen GraphQL-Endpunkt eines Drittanbieters zugegriffen, und jetzt haben Sie es eilig, etwas auf den Weg zu bringen. Einer Ihrer Stolpersteine? Dieser Endpunkt stellt keine CORS-Header zur Verfügung. Sie können ihn nicht mehr direkt von Ihrer JavaScript-Frontend-Anwendung aufrufen.

Müssen Sie für jeden Datensatz, den Sie benötigen, eine Express-App mit Routen erstellen? Keineswegs! In diesem Tutorial werden wir die Apollo Client-Bibliothek innerhalb einer Node.js Express-Applikation verwenden, um einen Vermittler zu Ihrem Endpunkt eines Drittanbieters bereitzustellen, ohne dass Sie Ihre GraphQL-Abfragen und -Mutationen neu schreiben müssen.

Zusätzlich zu Apollo gibt es mehrere NPM-Bibliotheken, wie lokka und express-graphqldie wir zur Abstraktion unseres Drittanbieter-Endpunkts verwenden können. Jede dieser Bibliotheken hat ihre Vor- und Nachteile. Wir verwenden Apollo aufgrund seiner Popularität und des Umfangs der Unterstützung, die es als Teil der Apollo Data Graph Plattform.

Möchten Sie zum Ende springen? Sie finden den gesamten Quellcode für dieses Tutorial auf GitHub.

Erste Schritte

Zuerst müssen wir alle Dateien und Abhängigkeiten an ihren Platz bringen. Erstellen Sie einen Ordner namens nodejs-apollo-client und öffnen Sie ihn im Terminal Ihrer Wahl.

Führen Sie nun npm init in Ihrem Terminal aus, um NPM in diesem Verzeichnis zu initialisieren. Führen Sie dann das folgende Skript aus, um die Abhängigkeiten zu installieren.

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

Erstellen Sie einen GraphQL-Mittelmann

Erstellen Sie eine neue Datei mit dem Namen apollo.js. Diese Datei enthält das eigentliche "Fleisch" unserer Lösung. Sie vermittelt Anfragen zwischen unserer Express-Anwendung und dem GraphQL-Endpunkt eines Drittanbieters.

Kopieren Sie zunächst den folgenden Ausschnitt in diese Datei.

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()
});

Das client Objekt ist ein Apollo-Client. Da wir diesen Code auf der Server-Seite ausführen, fetch ist für uns nicht verfügbar. Wir beginnen also mit der Erstellung eines HttpLink manuell erstellen, damit wir node-fetch anstelle des eingebauten Browserabrufs einfügen können.

Für unsere Zwecke werden wir das InMemoryCache Objekt für die Zwischenspeicherung von Daten, aber in Ihrer Produktionslösung werden Sie dies wahrscheinlich durch eine beliebige Zwischenspeicherlösung ersetzen wollen.

Als nächstes kopieren Sie den unten stehenden Ausschnitt in die Datei apollo.js Datei.

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));
  }
};

Diese Funktionen (Query und Mutate) nehmen eine Anfrage entgegen, ziehen Query/Mutate- und Variableninformationen aus dem Body und leiten diese Parameter dann mit dem client Objekt weiter.

Schließlich erstellen wir eine apollo Methode und exportieren sie, damit wir sie später im Express-Workflow verwenden können. Diese Funktion prüft die eingehende Anfrage und leitet sie an die entsprechende Funktion (mutate oder query) weiter.

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;

Nehmen Sie die Express-Spur

Nachdem wir nun unseren Vermittler erstellt haben, können wir ihn in eine Express-Anwendung einbinden. Erstellen Sie eine index.js Datei und kopieren Sie das Folgende hinein:

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}!`));

Dieses Snippet teilt Express mit, dass Sie JSON verwenden möchten und fügt unsere apollo Funktion in den Lebenszyklus der Anfrage ein. Im Wesentlichen wird nun jede Anfrage an diese Express-Anwendung von unserem Mittelsmann verarbeitet. Jede GraphQL-Abfrage und -Mutation wird also an den Endpunkt des Drittanbieters weitergeleitet und von Ihrem lokalen Server an den Client Ihrer Wahl zurückgegeben.

Handhabung der Authentifizierung

Das obige Beispiel kann mit Szenarien umgehen, in denen Sie sich nicht beim Endpunkt des Drittanbieters authentifizieren müssen, aber was passiert, wenn wir benutzerdefinierte Header mit jeder Anfrage senden müssen? Nehmen wir als Beispiel die Vonage Video Einblicke API GraphQL-Endpunkt.

Die Insights API ist eine GraphQL-API, mit der Sie Ihre Sitzungsmetadaten auf Projekt- und Sitzungsebene untersuchen können. Sie erfordert, dass Anfragen einen benutzerdefinierten Header von X-OPENTOK-AUTH mit einem JWT enthalten.

Voraussetzungen

Zunächst benötigen Sie einen Vonage Video Account. Wenn Sie noch keinen haben, erstellen Sie ein kostenloses Konto.

Klicken Sie in Ihrem Vonage Video Account auf das Menü "Projekte" und "Neues Projekt erstellen". Klicken Sie dann auf die Schaltfläche "Benutzerdefiniertes Projekt erstellen". Geben Sie Ihrem neuen Projekt einen Namen und klicken Sie auf die Schaltfläche "Erstellen". Sie können den bevorzugten Codec auf "VP8" setzen.

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

Kopieren Sie den API-Schlüssel und das Geheimnis auf diesem Bildschirm. Wir werden sie später verwenden, um unsere Authentifizierung zu konfigurieren.

Um den vollen Funktionsumfang nutzen zu können, benötigen Sie Daten in Ihrem Vonage Video Account. Nehmen Sie sich ein paar Minuten Zeit und gehen Sie durch den Hello World-Schnellstart um eine Echtzeit-Videoanwendung zu erstellen.

Konfiguration

Erstellen Sie eine neue Datei mit dem Namen config.js und fügen Sie den unten stehenden Code ein. Ersetzen Sie die Werte der Konstanten durch den API-Schlüssel und das Geheimnis, die Sie zuvor kopiert haben.

// 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 };

Benutzerdefinierte Kopfzeilen generieren

Nun müssen Sie ein gültiges JWT generieren, das in der Kopfzeile jeder Anfrage gesendet wird. Zu diesem Zweck müssen wir ein NPM-Paket hinzufügen. Installieren Sie von Ihrem Terminal aus das jsonwebtoken Paket.

npm install --save jsonwebtoken

Als nächstes erstellen Sie eine neue Datei namens auth.js und fügen Sie das Folgende ein:

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;

Dieser Code exportiert eine Methode, die unser benutzerdefiniertes Header-Objekt mit den erforderlichen X-OPENTOK-AUTH Parameter und angehängtem JWT-Token erstellt.

Alles zusammenfügen

Da wir nun in der Lage sind, die Kopfzeilen entsprechend zu generieren, müssen wir unseren apollo.js Code aktualisieren, um sie zu verwenden. Öffnen Sie die apollo.js Datei und fügen Sie das folgende Snippet hinzu:

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
  };
});

Als nächstes ersetzen Sie den Konstruktor für die Konstante client Konstante durch den folgenden:

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

Führen wir eine Abfrage durch

Wir können nun die Anwendung im Terminal starten, indem wir node index.js. Dann können wir eine GraphQL-Abfrage an http://localhost:3000. Senden Sie die folgende Abfrage und Variablen, um Informationen über die zuvor erstellten Sitzungen abzurufen.

Abfrage

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
          }
        }
      }
    }
}

Variablen

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

Ersetzen Sie bitte die {OPENTOK API KEY} durch Ihren tatsächlichen API-Schlüssel ersetzen.

Sie sollten ein ähnliches Ergebnis wie unten erhalten.

{
    "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
}

Schauen Sie sich unbedingt den Vonage Video API Explorer (Sie müssen in Ihrem Vonage Video Account eingeloggt sein), um das Insights API Schema zu überprüfen und mehr über andere Daten zu erfahren, die Ihnen zur Verfügung stehen.

Teilen Sie:

https://a.storyblok.com/f/270183/225x225/b0360f94ad/michaeljolley.png
Michael JolleyVonage Ehemalige

Michael ist der kahlköpfige, bärtige Baumeister. Mit seiner 20-jährigen Erfahrung in der Software-Entwicklung und DevOps verbringt er seine Tage damit, anderen zum Erfolg zu verhelfen.