Archivo de la etiqueta: Javascript

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

Código de 50% de descuento para #cpartymx4!

Hola amigos en esta ocasión les traigo un código de 50% de descuento para todos los usuarios de las comunidades afiliadas a Campus Party! El código es:

cpmx4comunidadesmayo

¿Como activo el código?

Accede a tu cuenta de campusparty, si aun no estas registrado corre y registrate

Captura de pantalla 2013-05-09 a la(s) 13.08.36

Una vez dentro de tu cuenta, accede a comprar tu entrada

Captura de pantalla 2013-05-09 a la(s) 13.13.51

Te aparecerá un botón con la leyenda “Comprar con descuento” haz clic en el

Captura de pantalla 2013-05-09 a la(s) 13.16.06

Por ultimo introduce el código de 50% de descuento para asistir a campusparty México

cpmx4comunidadesmayo

Captura de pantalla 2013-05-09 a la(s) 13.18.15

De manera paralela, Campus Party ha habilitado un micrositio para regalar pases gratis en en la siguiente dirección

salu2

@Chopapp para compartir código fuente

Después de un largo descanso …. Chop es una curiosa herramienta desarrollada por ZURB que te permite compartir snippets (trozos de código fuente) y recibir retro alimentación, si quieren saber por que esta app es bastante interesante les recomiendo seguir leyendo :).

chop

La idea es bastante simple y divertida, en el caso de querer mostrar nuestro codigo a alguna otra persona (similar a otros servicios como copypastecode o pastebin) y recibir algun tipo de retroalimentación tan solo tenemos que copiarlo en el formulario, elegir el lenguaje de programación adecuado y usar el botón de Chop It!, ejemplo:

chop_example1

Una vez hecho esto la aplicación nos pedirá un nombre de usuario y a continuación nos dará un link con el cual nuestros amigos podrán ver y opinar sobre nuestro código :), lo mas interesante de esta aplicación a diferencia de muchas otras que existen en el mercado es que nos permite realizar comentarios sobre el código línea por línea y no un comentario general, desde mi punto de vista es una forma bastante interesante de innovar y mejorar respecto a servicios ya existentes. El resultado final es algo como esto:

chop_example_2

Si quieren mantenerse informados sobre el desarrollo de esta aplicación pueden seguir a @chopapp

Tutorial Bing Search API 2.0 y PHP

Ha inicios del mes de agosto la gente de Microsoft mejoro (por no decir que modifico) la forma en que los desarrolladores interactuaban con la api, mejor conocida como bing api 2.0 ahora. Esto lógicamente causo bastantes problemas a las empresas y programadores independientes que no realizaron adoptaron los cambios en sus aplicaciones rápidamente, la mayor novedad que nos presenta ahora la api es que trabaja directamente con Windows Azure Marketplace.

Muchas personas pensaran que modificar sus aplicaciones para que vuelvan a funcionar va a ser una tarea muy tediosa, pero de hecho es bastante sencillo, a continuación he escrito una serie de pasos que te permitirá migrar una aplicación a bing api 2.0, mas concretamente utilizaremos la Bing search api 2.0

  • Registrarte en el Windows Azure Marketplace (usando tu cuenta de hotmail es suficiente)
  • Una vez registrado puedes acceder a la sección de datos del marketplace donde además de Bing Search Api (que es el servicio que utilizaremos en este tutorial) también podrás hacer uso de otros servicios como Microsoft Translator, etc. Lista de servicios de Bing

  • Al hacer clic en el servicio serás enviado a una vista donde se proporciona mas información acerca de la api así como una lista de precios por utilizar la api mensualmente, si crees que tu aplicación no tendrá mas de 5000 peticiones por mes a la api podrías utilizar el paquete gratuito al servicio (el ultimo precio que se muestra) de lo contrario te recomiendo adquirir algún otro paquete con las transacciones por mes que mas se ajusten a tus necesidades
  • Una vez suscrito al paquete de tu preferencia (hacer clic, aceptar términos, etc, etc.) en la sección de claves de cuenta podrás encontrar la key necesaria para poder conectarte al servicio y empezar a hacer uso de el. Así mismo en la sección de Mis datos encontraras un resumen de las aplicaciones que estas utilizando actualmente y el estado del numero de consultas restantes por mes, etc.

