Archivo de la etiqueta: apis

Introducción a GraphQL, Queries y Mutations

Como algunos de ustedes sabrán llevo poco mas de 1 año trabajando con una startup (si, deje Oracle XD) cuyo stack esta conformado en su mayoría por tecnologías de Javascript (NodeJS, ReactJS, Redux, Apollo, GraphQL, React-native, etc). y en esta ocasión quiero compartir con ustedes el material de la platica que di en el GDLJS del mes de octubre en Guadalajara, se trata de una breve introducción a GraphQL y cual ha sido mi experiencia con esta tecnología.

¿Que es GraphQL?

Primero lo primero, GraphQL es un lenguaje de consultas para tu API creado por Facebook en 2012, es decir, es un intermediario comúnmente utilizado entre un cliente y algún orm de tu elección, es importante mencionar que GraphQL no se conecta directamente a tu base de datos, en lugar de eso ayuda a que el cliente defina el formato de la respuesta que desea obtener del servidor, mas adelante veremos algunos ejemplos.

¿Cual es la diferencia?

Ya existen bastantes frameworks para desarrollar apis ¿Por que quisiera usar GraphQL?

Bueno una de las principales diferencias con apis basadas en REST simple que tienen múltiples endpoints es que en tu api basada en GraphQL solo tendras uno.

Ademas de eso las apis comunes utilizan varios métodos HTTP (GET, POST, DELETE, PUT, OPTIONS, etc) según la operación que vayan a realizar, mientras que con GraphQL usaras solamente POST si así lo deseas, un endpoint para gobernarlos a todos 😉

Todo bien hasta aquí, pero no me haz dicho realmente cual es el beneficio de usar esta tecnología

Tranquilo pequeño saltamontes, consideremos el caso siguiente:

Del lado izquierdo tenemos un cliente que hace una petición GET a un endpoint de álbumes pasando un id para obtener sus assets, posteriormente por cada uno de esos assets solicita los comentarios (múltiples peticiones al servidor), adicionalmente los objetos JSON que reciba en las respuestas siempre tendrán los mismos atributos.

Del lado derecho vemos la petición POST equivalente para un endpoint basado en GraphQL, como podemos observar en el mismo payload de nuestra petición estamos indicando el formato de respuesta que queremos que el servidor nos regrese, atributos en los objetos, etc.

Habra quien diga que puede ingeniárselas para que la petición defina la respuesta del servidor, regresar atributos dinámicamente, etc. y le creo pero buena suerte manteniendo algo como esto 🙂

GET /albums/1/assets/comments/?include=asset.name,comment.author,comment.text

Este es precisamente el problema que GraphQL resuelve, GraphQL nos permite definir relaciones entre las entidades de nuestra aplicación e inyectar esos objetos relacionados en las respuestas cada vez que el cliente lo pida.

El siguiente ejemplo de código esta basado en Javascript utilizando expressJS, supongamos que el cliente necesita desplegar en su frontend un objeto como el siguiente:

Un objeto película con datos como su nombre, el año y la calificación de la critica, adicionalmente también queremos los datos de los actores involucrados y los comentarios de los visitantes que han visto esa pelicula.

Manos a la obra, vamos a iniciar un nuevo proyecto con NodeJS

$ npm init
$ npm install --save express express-graphql graphiql graphql

Adicionalmente me gusta definir algunos comandos e instalar algunas dependencias para tener soporte es6, aquí pueden ver como queda mi package.json al final.

La estructura del proyecto es mas o menos la siguiente (demo-server)

Los archivos y carpetas mas importantes son:

  • app.js es nuestro entry point
  • graphql es la carpeta donde guardaremos nuestros “objetos QL”
  • data es la carpeta donde tendremos algunos objetos de ejemplo que simulan registros de la base de datos

Vamos a comenzar con el objeto Movie (película), en la carpeta graphql creamos un nuevo archivo llamado movieQL.js

import {
  GraphQLObjectType,
  GraphQLInt,
  GraphQLString,
  GraphQLList,
  GraphQLBoolean,
  GraphQLNonNull,
  GraphQLFloat,
} from 'graphql';

import actorQL from './actorQL';
import commentQL from './commentQL';

const movieQL = new GraphQLObjectType({
  name: 'movieQL',
  description: 'This is a movie QL object',
  fields: () => {
    return {
      name: {
        type: GraphQLString,
        resolve(movie) {
          return movie.name;
        }
      },
      score: {
        type: GraphQLFloat,
        resolve(movie) {
          return movie.score;
        }
      },
      year: {
        type: GraphQLInt,
        resolve(movie) {
          return movie.year;
        }
      },
      actors: {
        type: new GraphQLList(actorQL),
        resolve(movie) {
          return movie.actors;
        }
      },
      comments: {
        type: new GraphQLList(commentQL),
        resolve(movie) {
          return movie.comments;
        }
      },
    }
  }
});

