Firebase cloud functions con firestore y GraphQL.

August 13, 2019 • ☕️ 2 minutos de lectura

Crear proyecto en Firebase.

Para desarrollar este proyecto debemos crear un nuevo proyecto en firebase si aun no lo tenemos creado.

firebase init
# ❯ ◉ Firestore: Deploy rules and create indexes for Firestore
# ❯ ◉ Functions: Configure and deploy Cloud Functions

Otra cosa importante es seleccionar JavaScript en nuestro lenguaje.

? What language would you like to use to write Cloud Functions? (Use arrow keys)

❯ JavaScript
  TypeScript

Instalar dependencias

Instalaramos las dependencis que necesitaremos en nuestro proyecto, esto debe hacerse dentro del directorio functions/.

cd functions
npm install
npm install apollo-server-express express graphql

Empezamos

Editamos el fichero functions/index.js e importamos todas las dependencias que necesitamos, además inicializaremos firestore.

const admin = require("firebase-admin");
const functions = require("firebase-functions");
const express = require("express");
const { ApolloServer, gql } = require("apollo-server-express");
admin.initializeApp(functions.config().firebase);
// const serviceAccount = require('../serviceAccountKey.json');
// admin.initializeApp({
//   credential: admin.credential.cert(serviceAccount),
// });

TypeDefs

Definimos nuestro Shema de GraphQL declarando typeDefs, los tipos definen las entidades que vamos a consultar o modificar.

const typeDefs = gql`
  type Jurado {
    nombre: String
    foto: String
    orden: Int
  }

  type Query {
    jurados: [Jurado]
    jurado(id: ID!): Jurado
  }
`;

Resolvers

Los resolvers es un objeto que tiene una propiedad igual al nombre de la Query, esta función se ejecutará cuando se llame esa query.

const resolvers = {
  Query: {
    jurados: async () => {
      let jurados = [];
      try {
        await db
          .collection("jurado")
          .get()
          .then(function(querySnapshot) {
            if (querySnapshot) {
              querySnapshot.forEach(function(doc) {
                jurados.push(doc.data());
              });
            } else {
              console.log("Do Not Exist In DB");
            }
          });
      } catch (error) {
        console.log(error);
      }
      return jurados;
    },
    jurado: async (parent, args) => {
      const { id } = args;
      let jurado;
      try {
        await db
          .collection("jurado")
          .doc(id)
          .get()
          .then(function(doc) {
            if (!doc.exists) {
              console.log("No such document!");
            } else {
              jurado = doc.data();
            }
          })
          .catch(err => {
            console.log("Error getting document", err);
          });
        return jurado;
      } catch (error) {
        console.log(error);
      }
    }
  }
};

Las funciones en la nube son triggers exportados por nuestro fichero index.js. En este caso queremos usar eltrigger https.onRequest() que devuelverá ApolloServer a través de Express a una función de HTTP.

const app = express();
const server = new ApolloServer({ typeDefs, resolvers });
server.applyMiddleware({ app, path: "/", cors: true });
exports.graphql = functions.https.onRequest(app);

Lanzar GraphiQL

Lanzamos en modo local para realizar las pruebas y testear que todo está bien.

Para ello debemos descargar una llave privada de nuestra consola de firebase > Configuración > Cuentas de Servicio https://console.firebase.google.com/project/ruta-del-atun-ba866/settings/serviceaccounts/adminsdk

Esto nos devolverá en la consola una url similar a http://localhost:5000/firestore-to-graphql/us-central1/graphql

firebase serve

Si queremos desplegar nuestra función a producción basta con

firebase deploy

Ahora podemos disponer del endpoint de nuestra función, que estará disponible en Consola de Firebase > Funciones.

⚠️La interfaz de GraphiQL no estará disponible en producción, deberás acceder mediantes querys

https://us-central1-firestore-to-graphql.cloudfunctions.net/graphql?query={personajes{name}}