
Compartir:
Michael es el constructor calvo y barbudo. Aprovechando sus 20 años de experiencia en desarrollo de software y DevOps, este desarrollador con problemas de folclore pasa sus días centrado en ayudar a los demás a tener éxito.
Uso de Apollo para consultar GraphQL desde Node.js
Tiempo de lectura: 6 minutos
Es una situación habitual: has creado un prototipo rápido, ha funcionado muy bien y ahora la dirección quiere que esté disponible para ayer. Tal vez estaba accediendo a un punto final GraphQL de terceros y ahora tiene prisa por lanzar algo. ¿Uno de tus obstáculos? Ese punto final no proporciona cabeceras CORS. Ya no puedes llamarlo directamente desde tu aplicación JavaScript frontend.
¿Necesitas crear una aplicación Express con rutas para cada conjunto de datos que necesites? De ninguna manera. En este tutorial, utilizaremos la aplicación Apollo dentro de una aplicación Node.js Express para proporcionar un intermediario a tu endpoint de terceros, sin necesidad de reescribir tus consultas y mutaciones GraphQL.
Además de Apollo, existen varias bibliotecas NPM, como lokka y express-graphqlque podríamos utilizar para abstraer nuestro endpoint de terceros. Cada una de estas librerías tiene sus pros y sus contras. Usaremos Apollo debido a su popularidad y al nivel de soporte que tiene como parte de la plataforma Apollo Data Graph Platform.
¿Quieres saltar hasta el final? Puedes encontrar todo el código fuente de este tutorial en GitHub.
Primeros pasos
En primer lugar, vamos a obtener todos nuestros archivos y dependencias en su lugar. Crea una carpeta llamada nodejs-apollo-client y ábrela en el terminal que prefieras.
Ahora ejecute npm init en tu terminal para inicializar NPM en el directorio. A continuación, ejecute el script de abajo para instalar las dependencias.
Construir un intermediario GraphQL
Cree un nuevo archivo llamado apollo.js. Este archivo contiene la verdadera "carne" de nuestra solución. Intermediará las solicitudes entre nuestra aplicación Express y el punto final GraphQL de terceros.
Empecemos copiando el siguiente fragmento en ese archivo.
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()
});El objeto client es un cliente Apollo. Debido a que estamos ejecutando este código en el lado del servidor, fetch no está disponible para nosotros. Así que empezaremos creando un HttpLink manualmente para poder inyectar node-fetch en lugar del browser fetch incorporado.
Para nuestros propósitos, utilizaremos el objeto InMemoryCache para manejar los datos de caché, pero en su solución de producción, es probable que desee reemplazar esto con cualquier solución de almacenamiento en caché que prefiera.
A continuación, copie el siguiente fragmento en el archivo apollo.js archivo.
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));
}
};
Estas funciones (query y mutate) toman una petición, extraen información de consulta/mutación y variables del cuerpo, y luego reenvían esos parámetros usando el objeto client objeto.
Por último, creamos un método apollo y lo exportamos para poder utilizarlo posteriormente en el flujo de trabajo Express. Esta función inspecciona la solicitud entrante y la reenvía a la función apropiada (mutate o 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;
Tome el carril exprés
Ahora que tenemos nuestro intermediario construido, vamos a conectarlo a una aplicación Express. Crea un archivo index.js y copia lo siguiente:
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}!`));Este snippet le dirá a Express que quiere usar JSON e insertará nuestra función apollo en el ciclo de vida de la petición. Esencialmente, cada petición a esta aplicación Express será ahora procesada por nuestro intermediario. Así que cada consulta GraphQL y mutación será reenviada al endpoint de terceros y devuelta desde su servidor local al cliente de su elección.
Autenticación
El ejemplo anterior puede manejar escenarios en los que no es necesario autenticarse con el punto final de terceros, pero ¿qué sucede cuando necesitamos enviar encabezados personalizados con cada solicitud? Como ejemplo, utilicemos la API de Vonage Video Insights API GraphQL.
La API Insights es una API GraphQL que permite explorar los metadatos de sesión a nivel de proyecto y de sesión. Requiere que las solicitudes incluyan un encabezado personalizado de X-OPENTOK-AUTH con un JWT.
Requisitos previos
Primero, necesitarás una cuenta de Vonage Video. Si aún no tienes una crea una gratis.
En tu cuenta de Vonage Video, haz clic en el menú "Proyectos" y "Crear nuevo proyecto". Luego haz clic en el botón 'Crear proyecto personalizado'. Dale un nombre a tu nuevo proyecto y presiona el botón 'Crear'. Puedes dejar el códec preferido como 'VP8'.
Project Created
Copie la Clave API y el Secreto en esta pantalla. Las usaremos más tarde para configurar nuestra autenticación.
Para disfrutar de la experiencia completa, necesitarás datos en tu cuenta de Vonage Video. Tómate unos minutos para recorrer el Inicio rápido de Hello World para crear una aplicación de video en tiempo real.
Configuración
Cree un nuevo archivo llamado config.js y pegue en él el siguiente código. Asegúrese de reemplazar los valores de las constantes con la Clave API y el Secreto que copió anteriormente.
// 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 }; Generación de cabeceras personalizadas
Ahora querrás generar un JWT válido para enviar en la cabecera de cada petición. Para ello, tendremos que añadir un paquete NPM. Desde tu terminal, instala el paquete jsonwebtoken paquete.
A continuación, crea un nuevo archivo llamado auth.js y pega lo siguiente:
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;
Este código exporta un método que creará nuestro objeto custom headers con el parámetro necesario X-OPENTOK-AUTH y el token JWT adjunto.
Puesta en común
Ahora que podemos generar cabeceras de forma apropiada, necesitaremos actualizar nuestro código apollo.js para utilizarlas. Abra el archivo apollo.js y añada el siguiente fragmento:
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
};
});
A continuación, sustituya el constructor de la constante client por el siguiente:
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache()
}); Hagamos una consulta
Ahora podemos iniciar la aplicación en el terminal ejecutando node index.js. A continuación, podemos enviar una consulta GraphQL a http://localhost:3000. Envía la siguiente consulta y variables para recuperar información sobre las sesiones que creaste anteriormente.
Consulta
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"
}Asegúrese de sustituir
{OPENTOK API KEY}por su clave de API real.
Debería obtener un resultado similar al que se muestra a continuación.
{
"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
}Asegúrese de consultar el Explorador de API de Video de Vonage (deberás iniciar sesión en tu cuenta de Vonage Video) para revisar el esquema de Insights API y conocer otros datos que están disponibles para ti.