export default movieQL;

Como podemos observar al inicio estamos haciendo import de varios módulos que representan tipos de datos escalares en graphQL, adicionalmente hacemos import de otras 2 entidades de nuestra aplicación, actorQL.js y commentQL.js, después en el atributo fields de nuestro objeto movieQL definimos varios campos del mismo junto con su tipo y aqui viene lo mas importante, definimos actors como una lista de tipo actorQL y comments como una lista de tipo commentQL, el código de las otras entidades es bastante similar al de movieQL por lo que no lo pondre en el post, pueden revisarlo en el repositorio: actorQL.js y commentQL.js

Queries y mutations

Otro de los conceptos básicos en graphQL son las queries y las mutations, existe toda una teoría detrás pero en resumen:

  • Queries: nos permiten leer datos del servidor (por lo general extraídos de una db)
  • Mutations: Crear / modificar / borrar datos en el servidor

Dentro de la misma carpeta graphql vamos a crear 2 nuevos archivos, queryQL.js y mutationQL.js

import {
  GraphQLObjectType,
  GraphQLList,
  GraphQLString,
  GraphQLInt,
  GraphQLBoolean
} from 'graphql';

import movieQL from './movieQL';
import { movies } from '../data';

const query = new GraphQLObjectType({
    name: 'Query',
    description: 'This is the root Query',
    fields: () => {
      return Object.assign({
        getMovies: {
          type: new GraphQLList(movieQL),
          args: {},
          resolve(root, args, request) {
            // do some db queries
            return movies;
          }
        },
      });
    },
});

export default query;

Para efectos de que esto es un demo no estamos utilizando ningún orm para conectarnos a alguna base de datos, pero ustedes son libres de elegir e implementar el que mas le guste, de la misma forma que en movieQL.js definimos los fields aquí estamos definiendo nuestros “endpoints”, por ejemplo estamos diciendo que getMovies es una query que nos regresara una lista de movieQL y estamos haciendo return del objeto movies (que es un objeto de ejemplo que importamos de la carpeta data).

De la misma forma dentro de mutationQL.js declaramos una operación llamada createMovie que nos retornara un objeto tipo movieQL (después de haberlo creado), la parte importante aquí es que por lo general los mutations reciben argumentos (name, year, score, lista de actores, lista de comentarios) y de nuevo, para efectos de que esto es un demo no estamos haciendo nada con los datos que nos enviá el usuario, simplemente los regresamos en la respuesta.

import {
  GraphQLObjectType,
  GraphQLInt,
  GraphQLString,
  GraphQLNonNull,
  GraphQLList,
  GraphQLInputObjectType,
  GraphQLBoolean,
  GraphQLFloat,
} from 'graphql';

import movieQL from './movieQL';

const actorInputQL = new GraphQLInputObjectType({
  name: 'actorInputQL',
  fields: {
    name: { type: GraphQLString },
    age: { type: GraphQLInt },
    country: { type: GraphQLString },
  },
});

const commentInputQL = new GraphQLInputObjectType({
  name: 'commentInputQL',
  fields: {
    user: { type: GraphQLString },
    commentary: { type: GraphQLString },
    timestamp: { type: GraphQLString },
  },
});

const mutation = new GraphQLObjectType({
  name: 'Mutation',
  description: 'This is the root Mutation',
  fields: () => {
    return Object.assign({
      createMovie: {
        type: movieQL,
        args: {
          name: {
            type: new GraphQLNonNull(GraphQLString),
          },
          year: {
            type: GraphQLInt,
          },
          score: {
            type: GraphQLFloat,
          },
          actors: {
            type: new GraphQLList(actorInputQL),
          },
          comments: {
            type: new GraphQLList(commentInputQL),
          },
        },
        resolve(root, args, request) {
          // do something here
          return args;
        },
      },
    });
  },
});

export default mutation;

Hasta aquí ya tenemos definidos nuestros queries y mutations de ejemplo, ha llegado el momento de definir un schema de graphQL e integrar todo con express, es bastante sencillo, comenzamos creando un archivo llamado schemaQL.js también dentro de la carpeta graphql

import { GraphQLSchema } from 'graphql';
import queryQL from './queryQL';
import mutationQL from './mutationQL';

const schemaQL = new GraphQLSchema({
  query: queryQL,
  mutation: mutationQL,
});

