
Partager:
Michael est le bâtisseur chauve et barbu. Fort de ses 20 ans d'expérience dans le développement de logiciels et DevOps, ce développeur aux prises avec des difficultés folliculaires passe ses journées à aider les autres à réussir.
Utiliser Apollo pour interroger GraphQL depuis Node.js
Temps de lecture : 6 minutes
C'est un scénario courant : vous avez construit un prototype rapide, qui a très bien fonctionné, et la direction veut qu'il soit mis en service dès aujourd'hui. Vous avez peut-être accédé à un point de terminaison GraphQL tiers et vous êtes maintenant pressé de sortir quelque chose. L'un de vos obstacles ? Ce point d'accès ne fournit pas d'en-têtes CORS. Il n'est plus possible de l'appeler directement depuis votre application JavaScript frontale.
Devez-vous créer une application Express avec des itinéraires pour chaque ensemble de données dont vous avez besoin ? Pas du tout ! Dans ce tutoriel, nous utiliserons l'application Apollo dans une application Express Node.js pour fournir un intermédiaire à votre point de terminaison tiers, sans avoir à réécrire vos requêtes GraphQL et vos mutations.
En plus d'Apollo, il existe plusieurs bibliothèques NPM, comme lokka et express-graphqlque nous pourrions utiliser pour abstraire notre point de terminaison tiers. Chacune de ces bibliothèques a ses avantages et ses inconvénients. Nous utiliserons Apollo en raison de sa popularité et du niveau de support dont elle bénéficie dans le cadre de la plateforme Apollo Data Graph Platform.
Vous voulez sauter à la fin ? Vous pouvez trouver tout le code source de ce tutoriel sur GitHub.
Pour commencer
Tout d'abord, mettons en place tous nos fichiers et dépendances. Créez un dossier appelé nodejs-apollo-client et ouvrez-le dans le terminal de votre choix.
Lancez maintenant npm init dans votre terminal pour initialiser NPM dans le répertoire. Ensuite, exécutez le script ci-dessous pour installer les dépendances.
Construire un intermédiaire GraphQL
Créer un nouveau fichier nommé apollo.js. Ce fichier contient la véritable "viande" de notre solution. Il sert d'intermédiaire pour les requêtes entre notre application Express et le point de terminaison GraphQL tiers.
Commençons par copier l'extrait suivant dans ce fichier.
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()
});L'objet client est un client Apollo. Parce que nous exécutons ce code côté serveur, fetch n'est pas disponible pour nous. Nous allons donc commencer par créer un objet HttpLink manuellement afin de pouvoir injecter node-fetch à la place de la récupération intégrée du navigateur.
Pour nos besoins, nous utiliserons l'objet InMemoryCache pour gérer la mise en cache des données, mais dans votre solution de production, vous voudrez probablement le remplacer par la solution de mise en cache de votre choix.
Ensuite, copiez l'extrait ci-dessous dans le fichier apollo.js dans le fichier
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));
}
};
Ces fonctions (requête et mutation) prennent une requête, extraient les informations relatives à la requête/mutation et aux variables du corps de la requête, puis transmettent ces paramètres à l'aide de l'objet client objet.
Enfin, nous créons une méthode apollo et nous l'exportons afin de pouvoir l'utiliser ultérieurement dans le flux de travail Express. Cette fonction inspecte la requête entrante et la transmet à la fonction appropriée (mutate ou 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;
Prendre la voie express
Maintenant que nous avons construit notre intermédiaire, nous allons l'intégrer dans une application Express. Créez un fichier index.js et copiez-y ce qui suit :
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}!`));Cet extrait indiquera à Express que vous souhaitez utiliser JSON et insérera notre fonction apollo dans le cycle de vie de la requête. Essentiellement, chaque demande adressée à cette application Express sera désormais traitée par notre intermédiaire. Ainsi, chaque requête et mutation GraphQL sera transmise au point de terminaison tiers et renvoyée de votre serveur local au client de votre choix.
Gestion de l'authentification
L'exemple ci-dessus permet de gérer des scénarios dans lesquels il n'est pas nécessaire de s'authentifier auprès du point de terminaison tiers, mais que se passe-t-il lorsque nous devons envoyer des en-têtes personnalisés avec chaque demande ? À titre d'exemple, utilisons l'API Vonage Video Insights API GraphQL de Vonage.
L'API Insights est une API GraphQL qui vous permet d'explorer les métadonnées de votre session au niveau du projet et de la session. Elle exige que les requêtes incluent un en-tête personnalisé de X-OPENTOK-AUTH avec un JWT.
Conditions préalables
Tout d'abord, vous aurez besoin d'un Video Account de Vonage. Si vous n'en avez pas déjà un, créez-en un gratuitement.
Dans votre Account Video de Vonage, cliquez sur le menu "Projets" et "Créer un nouveau projet". Cliquez ensuite sur le bouton "Créer un projet personnalisé". Donnez un nom à votre nouveau projet et appuyez sur le bouton "Créer". Vous pouvez laisser le codec préféré comme 'VP8'.
Project Created
Copiez la clé et le secret de l'API sur cet écran. Nous les utiliserons plus tard pour configurer notre authentification.
Pour profiter pleinement de l'expérience, vous aurez besoin de données dans votre compte Video de Vonage. Prenez quelques minutes pour parcourir le Démarrage rapide Hello World pour créer une application vidéo en temps réel.
Configuration
Créez un nouveau fichier appelé config.js et collez-y le code ci-dessous. Veillez à remplacer les valeurs des constantes par la clé et le secret de l'API que vous avez copiés précédemment.
// 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 }; Générer des en-têtes personnalisés
Vous devez maintenant générer un JWT valide à envoyer dans l'en-tête de chaque requête. Pour ce faire, nous devons ajouter un paquetage NPM. Depuis votre terminal, installez le paquetage jsonwebtoken paquetage.
Ensuite, créez un nouveau fichier appelé auth.js et collez ce qui suit :
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;
Ce code exporte une méthode qui créera notre objet d'en-tête personnalisé avec le paramètre X-OPENTOK-AUTH nécessaire et le jeton JWT attaché.
La mise en place de l'ensemble
Maintenant que nous pouvons générer des en-têtes de manière appropriée, nous devons mettre à jour notre code apollo.js pour les utiliser. Ouvrez le fichier apollo.js et ajoutez l'extrait suivant :
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
};
});
Ensuite, remplacez le constructeur de la constante client par le suivant :
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache()
}); Exécutons une requête
Nous pouvons maintenant démarrer l'application dans le terminal en lançant node index.js. Nous pouvons ensuite envoyer une requête GraphQL à http://localhost:3000. Envoyez la requête et les variables suivantes pour récupérer des informations sur les sessions que vous avez créées précédemment.
Demande de renseignements
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
}
}
}
}
} Variables
{
"PROJECT_ID": {OPENTOK API KEY},
"START_TIME": "2020-01-01T08:00:00.000Z"
}Veillez à remplacer le
{OPENTOK API KEY}par votre véritable clé API.
Vous devriez obtenir un résultat similaire à celui ci-dessous.
{
"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
}N'oubliez pas de consulter le site Vonage Video API Explorer (vous devez être connecté à votre Account Video) pour consulter le schéma de l'API Insights et découvrir d'autres données disponibles.