El segundo de tres artículos centrados en la construcción Fullstack React y GraphQL con Express y Couchbase Server.
- Configuración de un servidor NoSQL Couchbase (Parte 1)
- Creación de una API Express-GraphQL (Parte 2)
- Crear un cliente Apollo GraphQL en React (Parte 3)
- Código fuente final
GraphQL con Express
Si no está familiarizado con GraphQL, tómese unos minutos para ponerse al día utilizando la documentación GraphQL. Las siguientes páginas deberían ser un buen comienzo:
Requisitos previos
Crear la estructura del proyecto
Necesitamos crear un directorio en tu máquina para nuestro proyecto, lo llamaremos rage-with-couchbase:
|
1 |
mkdir rage-with-couchbase && cd $_ |
mkdir creará un nuevo directorio utilizando la cadena rage-with-couchbase para el nombre de la carpeta, bash almacena esa cadena en una variable que podemos utilizar inmediatamente llamada $_.
cambiamos de directorio con $_ asegurándonos de no escribir mal el directorio en el comando concatenado (es magia de bash).
Ahora vamos a crear un .gitignore en la raíz de nuestro proyecto.
|
1 |
touch .gitignore && echo "/node_modules/*" >> .gitignore |
toque generará un .gitignore ignorando todos los node_modules en nuestro proyecto. Esto es importante porque como parte de nuestro proyecto de demostración fullstack React y GraphQL, estaremos rastreando cambios git desde la raíz rage-with-couchbase pero tendremos directorios de servidor y cliente con sus propios paquete.json y node_modules directorio.
echo añadirá el node_modules/ texto dentro del .gitignore esto servirá para ignorar todos los node_modules en la raíz y en todos los subdirectorios.
Creación de nuestro servidor Express
Ahora crearemos el directorio para almacenar nuestro servidor Express y usaremos npm para gestionar sus paquetes.
|
1 |
mkdir couchbase-gql-server && cd $_ && npm init -y |
mkdir creará una nueva carpeta dentro de la raíz del proyecto específicamente para nuestro servidor utilizando la cadena servidor couchbase-gql para el nombre, este es el directorio del proyecto de su servidor.
cambiamos de directorio y utilizamos $_ (más magia) y luego inicializamos un npm proyecto utilizando npm init -y aceptando los valores por defecto con el -y bandera.
Instalar dependencias de Express Server
|
1 |
npm install graphql express express-graphql couchbase && npm install nodemon -D && code . |
Una vez finalizada la instalación, tenemos que abrir nuestro proyecto con nuestro editor de elección. Yo prefiero VS Code.
Crear nuestro servidor GraphQL
|
1 |
touch server.js .gitignore && echo "/node_modules/*" >> .gitignore |
Requerir express/express-graphql/graphql en nuestro servidor.js file:
|
1 2 3 4 5 |
const express = require('express') const { graphqlHTTP } = require('express-graphql') const { buildSchema } = require('graphql') const couchbase = require('couchbase') |
Las tres primeras importaciones son necesarias para nuestro servidor GraphQL y la última importación es necesaria para conectar y consultar nuestro servidor Couchbase.
Inicializar Express y conectarse a nuestro cubo
Añade el siguiente código:
|
1 2 3 4 5 6 |
const app = express() const cluster = new couchbase.Cluster('couchbase://localhost', { username: 'Administrator', password: 'password' }) const bucket = cluster.bucket('travel-sample') var collection = bucket.defaultCollection(); |
Arriba estamos conectando a nuestro cluster de Couchbase Server, autenticando con nuestro usuario que configuramos, y abriendo nuestro viaje-muestra cubo. Nunca utilice nombres de usuario y contraseñas por defecto en aplicaciones de producción.
Crear nuestro esquema GraphQL
Añadiendo el siguiente código definiremos dos endpoints que permitirán a nuestro GraphQL Server acceder y recuperar datos de nuestros documentos dentro de nuestro bucket de Couchbase Server.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
const schema = buildSchema(` type Airline { id: Int, callsign: String, country: String, iata: String, icao: String, name: String, type: String } input AirlineInput { callsign: String, country: String, iata: String, icao: String, name: String, type: String } type Query { airlinesUK: [Airline], airlineByKey(id: Int!): Airline airlinesByRegion(region: String!): [Airline] } type Mutation { updateAirline(id: Int!, input: AirlineInput): Airline } |
En Consulta especifica qué Consultas GraphQL pueden ejecutar contra su propio gráfico de datos.
Tenemos dos puntos finales definidos por Consulta. Uno llamado "airlinesUK" y el otro "airlineByKey". En nuestra aplicación React, sólo utilizaremos el endpoint "airlinesUK". Hice el endpoint "airlineByKey" simplemente para mostrar un ejemplo de recuperación de un único documento Couchbase por clave. Esta operación no utiliza el lenguaje de consulta N1QL y por lo tanto no tiene ninguna sobrecarga adicional. Entender cuándo y dónde usar cada uno es importante desde la perspectiva de la construcción de la API, no querríamos usar una consulta N1QL para devolver un único documento que podemos obtener por clave.
En nuestro código GraphQL, tenemos un objeto de tipo Línea aérea. Este objeto modela la estructura del documento que se encuentra en nuestro Couchbase viaje-muestra donde el tipo es "aerolínea".
A continuación, tenemos un Endpoint llamado "compañías aéreasUK". Observe que el valor de retorno de este punto final es una matriz de Aerolíneas: [Aerolínea]. Esto significa que volveremos a recibir una lista de compañías aéreas.
También tenemos "airlineByKey"donde obtendremos un único archivo Línea aérea.
Si recuerda nuestras imágenes de Bucket anteriores, cada documento se define mediante una clave con un formato como el siguiente aerolínea_1234 donde 1234 es el id de la compañía aérea.

Mantendremos este id a la hora de utilizar el SDK de NodeJS para obtener nuestro airlineByKey utilizando un simple bucket.get() método.
Crear nuestra implementación de Resolver para cada punto final
Ahora, que hemos definido dos consultas en nuestra API GraphQL-Express utilizando nuestro esquema necesitamos una implementación en JavaScript para recuperar los datos.
Nuestra aplicación React que vamos a crear sólo necesitará el archivo N1QL consulta denominada compañías aéreasUK.
Pero quería mostrarte cómo consultar sin N1QL utilizando la API del SDK de NodeJS utilizando sólo una clave o extendiéndola para utilizar una región (US/UK, etc..), que es la airlineByKey y airlineByRegion aplicación.
Añada el siguiente código a nuestro servidor.js para nuestras consultas N1QL:
(En su código JS, asegúrese de escapar los backticks con barras invertidas)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// Define N1QL Queries const airlinesUkQuery = ` SELECT airline.* FROM `travel-sample` AS airline WHERE airline.type = 'airline' AND airline.country = 'United Kingdom' ` const airlinesByRegionQuery = ` SELECT airline.* FROM `travel-sample` AS airline WHERE airline.type = 'airline' AND airline.country = $REGION ` |
Añada el siguiente código a nuestro servidor.js para nuestros resolvedores GraphQL:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
const root = { airlinesUK: async () => { const result = await cluster.query(airlinesUkQuery) return result.rows }, /* query getAirlinesUK { airlinesUK { id name callsign country iata icao } } */ airlinesByRegion: async ({region}) => { const options = { parameters: { REGION: region } } const result = await cluster.query(airlinesByRegionQuery, options) return result.rows }, /* query getAirlinesByRegion($region: String!) { airlinesByRegion(region:$region) { id name callsign country iata icao } } { "region": "{{country}}" } */ airlineByKey: async ({id}) => { const result = await collection.get(`airline_${id}`) return result.value }, /* query getAirlineByKey($id: Int!) { airlineByKey(id:$id) { id name callsign country iata icao } } { "id": {{id}} } */ updateAirline: async ({id, input}) => { const result = await collection.get(`airline_${id}`) const newDocument = { ...result.content, callsign: input.callsign ? input.callsign : result.value.callsign, country: input.country ? input.country : result.value.country, iata: input.iata ? input.iata : result.value.iata, icao: input.icao ? input.icao : result.value.icao, name: input.name ? input.name : result.value.name, }; console.log(newDocument) await collection.upsert(`airline_${id}`, newDocument) return newDocument } /* mutation updateExistingAirline($id:Int!, $input:AirlineInput) { updateAirline(id:$id, input:$input){ callsign country iata } } { "id": 112, "input": { "callsign": "FLYSTAR", "country": "United Kingdom" } } */ } |
Nota: En la sentencia N1QL anterior, tendrá que escapar los puntos suspensivos en la línea FROM alrededor de con barras invertidas. El ejemplo de código de nuestro blog no muestra esas barras invertidas, pero están ahí y se encuentran en el archivo Código fuente finalviaje-muestra
Para entenderlo mejor, estamos utilizando dos métodos diferentes para consultar nuestro servidor Couchbase.
El primer método corresponde al compañías aéreasUK endpoint, este es su resolver. Necesitamos devolver una promesa y dentro confiar en bucket.querypara tomar una consulta N1QL predefinida que he desglosado línea por línea en la variable statement para facilitar la lectura. Poder ejecutar este tipo de consulta SQL es muy potente para una base de datos de documentos. Gran parte del SQL que conocemos se transfiere y esto es un gran alivio en comparación con otras bases de datos de documentos que tienen una nueva API y un lenguaje de consulta que tendrás que aprender.
El segundo método corresponde al compañías aéreasUK endpoint, este es su resolver. Necesitamos devolver una promesa y dentro confiar en cubo.get y en este caso, sólo estamos definiendo la clave de nuestro documento. Recuerde que una de las grandes cosas sobre el uso de un almacén de datos clave-valor es que podemos elegir fácilmente un solo documento con poca sobrecarga.
Cada uno de los métodos anteriores también comprueba si hay errores de consulta y los resuelve o los rechaza en función de un valor de resultado o error.
Creación de nuestro GraphQL con Express Server
Ahora que tenemos todo resuelto para nuestros puntos finales y consultas, todo lo que tenemos que hacer es utilice nuestro servidor Express y darle un puerto para ejecutar, vamos a hacer eso ahora.
Añade el siguiente código al final de nuestro servidor.js file:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/* The graphqlHTTP function accepts a schema, rootValue and graphiql among other options for configuring our GraphQL Server */ const serverPort = 4000 const serverUrl = '/graphql' app.use(serverUrl, graphqlHTTP({ schema: schema, rootValue: root, graphiql: true })) app.listen( serverPort, () => console.log(`GraphQL server running: https://localhost:${serverPort}${serverUrl}`) ) |
Si alguna vez has creado un servidor Express o Express-GraphQL, este código debería resultarte familiar.
En primer lugar, configuramos nuestro puerto y URL GraphQL.
A continuación, pasamos nuestro esquema GraphQL y sus resolvers y establecemos nuestro graphiql a true. (Esto nos dará un IDE para probar nuestras consultas GraphQL disponibles en localhost:4000/graphql.
Por último, escuchamos en el puerto 4000 y ponemos un mensaje en la consola para indicar que nuestro servidor se está ejecutando.
Vamos a ejecutar nuestro servidor, asegúrese de que su Couchbase:
|
1 |
node server |
Una vez que tenemos el servidor GraphQL en funcionamiento podemos probar la aplicación Compañías aéreasUK pegando el siguiente código en el panel de consultas de GraphQL IDE:
|
1 2 3 4 5 6 7 8 9 10 |
query getAirlinesUK{ airlinesUK { id name callsign country iata icao } } |
Como indica la consulta, recuperará todas las compañías aéreas con base en el Reino Unido:

A continuación, utilizaremos la función airlineByKey en este ejemplo, también tendremos que crear una variable de consulta y pegarla en el panel correspondiente:
|
1 2 3 4 5 6 7 8 9 10 |
query getAirlineByKey($id: Int!) { airlineByKey(id:$id){ id name callsign country iata icao } } |
|
1 2 3 |
{ "id": 112 } |
Y con eso en su lugar y podemos consultar de nuevo y recuperar un solo documento de la aerolínea por clave:

Con una configuración super sencilla de la API GraphQL, estamos listos para crear nuestra aplicación react que utilizará estos endpoints para una página maestro-detalle utilizando las aerolíneas del Reino Unido en un componente de lista y cuando hagamos clic en una aerolínea en particular, otro componente mostrará los detalles completos de la aerolínea en la parte derecha de la página.