Saltar al contenido

Lección 2 de 20 · Lectura y práctica

Definir un Esquema GraphQL Básico con Tipos

Concepto claveUn esquema GraphQL es la definición formal de tu API. Piensa en él como el contrato entre el cliente y el servidor: especifica qué datos se pueden consultar, qué mutaciones se pueden realizar y qué suscripciones.

Del concepto a la práctica

Taller de esta lección

Un esquema útil expresa restricciones que el cliente puede comprobar antes de ejecutar la operación. La diferencia entre String, String!, [Item] y [Item!]! cambia qué respuestas son válidas, así que la nulabilidad debe representar una decisión de dominio, no una decoración.

Ejemplo resuelto

Para una agenda de sesiones:

graphql
type Session { id: ID!, topic: String!, seats: Int!, tags: [String!]! }
type Query { session(id: ID!): Session }

Una sesión siempre tiene identificador, tema, cupos y una lista, aunque la lista esté vacía. session puede ser nula porque el identificador podría no existir.

  1. Enumera las entidades que el cliente necesita consultar.

  2. Marca como obligatorios solo los campos garantizados por los datos.

  3. Define argumentos con nombres y tipos explícitos.

  4. Escribe una consulta válida y otra que el esquema deba rechazar.

Error frecuente: confundir [String]!, que permite elementos nulos, con una lista de etiquetas siempre presentes. Corrección: usa [String!]! si tanto la lista como cada etiqueta deben existir.

Pruébalo

Añade level: Int! y prueba una sesión con level: 2.

Comprueba tu resultado

La consulta devuelve tags: [] para una sesión sin etiquetas; un resolver que omite topic falla durante la ejecución; una variable Int que contiene texto falla al convertir los inputs. No es el mismo momento de error.

Tres resultados que no debes confundir

Seleccionar solo id sin topic es una consulta válida: no es obligatorio pedir todos los campos no nulos. Pedir un campo inexistente falla antes de ejecutar resolvers. Si el resolver devuelve topic=null para un campo String!, GraphQL agrega errors y propaga null hasta el padre nullable, aquí session. En cambio tags=[] cumple [String!]!: lista obligatoria no significa lista no vacía. Una variable para un argumento Int debe ser un número entero válido; la conversión de variables ocurre antes de invocar el campo.

Navegador, API y base de datos conectados por solicitudes, consultas y respuestas en sentidos opuestos.
CursaloMapa de práctica
Del navegador a los datos

El navegador envía una solicitud a la API. El servidor valida la operación y consulta los datos; después devuelve una respuesta que el navegador puede mostrar. La base de datos se comunica con el servidor y no directamente con el navegador.

Ver la infografía en tamaño completo ↗
Fuentes para profundizar

Concepto clave

Un esquema GraphQL es la definición formal de tu API. Piensa en él como el contrato entre el cliente y el servidor: especifica qué datos se pueden consultar, qué mutaciones se pueden realizar y qué suscripciones están disponibles. A diferencia de REST, donde tienes múltiples endpoints, GraphQL tiene un único endpoint y el esquema define todas las operaciones posibles.

Los tipos GraphQL son los bloques fundamentales del esquema. Cada tipo define la estructura de un objeto, incluyendo sus campos y el tipo de dato de cada campo. Los tipos escalares básicos (como String, Int, Float, Boolean, e ID) representan valores atómicos, mientras que los tipos de objeto agrupan campos relacionados. Por ejemplo, en una aplicación de e-commerce, podrías tener un tipo Producto con campos como id (ID), nombre (String), y precio (Float).

Un esquema bien definido es como el plano de un edificio: sin él, cada desarrollador construiría de forma diferente, llevando a inconsistencias y errores.

Cómo funciona en la práctica

Para definir un esquema básico en GraphQL con Apollo Server y Next.js, sigamos estos pasos:

  1. Crea un archivo schema.graphql en la carpeta lib/graphql de tu proyecto Next.js.
  2. Define tipos usando la sintaxis SDL (Schema Definition Language). Por ejemplo:
    type Producto {
      id: ID!
      nombre: String!
      precio: Float!
      stock: Int
    }
    
    type Query {
      productos: [Producto!]!
      producto(id: ID!): Producto
    }
  3. Observa que ! indica que un campo es no-nulo (obligatorio), y [] denota una lista. El tipo Query es especial: define las consultas que los clientes pueden realizar.
  4. Integra este esquema en Apollo Server en tu API route de Next.js, importándolo y pasándolo a la configuración del servidor.

Este enfoque asegura que tu API esté tipada desde el inicio, reduciendo errores en tiempo de ejecución.

Caso de estudio

Imagina que estás construyendo una API para una plataforma de cursos en línea. Tu esquema podría incluir tipos como Curso, Instructor, y Estudiante. Aquí un ejemplo concreto:

