Andres Bernal

Andres Bernal

Developer.

© 2019

MERN App

Grapql

En este art铆culo, explicare desde mi punto de vista GraphQL, Apollo-client y c贸mo implementar ambos en nuestra aplicaci贸n.

Que es GraphQL?

GraphQL es un poderoso lenguaje de consulta que permite comunicar datos entre el cliente y el servidor. Es un enfoque m谩s flexible y eficiente que REST.

Ciertamente, no necesitamos GraphQL en todas las situaciones para la comunicaci贸n de datos, pero en algunos escenarios graphql puede ser un enfoque muy optimizador. Por ejemplo, supongamos que necesitamos construir un sistema de gesti贸n de autom贸viles. En esta aplicaci贸n con fines de aprendizaje tenemos los siguientes casos posibles: 1) Un autom贸vil puede tener m煤ltiples propietarios. 2) Un propietario puede tener varios autos.

Teniendo en cuenta los casos anteriores, en el enfoque REST podemos tener 2 API paramount en nuestra pila:

=> Punto final para obtener un solo autom贸vil. API :: 鈥榙omainName / api / car /: id鈥 Respuesta :: 鈥榥ombre, modelo, empresa, ID de propietario

=> Punto final para obtener informaci贸n del propietario. API :: 鈥榙omainName / api / owner /: id鈥 Respuesta :: 鈥榥ombre, edad, g茅nero, carIds

Imaginemos lo que sucede si necesitamos informaci贸n de un solo autom贸vil con detalles del Propietario y otros autom贸viles de su propiedad. En este caso, debemos realizar muchos golpes de API seg煤n el n煤mero de autom贸viles que pose铆a. Podr铆amos quedar atrapados en problemas de rendimiento si nuestra aplicaci贸n tiene una gran base de clientes. Para manejar este problema en gran medida, tenemos un mejor enfoque para este tipo de escenarios. Podemos usar graphql aqu铆.

Un enfoque GraphQL para este tipo de escenarios puede ser:


{
   car(id:3){
    name
    model
    company
    Owner {
      name
      age
      cars{
        name
        company
      }
    }
   }

   //or
   car(id:3){
     name
     Owner{
       name
       gender
     }
   }
}

Toda esta informaci贸n se recopilar谩 presionando una sola API solo una vez. Ese es el poder de graphql. Entonces empecemos.

project

IMPLEMENTACION DEL LADO DEL SERVIDOR

En primer lugar, debe descargar la 煤ltima versi贸n de NODE en su sistema. Despu茅s de instalarlo. Puede usar el editor VSCode ATOM para el desarrollo. Es gratis.

Anbra la terminal en VScode 
  1) crear carpeta MERNAPP
  2) cd MERNAPP
  3) crear folder server
  4) Hit "npm init" en la terminal de comandos.
  5) Presione "Enter" hasta que termine de preguntar

  //despues de crear package.json, Instale los siguientes package.

  6) npm install express express-graphql graphql lodash mongoose cors --save

  //el package.json se mostrara asi:

  //package.json
  {
  "name": "server",
  "version": "1.0.0",
  "description": "Server with Graphql & mongodb",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "vinod Chauhan",
  "license": "ISC",
  "dependencies": {
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "express-graphql": "^0.9.0",
    "graphql": "^14.5.4",
    "lodash": "^4.17.15",
    "mongoose": "^5.6.13"
  }
}

Mas adelante explicare el uso de cada paquete

Configuremos Express

En VS Editor en la carpeta 鈥榮erver鈥 , crear un nuevo archivo 鈥榓pp.js鈥.

 
const express = require("express");

const app = express();

app.listen(4000, () => {
  console.log("Server is listening on port 4000");
});

