Quicklinks
Introduccion
En este artículo voy a mostrarte como usar Apollo-Server para tomar un REST API y “traducirlo” en un nodo de GraphQL---que luego puedes integrar con el resto de tu schema y leerlo desde el cliente con Apollo-Client. Esto es muy útil si ya tienes un schema y quieres interactuar con APIs externas que no controlas, o si ya tienes un backend armado en Django por ejemplo y no quieres re-escribir todo solo para probar esta nueva tecnología que se ha puesto tan popular.
No voy a poder cubrir GraphQL desde 0 en este post o se alargaría mucho (y también es bastante nuevo para mí) pero hay muy buenos recursos para aprender en internet, probablemente partiendo por la documentación de Apollo mismo.
Para que el ejemplo esté completo, voy a implementar este servidor en una página estática creada con Gatsby para mostrarte como podrías hacer uso de este servidor. Lo mejor, es que vamos a usar las funciones serverless de netlify para servirlo junto al cliente, de manera que nunca vas a tener que preocuparte por armar infraestructura---y va a ser totalmente gratis!
Qué vamos a construir
Para los ansiosos, acá puedes ver lo que vamos a construir. Es el starter theme de blog oficial de gatsby (se ve familiar?), y le agregué una página que se conecta a una API abierta que encontré del gobierno que lista los regalos recibidos por funcionarios del gobierno según la ley de lobby (no tengo ninguna intención política con esto, solo necesitaba una API abierta y esta era más interesante que mostrar el dólar observado del día).
Dejé todo lo relacionado al blog en sí sin adulterar, porque recuerda que el foco acá es conectar la API externa. Si navegas a /donaciones
, podrás ver una lista con los datos que vienen de la API, donde puedes cambiar el número de página (la API viene con paginación) para obtener más resultados. Si navegas a /.netlify/functions/graphql
, puedes ver el schema de graphql que generamos, e interactuar con los datos—esta es una de las mayores ventajas de esta tecnología sobre REST!
Resumen
Si miras a la rápida este post, vas a ver que es muy largo y quizás te va a parecer muy complicado. La verdad es que no hay nada muy complejo acá, y la única complicación realmente viene de tener que manejar muchos archivos al mismo tiempo. Por eso voy a poner acá una especie de guía para que quede claro más adelante como se relacionan los archivos a las distintas funcionalidades que estamos armando. Todo lo que está acá es lo que haremos durante el resto del post, por lo que no va a hacer mucho sentido ahora---tómalo como referencia si te pierdes más adelante con qué archivo hace qué cosa o por qué está donde está. Notar que algunos aspectos de esta estructura vienen dados y no se pueden reemplazar (Gatsby) mientras que otros fueron los que elegí yo y puedes usar otro que te acomode (Apollo).
- Gatsby: La base del app, cuenta principalmente con 3 grupos de archivos:
- Archivos de configuración, que van en la raíz del proyecto (
gatsby-config.js
,gatsby-ssr.js
ygatsby-browser.js
). - Archivos de contenido, todos dentro de la carpeta
content
. Cuando quieres escribir un post, agregar un archivo.mdx
(markdown + JSX) a la carpeta correspondiente y Gatsby lo convierte en una página. - Archivos de funcionalidad, dentro de
src
y repartidos entrecomponents
ypages
(cada archivo acá se traduce en una página del sitio). También están los archivos propios del theme que estamos usando, y que podemos sobre-escribir (shadow) para cambiar aspectos como el layout.
- Archivos de configuración, que van en la raíz del proyecto (
- Apollo: Usaremos Apollo en 2 formas: Apollo-Server para leer la API REST externa y servir un endpoint con un servidor de GraphQL, y Apollo-Client para acceder a estos datos dentro de la app.
- Server: Dentro de la carpeta
src/apollo/server
están los módulos que determinan el funcionamiento del servidor---datasource.js
maneja la conexión al API externo, mientras queresolvers.js
junta todos los resolvers que determinarán como resolver los queries/mutations que le vamos a enviar desde el cliente. Finalmente, el servidor es inicializado ensrc/lambda/graphql.js
, lo que es un poco confuso porque este archivo está 100% relacionado con los 2 anteriores, sin embargo tiene que estar acá para que Netlify lo reconozca como una función lambda y la construya. - Client: Para poder usar el cliente de Apollo en gatsby, lo voy a inicializar en
src/apollo/client.js
, para luego importarlo con desdegatsby-ssr.js
ygatsby-browser.js
y así elApolloProvider
estará disponible en todos mis componentes (notar que hago esto a través de la función de utilidad ensrc/apollo/wrap-root-element.js
).
- Server: Dentro de la carpeta
Empezamos
Levantar el sitio gatsby
Para empezar, crea un nuevo sitio de gatsby con los siguientes comandos. Si no tienes gatsby instalado, corre primero npm install -g gatsby
.
1$2$ gatsby new gatsby-rest-apollo https://github.com/gatsbyjs/gatsby-starter-blog-theme3$ cd gatsby-rest-apollo4$ yarn install5$ gatsby develop
Notar que gatsby-rest-apollo
es el nombre que yo le puse al proyecto, y tu puedes elegir lo que quieras.
Si ahora navegas en tu explorador a http://localhost:8000
, vas a ver el sitio listo. Si lo único que estuvieramos haciendo es un blog nuevo, estás listo! Cada archivo markdown que incluyas en la carpeta content/posts/
va a ser convertido en una página e incluido de manera automática—así de fácil es. Adicionalmente, estos archivos son tipo mdx
, lo que te permite incluir componentes de react directamente en markdown! Luego lo conectas a netlify (al final veremos como hacer esto), y cada vez que hagas git push origin master
se va a construir/publicar con tus cambios.
Instalar paquetes
En esta aplicación usaremos varios paquetes externos, y además necesitamos cambiar algunos de los scripts que vienen por default del starter de gatsby. Reemplaza el package.json
con lo siguiente:
1{2 "name": "gatsby-rest-apollo-example",3 "private": true,4 "version": "0.0.1",5 "scripts": {6 "develop": "gatsby develop",7 "start": "gatsby develop",8 "start:app": "npm run develop",9 "start:lambda": "netlify-lambda serve src/lambda",10 "build": "gatsby build",11 "build:app": "gatsby build",12 "build:lambda": "netlify-lambda build src/lambda"13 },14 "dependencies": {15 "@apollo/react-hooks": "^3.0.0",16 "apollo-boost": "^0.4.4",17 "apollo-datasource-rest": "^0.6.1",18 "apollo-server-lambda": "^2.8.1",19 "dotenv": "^8.0.0",20 "gatsby": "^2.13.61",21 "gatsby-cli": "^2.7.30",22 "gatsby-theme-blog": "^1.0.2",23 "graphql-tag": "^2.10.1",24 "isomorphic-fetch": "^2.2.1",25 "netlify-lambda": "^1.5.1",26 "react": "^16.9.0",27 "react-dom": "^16.9.0",28 "styled-components": "^4.3.2"29 }30}
Y ahora anda a la terminal y corre yarn install
. Corre gatsby develop
de nuevo para confirmar que todo sigue en pie bien.
Construir el servidor de GraphQL
Para empezar, vamos a armar un servidor con Apollo-server. Como en este caso el objetivo es incorporar REST, vamos a usar Rest Data Source. El beneficio de usar esto en lugar de simplemente hacer los calls con fetch
desde los resolvers va a ser que vamos a conseguir todos los beneficios adicionales que da apollo con caching, y va a ser más fácil integrar varios APIs distintos. El proceso va a consistir en:
- Construir un schema –> Qué forma tienen tus datos
- Construir el datasource –> Cómo van a interactuar los resolvers con el API REST
- Armar los resolvers –> Qué tiene que pasar con cada query o mutation.
Schema
Primero tenemos que entender qué datos tenemos. Voy a usar ésta API abierta del Gobierno de Chile, que, entre otras cosas, tiene un par de endpoints para ver las donaciones a funcionarios del gobierno. Ahí puedes ver que del endpoint principal de donations vas a recibir una lista con objetos, cada uno con información de la donación como receptor, cargo, etc. Entonces para empezar, crea un archivo en src/lambda/
llamado graphql.js
. Acá vamos a hacer todo lo necesario para crear el servidor de apollo, y convertirlo en una función serverless que puede ser manejada por netlify.
Si estuvieramos armando un servidor que se levante por si solo (fuera de gatsby y netlify), en lugar de graphql.js
, verías en la mayoría de los tutoriales que a este archivo lo llaman server.js
o simplemente index.js
, y lo ponen junto a los modulos con los resolvers y el schema.
Si fuiste a ver la documentación de la API que puse arriba, vas a ver la forma en la que vienen los datos de vuelta. El primer paso ahora es traducir esto en un schema de GrapQL:
1// src/lambda/graphql.js2const { ApolloServer, gql } = require("apollo-server-lambda");34const typeDefs = gql`5 scalar DateTime67 type Query {8 donations(page: Int, donationId: Int): [Donation!]!9 donation(donationId: Int!): DonationDetail!10 }1112 type Donation {13 id_donativo: Int!14 nombres: String!15 apellidos: String!16 pais: String17 cargo: String18 ocasion: String19 descripcion: String20 fecha: DateTime21 nombre_institucion: String22 }2324 type DonationDetail {25 donation: Donation!26 donantes: [Donor!]!27 }2829 type Donor {30 id_donativo: Int!31 nombre: String!32 pais: String!33 tipo: String!34 giro: String35 actividades: String36 domicilio: String37 representante_legal: String38 naturaleza: String39 directorio: String40 }41`;
Acá definimos todo el schema que estará disponible de manera pública: Un Donation
que consiste en un objecto con información básica del receptor, un tipo DonationDetail
que incluye al Donation
y también una lista con sus Donors
, y la definición de estos donantes. Este es un schema pequeño y puedo incluirlo acá sin mucho problema—si creciera mucho, podrías moverlo a su propio archivo llamado schema.graphql
e importarlo con :
1const { importSchema } = require("graphql-import");2const path = require("path");34const typeDefs = importSchema(path.resolve("src/schema.graphql"));
Data Source
Luego, vamos a crear el datasource—un objeto que va a encapsular toda la lógica relacionada a nuestra interacción con la API externa. Crea un archivo llamado datasource.js
en src/apollo/server/
:
1// src/apollo/server/datasource.js2const { RESTDataSource, HTTPCache } = require("apollo-datasource-rest");34class LobbyAPI extends RESTDataSource {5 constructor() {6 super();7 this.baseURL = "https://www.leylobby.gob.cl/api/v1/";8 this.httpCache = new HTTPCache();9 }1011 // funciones por definir12}13module.exports = { LobbyAPI };
Este modulo va a crear un nuevo objeto que llamamos LobbyAPI
, que hereda de RESTDataSource de Apollo. En el constructor definimos la url base a donde se harán los requests. Finalmente, se define una función para cada uno de los queries que queremos hacer. Es muy importante que para cada query que definas en tus resolver, tengas un método correspondiente en este archivo, o el datasource no va a saber que hacer. Para entender bien estás funciones, lo mejor es ir en paralelo con los resolvers, así que veamos eso primero y luego volvemos.
Resolvers
Los resolvers van a ir en otro archivo, y van a interactuar directamente con las funciones definidas en el data source. Tenemos que crear un resolver para cada query definido en nuestro schema:
1donations(page: Int, donationId: Int): [Donation!]!2 donation(donationId: Int!): DonationDetail!
Uno llamado donations
que recibe 2 argumentos y devuelve una lista de objetos, y otro llamado donation
que recibo un ID y devuelve un objeto. En esta guía voy a mostrar solamente el primer resolver, y el segundo es similar y está disponible en el repo.
Empecemos con un resolver para obtener la lista de donaciones, disponible en https://www.leylobby.gob.cl/api/v1/donations{?page}{?institucion}{?cargo_pasivo}
. Nuestro resolver va a tener que recibir argumentos para el número de página, el ID de la institución y el ID del cargo pasivo. Omitamos este último por simplicidad, y nuestro resolver se vería así:
1// src/apollo/server/resolvers.js2const resolvers = {3 Query: {4 donations: async (parent, args, { dataSources }) => {5 const { page, institutionId } = args;6 const donations = await dataSources.lobbyAPI.getAllDonations(7 page,8 institutionId9 );10 return donations;11 }12 }13};1415module.exports = resolvers;
Los resolvers siempre reciben 4 argumentos: (parent, args, context, info)
, y en nuestro caso solo nos importan realmente 2: el contexto y los argumentos. Los argumentos van a ser las variables que le pasaremos a nuestro query, y que son convertidos en un objeto que podemos destructurar.
El contexto va a venir con el dataSource que definimos en el paso anterior, que nos va a dar acceso a la función (aún por definir) que finalmente va a ser la que emite el request al API externo. Esta función que estamos llamando, getAllDonations
, tenemos que definirla en el datasource para que reciba 2 argumentos, y tiene que devolver un lista de donations con la forma que definimos en el schema del primer paso. Este círculo es sin duda la parte más complicada y frustrante del proceso, ya que hay que estar muy concentrado en que va donde y que no falte nada, y si algo sale mal es difícil de encontrar. Vamos entonces a definir la función que recogerá los datos de la API:
1// src/apollo/server/datasource.js2const { RESTDataSource, HTTPCache } = require("apollo-datasource-rest");34class LobbyAPI extends RESTDataSource {5 constructor() {6 super();7 this.baseURL = "https://www.leylobby.gob.cl/api/v1/";8 this.httpCache = new HTTPCache();9 }1011 async getAllDonations(page, institutionId) {12 const donations = await this.get("donativos/", {13 page,14 institutionId15 });16 return donations.data;17 }18}19module.exports = { LobbyAPI };
Y listo! eso es todo lo que necesitamos, ya que armamos el schema de manera que la API devuelve un objeto que en el atributo data
contiene los datos que queremos con exactamente la forma que definimos. La función consiste solamente en llamar al método get
de la clase base (podría ser post
para un mutation) y le pasamos 2 argumentos: el path
(relativo al URL base que definimos previamente) donde hacer el request, y un objeto con los parámetros. También podríamos incluir headers, data, etc.
Para entenderlo bien, veamos como se vería en proceso completo. Si el cliente quiere ver una lista con los donations, abre el playground de graphql y ve en el schema que hay un query definido como donations(page: Int, donationId: Int): [Donation!]!
, que recibe 2 argumentos, page
y donationId
y devuelve una lista de objetos llamados Donation
. Si realiza un query como el siguiente:
1query {2 donations(page: 16) {3 nombres4 apellidos5 }6}
Se gatilla el resolver, que lo único que hace es llamar al método getAllDonations
que definimos en el datasource (y que recibe en el contexto) traspasando los argumentos que recibe. Finalmente, si vamos a esta función vemos que realiza un request GET
al url https://www.leylobby.gob.cl/api/v1/
+ donativos/
, entregando adicionalmente estos 2 argumentos como parámetros del request (van al final como ?page=16&insitucion=null
). Esta función recibe un objeto que guardamos en la constante donations
y devuelve lo que está en el atributo data
, que sabemos (mirando la documentación de la API externa) que es un objeto con la información que queremos. este objeto es traspasado directamente por el resolver (esta vez a través de la variable donations
) y así llega finalmente al cliente, filtrando para entregar solamente los atributos requeridos por este: nombres
y apellidos
.
El otro resolver, para el query donation(id: Int!)
tiene una forma similar y no lo voy a incluir acá por espacio, pero lo puedes ver en el repo. Esta API solamente va a realizar queries, ya que no tengo acceso a modificar datos que no son míos. Pero en un ejemplo más real donde estás interactuando totalmente con una base de datos, se pueden crear mutations con estos mismos pasos.
Con los resolvers listos, volvemos al archivo base graphql.js
para incorporarlos y dar por terminado el servidor:
1// src/lambda/graphql.js2const { ApolloServer, gql } = require("apollo-server-lambda");3const { LobbyAPI } = require("../apollo/server/datasource");4const resolvers = require("../apollo/server/resolvers");56const typeDefs = gql`7 scalar DateTime89 type Query {10 donations(page: Int, donationId: Int): [Donation!]!11 donation(donationId: Int!): DonationDetail!12 }1314 type Donation {15 // ...16 }1718 type DonationDetail {19 // ...20 }2122 type Donor {23 // ...24 }25`;2627const server = new ApolloServer({28 typeDefs,29 resolvers,30 dataSources: () => ({31 lobbyAPI: new LobbyAPI()32 })33});3435// Exportar el servidor en una función del formato que netlify espera36exports.handler = server.createHandler();
Por último, crea un archivo llamado netlify.toml
en la raíz del proyecto con la configuración necesaria para que netlify sepa que hacer con esta función.
1[build]2 command = "yarn build"3 functions = "built-lambda"4 publish = "public"
Con esto listo, podemos inicializar nuestro servidor en development y ver como funciona. Abre otra terminal, y corre NODE_ENV=development npm run start:lambda
. Si navegas a localhost:9000/.netlify/functions/graphql
, vas a ver el GraphQL Playground donde puedes interactuar con los queries que creaste. Pega este snippet para ver ejemplos de como funciona.
1query GET_DONATIONS {2 donations(page: 1) {3 nombres4 apellidos5 cargo6 ocasion7 descripcion8 }9}
Incorporar nuestra nueva API en el cliente
Con el servidor listo, vamos a conectarlo ahora con nuestro sitio gatsby usando Apollo-Client. Primero vamos a hacer los cambios necesarios en los archivos de configuración, y luego veremos como se puede acceder a esta data desde nuestros componentes. Este proceso es bastante estándar y los saqué casi literalmente de éste repositorio de Jason Lengstorf, que trabaja en Gatsby y tiene muy buen material para aprender.
Creando el cliente
Lo primero que hay que hacer es inicializar un nuevo cliente que se conecte a nuestro endpoint—lo haremos creando un
archivo en src/apollo/
llamado client.js
. El cliente va a apuntar al url en donde netlify engancha nuestro servidor.
1// src/apollo/client.js2import ApolloClient from "apollo-boost";3import fetch from "isomorphic-fetch";45export const client = new ApolloClient({6 uri: "/.netlify/functions/graphql",7 fetch8});
Luego tenemos que incluir el ApolloProvider que recibe este cliente en nuestra aplicación. Normalmente, este se pone
como wrapper a un componente alto en la jerarquía, como App.js
si usáramos create-react-app
, pero en este caso
vamos a tener que hacerlo distinto para que funcione con gatsby y el server side rendering. Para esto creamos un
archivo llamado wrap-root-element.js
, que hará justamente esto, y luego lo usaremos como el único export desde 2
archivos de configuración de gatsby: gatsby-ssr.js
y gatsby-browser.js
, que dictan el comportamiento de la app
cuando está siendo ejecutada en el servidor y en el cliente, respectivamente. Estos archivos van en la raíz del proyecto, al mismo nivel que gatsby-config.js
.
1// src/apollo/wrap-root-element.js2import React from 'react'3import { ApolloProvider } from '@apollo/react-hooks';4import {client} from './client'56export const wrapRootElement = ({ element }) => (7 <ApolloProvider client={client}>8 {element}9 </ApolloProvider>10 )111213// gatsby-browser.js14export { wrapRootElement } from "./src/apollo/wrap-root-element";151617//gatsby-ssr.js18export { wrapRootElement } from "./src/apollo/wrap-root-element";
Finalmente, para poder interactuar con el servidor en nuestra maquina local durante desarrollo, hay que crear una proxy desde donde se encuentra actualmente, localhost:9000
, al dominio del cliente. Con este cambio, ahora vas a poder acceder al playground directamente desde http://localhost:8000/.netlify/functions/graphql
. Abre gatsby-config.js
e incluye lo siguiente:
1const proxy = require("http-proxy-middleware");23module.exports = {4 plugins: [5 // .....6 ],7 siteMetadata: {8 // ....9 },10 developMiddleware: app => {11 app.use(12 "/.netlify/functions/",13 proxy({14 target: "http://localhost:9000",15 pathRewrite: {16 "/.netlify/functions/": ""17 }18 })19 );20 }21};
Incluyendo la data en nuestro componentes
Con esto, finalmente podemos acceder a nuestra data usando los métodos que provee Apollo. A modo de ejemplo, voy a crear una página en /donaciones
que va a cargar una lista con donaciones y mostrarla como tabla. Primero creamos esta página, creando el archivo donaciones.js
en src/pages/
.
1// src/pages/donaciones.js2import React from "react";3import Layout from "gatsby-theme-blog/src/components/layout";45export default function donaciones() {6 return (7 <Layout location="/donaciones" title="Home">8 <h2>Donaciones a funcionarios del gobierno</h2>9 </Layout>10 );11}
Si vas a localhost:8000/donaciones
, deberías ver esta página, prácticamente en blanco. Ahora creamos un componente ahora que reciba y muestre los datos en la consola.
1// src/components/getDonations.js2import React from 'react'3import gql from 'graphql-tag'4import {useQuery} from '@apollo/react-hooks'56const GET_DONATIONS = gql`7query getDonations {8 donations(page: 1) {9 id_donativo10 nombres11 apellidos12 cargo13 ocasion14 descripcion15 fecha16}}17`1819export default function GetDonations() {20 const { loading, error, data, refetch } = useQuery(GET_DONATIONS);2122 console.log(data)23 return (24 <div>Nothing here yet</div>25 )
Ahora vuelve a donaciones.js
e incluyelo.
1import React from "react";2import Layout from "gatsby-theme-blog/src/components/layout";3import GetDonations from "../components/getDonations";45export default function donaciones() {6 return (7 <Layout location="/donaciones" title="Home">8 <h2>Donaciones a funcionarios del gobierno</h2>9 <GetDonations />10 </Layout>11 );12}
Si haces refresh, deberías ver en la consola como se carga la data. Eso es todo! Ahora que tienes acceso a la data, puedes hacer lo que quieras. Para darle un poco más de interactividad a la cosa, incluyamos la posibilidad de cambiar el número de página a buscar, y mostremos la data en una tabla.
1import React, { useState } from "react";2import gql from "graphql-tag";3import styled from "styled-components";4import { useQuery } from "@apollo/react-hooks";56const GET_DONATIONS = gql`7 query getDonations($page: Int) {8 donations(page: $page) {9 id_donativo10 nombres11 apellidos12 cargo13 ocasion14 descripcion15 fecha16 }17 }18`;1920export default function GetDonations() {21 const [page, setPage] = useState(1);22 const { loading, error, data, refetch } = useQuery(GET_DONATIONS, {23 variables: { page }24 });2526 const handleChange = e => {27 const newPage = parseInt(e.target.value);28 setPage(newPage);29 refetch({ newPage });30 };3132 const renderTable = () => {33 return data.donations.map(donation => (34 <Tr key={donation.id_donativo}>35 <Td>{donation.id_donativo}</Td>36 <Td>{`${donation.nombres} ${donation.apellidos}`}</Td>37 <Td>{donation.cargo}</Td>38 <Td>{donation.ocasion}</Td>39 <Td>{donation.descripcion}</Td>40 <Td>{donation.fecha}</Td>41 </Tr>42 ));43 };44 return (45 <div>46 <div>47 <input type="number" value={page} onChange={handleChange} />48 </div>49 <T>50 <thead>51 <Tr>52 <Th>ID</Th>53 <Th>Nombre receptor</Th>54 <Th>Cargo</Th>55 <Th>Ocasión</Th>56 <Th>Descripción</Th>57 <Th>Fecha</Th>58 </Tr>59 </thead>60 <tbody>61 {loading && (62 <tr>63 <td>Loading</td>64 </tr>65 )}66 {data.donations && data.donations.length > 0 && renderTable()}67 </tbody>68 </T>69 </div>70 );71}7273const T = styled.table`74 width: 100%;75 border-collapse: collapse;76 color: #686f7a;77 tbody:before {78 content: "-";79 display: block;80 line-height: 0.6em;81 color: transparent;82 }83`;8485const Th = styled.th`86 text-align: "left";87 font-size: 18px;88 color: #686f7a;89 font-weight: 700;90 opacity: 0.65;91`;9293const Td = styled.td`94 text-align: "left";95`;9697const Tr = styled.tr`98 border-bottom: 2px solid rgba(150, 150, 150, 0.5);99`;
Deployment a Netlify
Con la app lista, ahora solo queda subirla para que todo el mundo la vea! Netlify hace esto muy fácil, y totalmente gratis. Subir una página de gatsby a netlify está muy bien documentado así que no voy a repetirlo acá---y si hiciste los cambios que mencioné antes en el package.json
y netlify.toml
, ya estás listo para seguir las guías estándar.
Una vez que hayas conectado tu cuenta de github a netlify, cada vez que hagas un push a master, netlify va a reconstruir tu aplicación y servirla vía sus CDNs.
Conclusión
Bueno, eso fue bastante más largo de lo que me imaginé que iba a ser—y aún así siento que tuve que pasar cosas por encima! Espero que te sirva para tener una idea de lo que se puede hacer con las herramientas disponibles hoy en día. Si seguiste todos los pasos en este post, creaste una aplicación usando el famoso JAMStack—contenido dinámico e interfaces inteligentes, sin bases de datos, sin maquinas virtuales, sin load balancers, sin servidores—pero con todos los beneficios de server-side rendering como SEO y performance.
Para otro post me gustaría mostrar una versión alternativa de lo que hicimos acá: he estado jugando com Prisma y Next.js y me ha encantado. Gatsby realmente reluce cuando el contenido de una app es principalmente estático (en el sentido que no necesita una base de datos para funcionar), como para un blog, restaurant, incluso e-commerce. Otro feature que me encanta de netlify es el CMS que provee, que se puede integrar con Gatsby si quieres hacer una página con contenido 100% editable por gente que jamás va a tener que tocar la terminal para usar git. Pero para aplicaciones más complejas, del tipo que se desarrollaría de manera especial para resolver problemas de negocio, ya se hace necesario interactuar con una base de datos y tener una aplicación más versátil. Next y Prisma permiten esto de una manera muy elegante, se puede conseguir sin mucho más código que el que usamos acá (la parte de Apollo es casi igual).
Como hay mucho que digerir en este post, habilité los comentarios por si hay algo que no funciona o te gustaría que profundice más.