type Curso {
  id: ID!
  titulo: String!
  descripcion: String
  duracionHoras: Int!
  instructor: Instructor!
  estudiantesInscritos: [Estudiante!]
}

type Instructor {
  id: ID!
  nombre: String!
  especialidad: String!
  cursosDictados: [Curso!]!
}

type Query {
  cursos: [Curso!]!
  cursoPorId(id: ID!): Curso
  instructores: [Instructor!]!
}

Este esquema permite consultas como obtener todos los cursos con sus instructores, o un curso específico por ID. Nota cómo los tipos se relacionan: Curso tiene un campo instructor de tipo Instructor, y Instructor tiene un campo cursosDictados que es una lista de Curso. Esto crea una estructura de datos coherente y reutilizable.

Errores comunes

  • Olvidar los signos de exclamación para campos obligatorios: Si un campo debe siempre devolver un valor, usa !. Sin él, GraphQL permitirá valores nulos, lo que puede causar errores en el cliente. Por ejemplo, en nombre: String vs nombre: String!, el primero acepta null, el segundo no.
  • Definir tipos circulares sin límites: En relaciones como la de Curso e Instructor, asegúrate de que las listas no sean infinitas. En la práctica, limita la profundidad de las consultas o usa paginación para evitar sobrecargar el servidor.
  • No usar tipos escalares apropiados: Usa ID para identificadores únicos, no String. Esto ayuda a GraphQL a optimizar el caching y la validación. Por ejemplo, id: ID! es mejor que id: String!.
  • Ignorar la nulabilidad en listas: Una lista como [Producto] puede ser null o contener elementos null. Para evitar esto, usa [Producto!]! que asegura que la lista no sea null y que ningún elemento sea null.
  • Definir esquemas demasiado complejos desde el inicio: Comienza con tipos básicos y expande según las necesidades. Un esquema sobrecargado puede ser difícil de mantener y ralentizar el desarrollo.

Checklist de dominio

  • He definido al menos tres tipos de objeto en mi esquema GraphQL, usando SDL en un archivo .graphql.
  • He incluido un tipo Query con al menos dos consultas diferentes que devuelven datos de mis tipos.
  • He usado tipos escalares correctos (String, Int, Float, Boolean, ID) para los campos, aplicando no-nulabilidad (!) donde sea necesario.
  • He establecido relaciones entre tipos, como un campo en un tipo que referencia otro tipo, manejando listas con sintaxis apropiada (e.g., [Tipo!]!).
  • He integrado mi esquema en Apollo Server dentro de un proyecto Next.js, verificando que se pueda ejecutar una consulta básica.
  • He evitado tipos circulares infinitos al limitar la profundidad de las relaciones en las definiciones.
  • He revisado mi esquema para asegurar que sea coherente con los requisitos del negocio, como campos obligatorios para datos críticos.

Definir un esquema GraphQL para una app de tareas

En este ejercicio, crearás un esquema GraphQL básico para una aplicación de gestión de tareas (todo list). Sigue estos pasos:

  1. Crea un nuevo proyecto Next.js o usa uno existente. En la carpeta lib/graphql, crea un archivo llamado schema.graphql.
  2. Define un tipo Tarea con los siguientes campos: id (ID, no nulo), titulo (String, no nulo), descripcion (String, puede ser nulo), completada (Boolean, no nulo, valor por defecto false), y fechaCreacion (String, no nulo).
  3. Define un tipo Query con dos consultas: tareas que devuelva una lista no nula de tareas no nulas, y tarea que acepte un argumento id de tipo ID no nulo y devuelva una tarea (puede ser nula si no se encuentra).
  4. Define un tipo Mutation con al menos una mutación: crearTarea que acepte argumentos para titulo y descripcion (ambos Strings, titulo no nulo) y devuelva la tarea creada.
  5. Integra este esquema en un API route de Next.js usando Apollo Server. Prueba ejecutar una consulta simple en GraphQL Playground o Apollo Studio para verificar que funciona.
Pistas
  • Recuerda que en SDL, los argumentos en mutaciones se definen entre paréntesis, por ejemplo: crearTarea(titulo: String!, descripcion: String): Tarea
  • Usa el tipo ID para el campo id, no String, para aprovechar las optimizaciones de GraphQL.
  • Asegúrate de que las listas en GraphQL usen la sintaxis correcta: [Tarea!]! significa una lista no nula que no contiene elementos nulos.

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.

Sigue con GraphQL Profesional con Next.js y Apollo Server: APIs Tipadas y Suscripciones

Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.

Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.

01 / ELEGIR UNA RUTA

El próximo paso

Aprende IA mientras construyes algo que sí necesitas.

Empieza por el curso inicial o explora el catálogo para encontrar una práctica alineada con tu trabajo.