Para ejecutar esta app.js, primero descargue 鈥榥odemon鈥 en su sistema de manera global para que no necesite iniciar / detener la aplicaci贸n una y otra vez para ver los cambios.

 //Instale nodemon package
   npm install nodemon -g

   //Corra su app.js con nodemon
   nodemon app.js
   [nodemon] 1.19.1
   [nodemon] to restart at any time, enter `rs`
   [nodemon] watching: *.*
   [nodemon] starting `node app.js`
   Server is listening on port 4000

Abre tu favorito. navegador y entrada localhost: 4000, mostrar谩 una p谩gina en blanco a partir de ahora.

Si ha completado hasta este punto, configuraremos graphql en express en nuestro siguiente paso

Setup GraphQL en Express app

Nuestro servidor 鈥榚xpress-graphql鈥 ayudar谩 al servidor express a comprender sobre graphql y nos permitir谩 hacer nuestro trabajo.

//Obtenga la biblioteca express de node_modules que acabamos de descargar.
   const express = require("express");

   const graphqlHTTP = require("express-graphql");

   //Hacer const de express () en una variable (funci贸n JS objeto de primera clase).
   const app = express();

   /*Podemos usar graphql en el servidor express con middlewares, para que siempre necesitamos una consulta graphql de la interfaz, nuestro servidor express puede manejarla
   suavemente.
    
   El m茅todo graphqlHTTP nos permite hacer lo que queremos hacer si hemos capturado
    Middleware '/ graphql'.
   */
   app.use("/graphql", graphqlHTTP({}));

   //Cuando se inicie nuestra aplicaci贸n, escuchar谩 en el puerto 4000
   app.listen(4000, () => {
    console.log("Server is listening on port 4000");
   });

En el tipo de navegador: localhost: 4000 / graphql Al ejecutar app.js, actualmente nos dar谩 un error que dice:

{鈥渆rrors鈥:[{鈥渕essage鈥:鈥滸raphQL middleware options must contain a schema.鈥潁]}

No se preocupe, nuestro pr贸ximo paso es solo configurar el esquema Graphql.

Configurando GraphQL Schema

En la carpeta del servidor, cree la carpeta 鈥榮cheme鈥 y cree 鈥榮chema.js鈥 en ella. El archivo de esquema tiene principalmente 3 responsabilidades principales que hacer.

1) Crear tipos a partir del objeto 鈥楪raphQLObjectType鈥. 2) Definir relaci贸n entre tipos. 3) Defina 鈥楻ootQueries鈥 para permitir que el usuario ingrese al gr谩fico y use datos.

Como el archivo schema.js tiene el rol principal al final del servidor, as铆 lo completaremos gradualmente paso a paso.

/// schema.js

const graphql = require("graphql"); //use el paquete graphql

/*
Obteniendo la funci贸n GraphQLObjectType de 'graphql' para definir el (dataType)
estructura de nuestras consultas y su tipo de modelo.
*/
const {
  GraphQLObjectType,
  GraphQLID,
  GraphQLString,
  GraphQLInt,
  GraphQLSchema
} = graphql;

//Definiendo CarType con sus campos.
const CarType = new GraphQLObjectType({
  name: "Car",
  fields: () => ({
    id: { type: GraphQLID },
    name: { type: GraphQLString },
    model: { type: GraphQLInt },
    company: { type: GraphQLString }
  })
});

//Definiendo RootQuery
const RootQuery = new GraphQLObjectType({
  name: "RootQueryType",
  fields: {
    // Los campos aqu铆 ser谩n la consulta de las interfaces.
    //Estamos definiendo una consulta 'auto' que puede tomar (ID de auto) para buscar en DB.
    car: {
      type: CarType, //Definir modelo para consulta de coche
      args: { id: { type: GraphQLID } },  //el campo args para extraer el argumento vino con la consulta del autom贸vil, por ejemplo: Id del objeto del autom贸vil para extraer sus detalles.
      resolve(parent, args) {
        //c贸digo para obtener valor de DB
      } //resuelve la funcion
    } //la consulta del auto termina aqu铆
  } //campos terminan aqui
});