Listo eso es todo lo que tienes que configurar para comenzar a hacer uso de la api de bing :), ahora para no dejar el articulo a medias les dejo un pequeño código en PHP que nos regresa los resultados encontrados de la query que le pasemos a la api.

<?php

  $api = 'https://api.datamarket.azure.com/Data.ashx/Bing/Search/v1/Web?$format=json&$top=8&Query=';
  $accountKey = "LA KEY QUE APARECE EN LA SECCION DE CLAVES DE CUENTA";
  $context = stream_context_create(array(
    'http' => array(
        'request_fulluri' => true,
        'header'  => "Authorization: Basic " . base64_encode($accountKey . ":" . $accountKey)
    )
  ));

  $query = 'alevsk';
  $request = $api . '%27'.$query.'%27';

  $jsonResponse =  json_decode(file_get_contents($request, 0, $context));
  print_r($jsonResponse);
  
?>

El código es bastante sencillo pero creo que deja bastante claro cuales son los requerimientos mínimos para interactuar con la api como la autentificación, los sources y el formato de respuesta, si tienes mas dudas acerca de los parámetros que recibe la api puedes utilizar el generador de consultas que proporciona el sitio o también acceder a el utilizando el enlace de “Usar” (el que esta a la derecha en la imagen anterior).

El generador de consultas de bing api 2.0 se trata de una herramienta bastante útil ya que te permite configurar tus request de una manera muy amigable y al final en la parte superior te muestra como quedaría la petición (la URL) que deberías de hacer a la api para obtener los resultados mostrados abajo :).

Muy importante, aquí les dejo la documentacion completa de la api que podrán utilizar como referencia.

Con esto espero que haya quedado claro o por lo menos entendible la nueva manera de interactuar con la api de bing y como siempre digo, si hay dudas respecto al código pueden escribirlas en los comentarios y con gusto las resolveré.

salu2

SelectBox dependientes – ciudades y estados

Retomando los post sobre programación web en esta ocasión les comparto un rápido ejemplo sobre selectbox dependientes, mas concretamente el ejemplo de selectbox de ciudades y estados. Básicamente tenemos 2 selectbox, el primero contendrá los estados de la republica mexicana, cuando seleccionamos alguno el segundo selectbox contendrá ahora las ciudades de ese estado, para hacer esto necesitamos una pequeña base de datos con 2 tablas (ciudades y estados .. obvio), después algo de código php que se encargue de hacer la conexión y otro mas que nos devuelva los datos de las consultas vía JSON y por ultimo nuestro html y javascript que se encargara de mostrar el resultado.

Al terminar el tutorial tendremos algo que se vera así 🙂

Puedes descargar los archivos que se utilizara en la practica a continuación.

Comenzamos pues :).

Comenzamos creando el archivo que hará la conexión a la base de datos, yo acostumbro hacer una clase para eso ya que luego puedo hacer extends de la misma y todo es mas fácil.

<?
  global $ID_BD;
  $ID_BD=mysql_connect("127.0.0.1", "root","");
  mysql_select_db("states_cities", $ID_BD);
  mysql_query("SET NAMES 'utf8'", $ID_BD);  

class mysql {
VAR $ID;
function mysql (){

}
  function _query($sql){

  global $ID_BD;
   

    //echo "$sql\n";
      return mysql_query($sql,$ID_BD);
  }
  
  function _registers($sql){
  
  global $ID_BD;
    [email protected]_query($sql, $ID_BD);
    
    //echo $result;
    //echo $sql;
    if ($row=mysql_fetch_object($result)){
        do{
        
        $registros[]= $row;
        
        }while($row=mysql_fetch_object($result));
    }
    else
      return array();
    return $registros;
  }
  
  function _register ($sql){

  global $ID_BD;
    //echo "$sql";
      $result=mysql_query($sql, $ID_BD);
      if ($row=mysql_fetch_object($result))
        return  $row;
  }
  
  function _close(){
    mysql_close($this->ID);
  }
  
  function _last_id(){
    global $ID_BD;
      return  mysql_insert_id($ID_BD);
  }
}  

?>

Después creamos el archivo que se encargara de hacer las consultas y regresar el JSON correspondiente, realizaremos peticiones a este archivo via ajax por medio de jquery.

<?php
require_once 'mysql.php';

class data extends mysql
{
  function getStates()
  {
    $states = $this->_registers("SELECT * FROM states;");
    return json_encode($states);
  }

