Ejercicio 8.
8.1 Defininión del esquema
1. Clonar el repositorio
En el directorio c:\sc, clonar el repositorio de inicio de la aplicación:
cd c:\sc
git clone https://github.com/fararoni/curso.graphql.odyssey-lift-off-part1.git
2. Ejecutar la aplicación de lado del servidor
En una ventana CMD, ir al directorio
cd c:\sc\curso.graphql.odyssey-lift-off-part1\server
Ejecute los siguientes comandos para instalar las dependencias y ejecutar la aplicación:
npm install
npm start
únicamente verá un mensaje final “nodemon”
3. Ejecutar la aplicación de lado del cliente
En otra ventana CMD, ir al directorio
cmd
cd C:\sc\curso.graphql.odyssey-lift-off-part1\client
Ejecute los siguientes comandos para instalar las dependencias y ejecutar la aplicación:
npm install
npm start
Abra el navegador e ingrese a la siguiente dirección:
http://127.0.0.1:3000/
4. Analisis de datos
Según la maqueta, parece que necesitaremos la siguiente información para cada Ruta de aprendizaje:
- Título
- Imagen en miniatura
- Duración (duración estimada)
- Recuento de módulos
- Nombre del autor
- Foto del autor
Un tipo se declara usando la palabra reservada type, seguida del nombre del tipo (la mejor práctica es usar un formatpo PascalCase y luego abrimos corchetes para contener los campos:
type SpaceCat {
# Los campos van aquí
}
Quedando así
type SpaceCat {
age: Int
missions: [Mission]
}
Define un objeto tipo SpaceCat con los siguientes campos: name de tipo String(no nulo), age de tipo Int y missions de tipo List de Mission.
type SpaceCat {
name: String!
age: Int
missions : [Mission]
}
Documenta tu esquema como mejor práctica y para permitir que herramientas como Apollo Studio Explorer orienten a los usuarios a entender lo que hace su código.
type SpaceCat {
name: String!
age: Int
missions : [Mission]
}
5. Definición del esquema
Abrir una ventana CMD, ir al directorio del server y abrir Visual Studio code
cmd
cd C:\sc\curso.graphql.odyssey-lift-off-part1\server
code .
- Crear un nuevo archivo en la carpeta “src” con el nombre “schema.js”.
- Desde visual estudio abrir una consola en el directorio server, asegurarse que sea de tipo CMD, ejecutar lo siguiente:
npm install @apollo/server graphql graphql-tag
Ahora en el archivo schema.js, cargar la plantilla literal gql de graphql-tag:
const gql = require("graphql-tag");
Declarar una constante typeDefs (abreviatura de “definiciones de tipo”), a la que se le asignará la plantilla gql donde irán nuestras definiciones
const typeDefs = gql`
# Schema definitions go here
`;
module.exports = typeDefs;
Agregar el tipo Track
const typeDefs = gql`
"Un Track es un grupo de módulos que enseñan acerca de un tópico"
type Track {
id: ID!
title: String!
author: Author!
thumbnail: String
length: Int
modulesCount: Int
}
`;
Agregar el tipo Author
const typeDefs = gql`
"Un Track es un grupo de módulos que enseñan acerca de un tópico"
type Track {
id: ID!
title: String!
author: Author!
thumbnail: String
length: Int
modulesCount: Int
}
"Autor de un Track completo o de un Módulo "
type Author {
id: ID!
name: String!
photo: String
}
`;
6. Definición de la consulta en el esquema
Obtener la lista de rutas (Tracks) para nuestra página de inicio
type Query {
" Obtener una lista de rutas para la cuadrícula de la página de inicio"
tracksForHome: [Track!]!
}
7. Version completa del archivo schema.js
const gql = require("graphql-tag");
const typeDefs = gql`
type Query {
"Obtener un arreglo de Tracks para la página de inicio"
tracksForHome: [Track!]!
}
"Un Track es un grupo de módulos que enseñan acerca de un tópico"
type Track {
id: ID!
title: String!
author: Author!
thumbnail: String
length: Int
modulesCount: Int
}
"Autor de un Track completo o de un Módulo "
type Author {
id: ID!
name: String!
photo: String
}
`;
module.exports = typeDefs;
8.2 Creación del backend
1. Importar las librerías del servidor
Desde Visual Studio code, en la carpeta server/src/, abra el archivo index.js. Agregar al principio
const { ApolloServer } = require("@apollo/server");
const { startStandaloneServer } = require("@apollo/server/standalone");
const typeDefs = require("./schema");
Configuremos una función async llamada startApolloServer, para crear una instancia de la clase ApolloServer y le pasaremos nuestro objeto typeDefs en sus parámetros de objetos
async function startApolloServer() {
const server = new ApolloServer({ typeDefs });
}
Nota: En este código estamos usando la notación de propiedad abreviada con claves implícitas, porque hemos nombrado nuestra constante que coincide con su atributo correspondiente ( typeDefs).
Para iniciar el servidor, usaremos la función startStandaloneServer, pasándola al server que acabamos de inicializar.
async function startApolloServer() {
const server = new ApolloServer({ typeDefs });
startStandaloneServer(server);
}
La función startStandaloneServer devuelve una Promise, por lo que esperaremos los await de esa llamada y extraeremos la propiedad url del resultado.
async function startApolloServer() {
const server = new ApolloServer({ typeDefs });
const { url } = await startStandaloneServer(server);
}
Agregar un mensaje que indique que ya se levantó el servidor
async function startApolloServer() {
const server = new ApolloServer({ typeDefs });
const { url } = await startStandaloneServer(server);
console.log(`
🚀 Server is running!
📭 Query at ${url}
`);
}
Finalmente, llamar a la startApolloServerfunción al final del archivo.
startApolloServer();
Comparar la versión completa
const { ApolloServer } = require("@apollo/server");
const { startStandaloneServer } = require("@apollo/server/standalone");
const typeDefs = require("./schema");
async function startApolloServer() {
const server = new ApolloServer({ typeDefs });
const { url } = await startStandaloneServer(server);
console.log(`
🚀 Server is running!
📭 Query at ${url}
`);
}
startApolloServer();
Levantar el servidor Desde la terminal, iniciaremos nuestro servidor con npm run start desde la carpeta server
npm start
2. Sandbox explorer
- Navegar en los apartados del explorar de Apollo
3 Consultas
Guardar una operación con el nombre GetTracks que nos va a servir posteriormente.
4 Datos mock
El explorador no puede entregar datos porque no los tiene, vamos a generar datos simulados. En la consola de visual studio, interrumpir la ejecución del servidor y agregar las siguientes paquetes
ctrl + c
npm install @graphql-tools/mock @graphql-tools/schema
Agregar al principio del archivo index.js
const { addMocksToSchema } = require("@graphql-tools/mock"); const { makeExecutableSchema } = require("@graphql-tools/schema");
Modificar la constante server para que reciba los datos mock
const server = new ApolloServer({
schema: addMocksToSchema({
schema: makeExecutableSchema({ typeDefs }),
}),
});
Levanta nuevamente el servidor y revisa los datos en el explorador
Para que no muestre datos tan genéricos, agregar lo siguiente debajo de la línea
const typeDefs = require("./schema");
const mocks = {
Track: () => ({
id: () => "track_01",
title: () => "Astro Kitty, Space Explorer",
author: () => {
return {
name: "Grumpy Cat",
photo:
"https://res.cloudinary.com/dety84pbu/image/upload/v1606816219/kitty-veyron-sm_mctf3c.jpg",
};
},
thumbnail: () =>
"https://res.cloudinary.com/dety84pbu/image/upload/v1598465568/nebula_cat_djkt9r.jpg",
length: () => 1210,
modulesCount: () => 6,
}),
};
Y modificar la invocación del server
const server = new ApolloServer({
schema: addMocksToSchema({
schema: makeExecutableSchema({ typeDefs }),
mocks,
}),
});
8.3 Frontend
1. Abrir el proyecto frontend react
Abrir una Ventana CMD, ir al directorio C:\sc\curso.graphql.odyssey-lift-off-part1\client y abrir Visual Studio Code:.
cmd
cd C:\sc\curso.graphql.odyssey-lift-off-part1\client
code .
Desde visual studio, abrir una terminal CMD y ejecutar
npm start
Abrir el archivo raíz de nuestra aplicación React (client/src/index.js) , debe verse de la siguiente forma
import React from 'react';
import { createRoot } from 'react-dom/client'
import GlobalStyles from './styles';
import Pages from './pages';
const root = createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<GlobalStyles />
<Pages />
</React.StrictMode>
);
Interrumpa la ejecución del cliente y ejecute el siguiente comando
C:\sc\curso.graphql.odyssey-lift-off-part1\client>npm install graphql @apollo/client
Imporar ApolloClient en el frontend
Importar en src/index.js los tres símbolos que necesitamos del paquete @apollo/client
import { ApolloClient, InMemoryCache, ApolloProvider } from "@apollo/client";
Crear uns instancia de ApolloClient
const client = new ApolloClient({
uri: "http://localhost:4000",
cache: new InMemoryCache(),
});
Hacer que Apollo Client quede disponible para todo el arbol de componentes de React
root.render(
<React.StrictMode>
<ApolloProvider client={client}>
<GlobalStyles />
<Pages />
</ApolloProvider>
</React.StrictMode>
);
Reiniciar el client
npm start
Se ve igual, porque aun no se le envia una consulta
Enviar query
Abrir C:\sc\curso.graphql.odyssey-lift-off-part1\client\src\pages\tracks.js e importar la plantilla gql al principio del archivo
import { gql } from "@apollo/client";
A continuación definir la consulta TRACKS
const TRACKS = gql`
# Query goes here
`;
Abrir el explorador en el server y recuperar la consulta guardada TracksForHome. Actualizar con la consulta
const TRACKS = gql`
query GetTracks {
tracksForHome {
id
title
thumbnail
length
modulesCount
author {
id
name
photo
}
}
}
`;
hook useQuery
Importar useQuery desde el paquete @apollo/client en src/pages/tracks.js.
import { useQuery, gql } from "@apollo/client";
Y en el componente Tracks las siguientes constantes desestructuradas
const Tracks = () => {
const { loading, error, data } = useQuery(TRACKS);
if (loading) return "Loading...";
if (error) return `Error! ${error.message}`;
return <Layout grid>{JSON.stringify(data)}</Layout>;
};
Actualiza el servidor, debe mostrar datos. Aunque no están amigables El código queda de la siguiente forma
import React from 'react';
import { Layout } from '../components';
import { useQuery, gql } from "@apollo/client";
const TRACKS = gql`
query GetTracks {
tracksForHome {
id
title
thumbnail
length
modulesCount
author {
id
name
photo
}
}
}
`;
/**
* Tracks Page is the Catstronauts home page.
* We display a grid of tracks fetched with useQuery with the TRACKS query
*/
const Tracks = () => {
const { loading, error, data } = useQuery(TRACKS);
if (loading) return "Loading...";
if (error) return `Error! ${error.message}`;
return <Layout grid>{JSON.stringify(data)}</Layout>;
};
export default Tracks;
Renderizado en las tarjetas
Continuar trabajando en src/pages/tracks.js
import TrackCard from "../containers/track-card";
Actualizar la siguiente línea
return <Layout grid>{JSON.stringify(data)}</Layout>;
Por la siguiente
return <Layout grid>
{data?.tracksForHome?.map((track) => (
<TrackCard key={track.id} track={track} />
))}
</Layout>
Manejo de los resultados
Continuar trabajando en src/pages/tracks.js
import QueryResult from "../components/query-result";
Actualizar la siguiente línea
if (loading) return "Loading...";
if (error) return `Error! ${error.message}`;
Por lo siguiente
<QueryResult error={error} loading={loading} data={data}>
{data?.tracksForHome?.map((track) => (
<TrackCard key={track.id} track={track} />
))}
</QueryResult>
Actualice el navegador y compruebe la salida
npm start