export default schemaQL;

Como podemos ver, simplemente importamos los modulos de queryQL y mutationQL y finalmente en nuestro entry point (app.js) mandamos llamar a graphQL con el schema recién creado.

import express from 'express';
import GraphHTTP from 'express-graphql';
import schemaQL from './graphql/schemaQL';

var app = express();

app.use('/graphiql', GraphHTTP({
    schema: schemaQL,
    pretty: true,
    graphiql: true
}));

app.use('/graphql', GraphHTTP({
    schema: schemaQL
}));

app.get('/', function (req, res, next) {
  const reponse = {
    message: 'hello world',
  };
  return res.json(reponse);
});

module.exports = app;

Notaran que tenemos definidos 2 endpoints, graphql y graphiql. GraphiQL es una herramienta bastante útil que viene con el modulo de graphQL, se trata de una pequeña interfaz web desde donde podemos probar nuestras queries y mutations y la cual nos genera una documentación con base en los objetos QL de nuestro código, por ejemplo para probar nuestra query de getMovies seria algo como lo siguiente:

Observen que del lado izquierdo estoy definiendo los atributos que quiero que contengan los objetos de la respuesta, puedo solicitar mas o menos dependiendo de lo que el cliente pida, ayudando bastante a, por ejemplo, reducir el tamaño de los mensajes si la petición se hace desde un cliente móvil.

De la misma forma podemos probar nuestro mutation por medio de graphiQL

Observen como desde el cliente podemos pasar directamente el objeto con sus atributos, incluso los objetos relacionados como la lista de actores y comentarios, ya es cuestión de procesar todo eso en nuestro backend y crear los registros en la base de datos.

Todo bien hasta el momento, ya sabemos utilizar graphiQL, ahora como usamos nuestra api ya en un proyecto real, muy sencillo, cada vez que hacemos un request en google developer toolbar podemos observar cual es el payload que se enviá al servidor:

Podemos tomar ese mismo payload y con la ayuda de POSTMAN enviarlo como raw body a nuestro endpoint de graphQL en /graphql

Observa como el POST request va dirigido a /graphql y no /graphiql, por ultimo desde el mismo POSTMAN podemos ver cual seria el HTTP request generado haciendo clic en el boton code

Finalmente lo único que queda es implementar ese request en tu lenguaje de programación / framework favorito, a continuación dejo la presentación que utilice durante el evento por si necesitan revisarla asi como el repositorio de github donde esta alojado el código de este demo: graphql demo server

Mi experiencia durante MoreliaHacks 2015

Hola de nuevo lectores 🙂 como les comentaba en una publicación anterior, en noviembre estuve participando en el I/O Hack 2015 con un proyecto de agricultura y drones, me divertí bastante y aprendí muchas cosas nuevas, después de todo fue mi primer hackaton. Asistí al evento por varias razones, la primera es porque me gustan los retos, solucionar problemas de la vida real y creo que eventos de este tipo son los ideales, la segunda razon, y de lo que se trata este post, es que a mediados de octubre de este año me junte con un grupo de personas en Morelia para discutir una estrategia en la que pudieramos impulsar proyectos de datos y gobierno abierto en la ciudad, estuvimos investigando bastante, viendo que es lo que se hacía en otros lugares y al final decidimos que lo más adecuado era organizar un hackaton, debido a eso me fui al I/O Hack para aprender lo más que pudiera en cuanto a temas de logística, organización, programación del evento y todo eso 🙂

Planeando el evento

Como decía, todo comenzó con una plática en starbucks, juntas y más juntas donde definíamos una planeación, nuestro objetivo era impulsar el gobierno abierto en la ciudad y para hacerlo antes teníamos que demostrar el poder de las fuentes públicas de información (las redes sociales), en pocas palabras diseñamos un plan en donde pudiéramos obtener suficiente información para responder a preguntas como ¿Qué es lo que se está diciendo de Morelia?, ¿Cuáles son los principales problemas de la ciudad?, etc. todo por medio de la opinión publica de los ciudadanos.

Organizando el evento

Conforme el los días pasaban la fecha del evento se acercaba, y teníamos que tener listo cada detalle del evento, ahora, yo como mentor tecnológico me encargaba de las cosas técnicas: sitio web, registro de participantes, envió de correos y todas esas cuestiones, pero después entendí que un evento de esta magnitud requiere mucho más que eso, se tienen que conseguir todos los patrocinadores, la difusión del evento, protocolos (no protocolos de red xd sino mas bien sociales) de inauguración, comida, ruedas de prensa y muchísimas cosas más en donde no soy experto pero que gracias a que estaba involucrado en la organización pude ver muy de cerca, además los otros miembros organizadores sabían hacer bastante bien su trabajo 🙂