  function getCities($idState)
  {
    $idState = (int) $idState;
    $cities = $this->_registers("SELECT * FROM cities WHERE id_state = " . $idState . ";");
    return json_encode($cities);
  }
}

  $data = new data();
  if($_GET['action'] == "getStates")
  {
    echo $data->getStates();
  }
  else if($_GET['action'] == "getCities" && isset($_GET['stateID']))
  {
    echo $data->getCities($_GET['stateID']);
  }

?>

Como podemos ver he empaquetado el código en una clase y casi en la parte final del código reviso si existen algunos parámetros pasados por GET para mandar llamar a las funciones correspondientes :), examinemos por ejemplo la función que nos trae los estados:

  function getStates()
  {
    $states = $this->_registers("SELECT * FROM states;");
    return json_encode($states);
  }

Básicamente hacemos un select y el arreglo asociativo resultante (checar la clase mysql para mas información) lo pasamos por json_encode para ser manipulado con javascript, lo mismo pasa con la función que te arroja las ciudades solo que esa tiene una clausula WHERE que te manda traer solo las ciudades de X estado :).

Finalmente creamos nuestro archivo html donde desplegaremos los 2 selectbox, para eso escribimos el siguiente código.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <title>SelectBox dependientes</title>
    <script type="text/JavaScript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
    <script language="JavaScript">

    Object.size = function(obj) {
      var size = 0, key;
      for (key in obj) {
          if (obj.hasOwnProperty(key)) size++;
      }
      return size;
    };
    $(document).ready(function() {

      //$.ajax({
      $.ajax({
        url: 'data.php?action=getStates',
        dataType: 'json',
        success: function(data) {
          var size = Object.size(data);
          var items = "";
          for(var i = 0; i < size; i++)
          {
            items = items + '<option value="' + data[i].id_state + '">' + data[i].name + '</option>';
            //console.log(data[i].id_state + " : " + data[i].name);
          }  
          $('#states').append(items);
          $('#states').change();
        }
      });

     $('#states').change(function() {
      $.ajax({
        url: 'data.php?action=getCities&stateID=' + $('#states').val(),
        dataType: 'json',
        success: function(data) {
          var size = Object.size(data);
          var items = "";
          for(var i = 0; i < size; i++)
          {
            items = items + '<option value="' + data[i].id_state + '">' + data[i].name + '</option>';
            //console.log(data[i].id_state + " : " + data[i].name);
          }  
          $('#cities').html("");
          $('#cities').append(items);
          $('#cities').change();
        }
      });      
     });

    });      
    </script>
</head>
<body>

<a href="#">Selecciona un estado</a>
<br/>
<select id="states">
</select>
<br/>
<a href="#">Selecciona una ciudad</a>
<br/>
<select id="cities">
</select>
<br/>

<div id="map">
</div>

</body>
</html>

Como pueden ver, al inicio cargamos la librería de JQuery desde google, después hacemos la primera petición al script data.php via ajax para que nos traiga los estados y poder “rellenar el primer selectbox”, después tenemos el siguiente código javascript.

     $('#states').change(function() {
      $.ajax({
        url: 'data.php?action=getCities&stateID=' + $('#states').val(),
        dataType: 'json',
        success: function(data) {
          var size = Object.size(data);
          var items = "";
          for(var i = 0; i < size; i++)
          {
            items = items + '<option value="' + data[i].id_state + '">' + data[i].name + '</option>';
            //console.log(data[i].id_state + " : " + data[i].name);
          }  
          $('#cities').html("");
          $('#cities').append(items);
          $('#cities').change();
        }
      });      
     });


change() nos permite detectar el cambio de selección de un selectbox, entonces utilizamos ese evento para “refrescar” las opción del segundo selectbox, vemos cual es el estado que esta seleccionado, extraemos su valor (es el mismo id que le corresponde en la tabla de estados) y armamos la petición para mandar traer las ciudades :).

Y listo con esto tenemos listo un mini ejemplo de selectbox dependientes, espero les sirva este pequeño snippet :), ya saben cualquier duda pónganla en comentarios.

La verdad es un código bastante sencillo y fácil de implementar (unos 10 mins a lo mucho), con un poco mas de código se podría mostrar la ubicación de la ciudad en google maps o utilizar esto en algún formulario de registro o cualquier otra cosa.

salu2