//exportando 'GraphQLSchema con RootQuery' para el middleware GraphqlHTTP.
module.exports = new GraphQLSchema({
  query: RootQuery
});


En el archivo anterior schema.js, hemos realizado los siguientes pasos:

1) Se import贸 鈥榞raphql鈥 para usar graphql en el servidor express.

2) Tome diferentes objetos, tipos de datos de la biblioteca graphql.

3) Crear un tipo 鈥楥arType鈥 constante con sus campos () desde GraphQLObjectType ().

4) Crear rootQuery 鈥楻ootQuery鈥 con la consulta de punto final 鈥榗ar鈥 para la funci贸n GraphQLSchema.

5) Exportar todo lo anterior como GraphQLSchema con 鈥楻ootQuery鈥 como argumento en 茅l.

Cambios en App.js

 
const express = require("express");

const graphqlHTTP = require("express-graphql");


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

const app = express();

/*Podemos usar graphql en el servidor express con middlewares, para que siempre
    necesitamos una consulta graphql de la interfaz, nuestro servidor express puede manejarla
    facil.
*/
app.use(
  "/graphql",
  graphqlHTTP({
    schema: schema
  })
);

app.listen(4000, () => {
  console.log("Server is listening on port 4000");
});

Hasta ahora, nuestra salida en el navegador ha cambiado pero a alg煤n otro error.

  {"errors":[{"message":"Must provide query string."}]}

//Dont worry guys we will remove this error too.

Resolver Funciones

En primer lugar, obtengamos datos ficticios para que nuestra consulta funcione por ahora.

Poner el siguiente c贸digo en el archivo schema.js

const graphql = require("graphql"); 

const _ = require("lodash");


const {
  GraphQLObjectType,
  GraphQLID,
  GraphQLString,
  GraphQLInt,
  GraphQLSchema
} = graphql;

const CarsArray = [
  { id: "1", name: "S-Class", model: "2019", company: "Mercedes" },
  { id: "2", name: "Continental GT", model: "2019", company: "Bentley" },
  { id: "3", name: "Phantom", model: "2019", company: "Rolls-Royce" },
  { id: "4", name: "Panamera", model: "2019", company: "Porsche" },
  { id: "5", name: "A8", model: "2019", company: "Audi" },
  { id: "6", name: "I-Pace", model: "2019", company: "Jaguar" }
];

//Definiendo CarType con sus campos.
const CarType = new GraphQLObjectType({
  name: "Car",
  fields: () => ({
    id: { type: GraphQLID },
    name: { type: GraphQLString },
    model: { type: GraphQLInt },
    company: { type: GraphQLString }
  })
});

//Definiendo RootQuery
const RootQuery = new GraphQLObjectType({
  name: "RootQueryType",
  fields: {
    // Los campos aqu铆 ser谩n la consulta de las interfaces.
    //Estamos definiendo una consulta 'auto' que puede tomar (ID de auto) para buscar en DB.
    car: {
      type: CarType, //Definir modelo para consulta de coche
      args: { id: { type: GraphQLID } },
//el campo args para extraer el argumento vino con la consulta del autom贸vil, por ejemplo: Id del objeto del autom贸vil para extraer sus detalles.
      resolve(parent, args) {
        //c贸digo para obtener valor de DB
        /**
         * Con la ayuda de la biblioteca lodash (_), estamos tratando de encontrar un autom贸vil con identificaci贸n de 'CarsArray'
         * y devolver sus datos requeridos a la herramienta de llamada.
         */
        return _.find(CarsArray, { id: args.id });
      } //resolvemos function
    } //car query termina aqui
  } //campos termina aqui
});

//exportando 'GraphQLSchema con RootQuery' para el middleware GraphqlHTTP.
module.exports = new GraphQLSchema({
  query: RootQuery
});


Debajo de los pasos que hemos hecho en schema.js: 1) Importar biblioteca 鈥榣odash鈥 para facilitar nuestra vida. 2) Dummy 鈥楥arsArray鈥 con los detalles necesarios. 3) Definici贸n de la funci贸n 鈥榬esolver鈥 de la consulta 鈥榓uto鈥.