Bonus: durante este proceso tuve la oportunidad de dar varias entrevistas y aparecer en televisión XD.

12303938_10206490936287026_6276593269870553135_o

hack

Se realizó la convocatoria y de todos los aspirantes se eligió a los 40 mejores programadores, me di a la tarea de evaluar sus aptitudes no solo revisando su cv, investigue si habían hecho alguna aportación a proyectos de software libre, si tenían cosas interesantes en github, si pertenecían a alguna comunidad en línea, algún blog personal y cosas de ese estilo, yo estaba buscando ese espíritu hacker y no tanto expertis en un tema específico, me interesaban personas que si tenían un problema iban a buscar la manera de solucionarlo a como dé lugar, gente que estuviera dispuesta a aprender nuevas cosas y a enseñar lo que saben y me dio mucho gusto encontrar a varias personas con esas cualidades.

Primer día del evento

Llego el gran día, viernes 11 de diciembre, se presentó oficialmente el proyecto a la comunidad tecnológica, a los medios y al gobierno de la ciudad, se realizó otra pequeña rueda de prensa y se contestaron varias dudas de los participantes, durante la organización conocí a dos personas increíbles especializadas en manejo de datos abiertos de una empresa llamada Fractal, ellos dieron una plática en donde explicaban todo acerca del gobierno abierto.

12347767_448143095393425_6599439726446076015_n

Al final del primer día cerramos con una sesión de neworking en donde todos los participantes y los mentores interactuaron, aprovechamos para presentarnos, conocernos, hablar acerca de que es lo que hacía cada quien y prepararnos para el día siguiente.

Segundo día del evento

Durante el segundo día yo hable un poco acerca de tecnologías que nos podían ayudar a recopilar información de fuentes públicas, apis de redes sociales (facebook, twitter, youtube, etc) y algunas herramientas que ya existen en el mercado como socialsensor, después organizamos a los participantes mediante grupos que se encargarían de hacer distintas tareas como:

  • Extracción de datos de redes sociales
  • Visualización de datos
  • Crawling de sitios web
  • Datos abiertos
  • Procesamiento de lenguaje natural
  • Prevención del crimen
  • Movilidad

Y así comenzó el hackaton, durante 8 hrs seguidas los programadores trabajaron arduamente para lograr los objetivos asignados, fueron 8 hrs en donde estuve conociendo más de cerca a los participantes, resolviendo sus dudas y también aprendiendo acerca de las tecnologías que estaban usando y su experiencia con ellas 🙂

12359902_10206558445974726_8280400728719171982_n

12341556_448442548696813_6272023644551489969_n

12376532_448442682030133_4535409909592327811_n

Al final del evento cada equipo presento los avances que habían logrado, las herramientas que crearon y las soluciones que planearon, el equipo de visualización se encargó de crear un pequeño sitio web en donde se centralizaron todas las apis desarrolladas durante el evento http://api.moreliahacks.org/, muchas de estas apis continúan siendo desarrolladas por sus creadores.

Comentarios personales

Para concluir la publicación me gustaría terminar con algunos comentarios personales, ser parte de la organización de este evento sin duda me dejo bastantes cosas, yo por lo general siempre me he encargado del aspecto técnico de las cosas, tech guy, la persona que está detrás de la creación de plataformas y aplicaciones, siempre estuve cómodo y conforme con eso, sin embargo cuando te empiezas a involucrar en otros aspectos fuera de tu área, cosas tan básicas como ver qué tipo de comida tendrán los participantes, el color de las playeras que recibirán, la decoración del evento y después tener la oportunidad de tomar el micrófono para expresar tus ideas y tus pensamientos a las personas, eso es algo que de alguna forma te cambia y te hace crecer como persona, pienso yo.

Contribuir con la creación de una comunidad de hackers cívicos en mi ciudad y la organización del primer hackaton de la ciudad es una experiencia que nunca antes había tenido, como mencionaba al inicio de mi post ya había tenido la oportunidad de participar en un hackaton y esta vez me toco estar del otro lado, ser el mentor :).

Como en todos los eventos, y más por ser el primero, hay muchísimas oportunidades de mejora, personas con las que te encontraras que no comparten tus mismas opiniones e ideales pero con las que al final debes lidiar y convencer del por qué haces las cosas que haces, de lo que si estoy seguro es que la colaboración entre las personas es el futuro y al final es algo que nos beneficia a todos como sociedad.

Saludos.