Testiando nuestra consultas

Para probar nuestra consulta primero, necesitamos hacer un peque帽o cambio en nuestro archivo app.js.

app.use(
  "/graphql",
  graphqlHTTP({
    schema: schema,
    graphiql: true
  })
);

Al agregar 鈥榞raphiql: true鈥, habilitamos una herramienta incre铆ble incorporada para probar nuestras consultas. Ahora abierto: localhost: 4000 / graphql

graphql

En el lado izquierdo de la ventana, como se puede ver en la imagen de arriba, escriba una consulta con los detalles que desee dando la identificaci贸n del objeto del autom贸vil.

Defininendo OwnerType :

En schema.js, escriba el siguiente c贸digo.

const graphql = require("graphql"); 
const _ = require("lodash");

const {
  GraphQLObjectType,
  GraphQLID,
  GraphQLString,
  GraphQLInt,
  GraphQLSchema
} = graphql;

const CarsArray = [
  { id: "1", name: "S-Class", model: "2019", company: "Mercedes" },
  { id: "2", name: "Continental GT", model: "2019", company: "Bentley" },
  { id: "3", name: "Phantom", model: "2019", company: "Rolls-Royce" },
  { id: "4", name: "Panamera", model: "2019", company: "Porsche" },
  { id: "5", name: "A8", model: "2019", company: "Audi" },
  { id: "6", name: "I-Pace", model: "2019", company: "Jaguar" }
];

var OwnersArray = [
  { id: "1", name: "Vinod Chauhan", age: 27, gender: "male" },
  { id: "2", name: "John Dow", age: 46, gender: "male" },
  { id: "3", name: "Kristen", age: 30, gender: "female" },
  { id: "4", name: "Paris", age: 44, gender: "female" },
  { id: "5", name: "Sylvestor", age: 26, gender: "male" }
];

//Definiendo CarType con sus campos.
const CarType = new GraphQLObjectType({
  name: "Car",
  fields: () => ({
    id: { type: GraphQLID },
    name: { type: GraphQLString },
    model: { type: GraphQLInt },
    company: { type: GraphQLString }
  })
});

//Definiendo CarType con sus campos.
const OwnerType = new GraphQLObjectType({
  name: "Owner",
  fields: () => ({
    id: { type: GraphQLID },
    name: { type: GraphQLString },
    age: { type: GraphQLInt },
    gender: { type: GraphQLString }
  })
});

//Definiendo RootQuery
const RootQuery = new GraphQLObjectType({
  name: "RootQueryType",
  fields: {
    // Los campos aqu铆 ser谩n la consulta de las interfaces.
    //Estamos definiendo una consulta 'auto' que puede tomar(car ID ) to search in DB.
    car: {
      type: CarType, //Definir modelo para consulta de coche
      args: { id: { type: GraphQLID } }, //campo de args para extraer
      // El argumento vino con la consulta del autom贸vil, por ejemplo: Id del objeto del autom贸vil para extraer sus detalles.
      resolve(parent, args) {
        //c贸digo para obtener valor de DB
        /**
         * Con la ayuda de la biblioteca lodash (_), estamos tratando de encontrar un autom贸vil con identificaci贸n de 'CarsArray'
         * y devolver sus datos requeridos a la herramienta de llamada.
         */
        return _.find(CarsArray, { id: args.id });
      } //resolver function
    }, //car query termina aqui
    owner: {
      type: OwnerType,
      args: { id: { type: GraphQLID } },
      resolve(parent, args) {
        return _.find(OwnersArray, { id: args.id });
      }
    }
  } //fields termina aqui
});


module.exports = new GraphQLSchema({
  query: RootQuery
});

En Actualizar navegador o escribir localhost: 4000 / graphql, busque la consulta del propietario.

graphql2