¿Odias los anuncios? Ir Sin publicidad Hoy

Esquemas de GraphQL Escribir, Formatear y Comprender SDL sin el código repetitivo

Actualizado en

Los esquemas de GraphQL son contratos auto-documentados entre servidor y cliente. Esta guía te lleva desde cero a la Lenguaje de Definición de Esquema (SDL): tipos, escalares, consultas, mutaciones, tipos de entrada, enumeraciones e interfaces, para que puedas leer y escribir esquemas con confianza.

Esquemas de GraphQL: Escribe, Formatea y Entiende SDL sin el Boilerplate 1
ANUNCIO · ¿ELIMINAR?

Si has trabajado con APIs REST y luego has abierto por primera vez un esquema de GraphQL, la sintaxis probablemente se parecía a lo que ya conocías, pero no era completamente parseable. Eso es normal. El Lenguaje de Definición de Esquemas (SDL) es conciso, pero transmite mucho significado por línea. Este artículo lo desglosa para que puedas leer y escribir esquemas sin tener que consultar las documentaciones cada cinco minutos.

Qué es realmente un esquema de GraphQL

Un esquema de GraphQL es el contrato entre tu servidor de API y cada cliente que lo llama. Define exactamente qué datos existen, qué operaciones están disponibles y qué forma tienen las respuestas. A diferencia de REST —donde descubres puntos de acceso mediante documentación, pruebas y errores— GraphQL hace que el contrato sea explícito y legible por máquinas.

Cada API de GraphQL comienza con un esquema escrito en SDL. El servidor valida todas las consultas contra él en tiempo de ejecución. Si un cliente pide un campo que no existe en el esquema, la solicitud se rechaza antes de que se ejecute cualquier resolución. Este es el valor fundamental del sistema de tipos de GraphQL: el esquema es la fuente de verdad para el área de superficie de tu API.

Básicos del SDL: Tipos, Consultas y Mutaciones

Cada archivo SDL se construye a partir de definiciones de tipos. Aquí está el esquema más útil posible:

type Query {
  hello: String
}

Query es el punto de entrada para operaciones de lectura. Cada esquema debe tener uno. El campo hello devuelve un String — uno de los cinco tipos escalares integrados.

Los cinco escalares integrados son:

  • Cadena — texto UTF-8
  • Int — entero firmado de 32 bits
  • Float — punto flotante de precisión doble
  • Boolean — verdadero o falso
  • IDENTIFICACIÓN — un identificador único, serializado como cadena

Esquemas reales definen tipos de objetos personalizados. Aquí está un patrón más típico:

type User {
  id: ID!
  name: String!
  email: String!
  role: UserRole!
  posts: [Post!]!
}

type Post {
  id: ID!
  title: String!
  body: String
  author: User!
  publishedAt: DateTime
}

type Query {
  user(id: ID!): User
  posts: [Post!]!
}

Hay mucho sucediendo en esas 20 líneas. Vamos a desglosarlo.

Campos no nulos y listas

El ! después de un tipo significa que el campo no es nulo — nunca devolverá null. Sin ello, el campo es nulo y el cliente debe manejar un valor ausente. Esta distinción importa en tiempo de ejecución: si un resolución de un campo no nulo lanza una excepción o devuelve null, GraphQL propagará el null hacia arriba en el árbol, posiblemente nulando también campos padres.

Las listas usan corchetes: [Post] es una lista nula de publicaciones nulas. [Post!]! es una lista no nula de publicaciones no nulas. Esa es la versión que normalmente deseas — un campo que siempre devuelve un array (posiblemente vacío) y cada elemento dentro de él es siempre un objeto real, no nulo.

Las cuatro combinaciones, explicadas:

  • [Post] — lista nula, elementos nulos (raramente útiles)
  • [Post!] — lista nula, elementos no nulos
  • [Post]! — lista no nula, elementos nulos
  • [Post!]! — lista no nula, elementos no nulos (más común)

Mutaciones: escritura de datos

Las consultas son de solo lectura. Las mutaciones manejan escrituras. El tipo Mutation se estructura de la misma manera que Query, pero por convención sus campos tienen efectos secundarios:

type Mutation {
  createPost(input: CreatePostInput!): Post!
  deletePost(id: ID!): Boolean!
}

Aviso CreatePostInput! — es un tipo de entrada, lo que lleva directamente al siguiente concepto.

Tipos de entrada vs tipos de salida

Este es uno de los puntos más comunes de confusión en esquemas de GraphQL. Usted no pueden reutiliza un tipo de objeto como Post como argumento en una mutación. SDL tiene dos tipos separados por una razón:

  • Tipos de objeto (type) — utilizados en respuestas. Pueden contener resoluciones y lógica compleja de campos.
  • Tipos de entrada (input) — utilizados en argumentos. Datos simples, sin resoluciones. Los campos solo pueden referirse a escalares u otros tipos de entrada.
input CreatePostInput {
  title: String!
  body: String
  authorId: ID!
}

Esta separación mantiene la validación de argumentos limpia y evita problemas de referencia circular que surgirían si se usaran directamente tipos de salida (que pueden referirse entre sí en grafos complejos) como entradas.

Escalares personalizados

Los cinco escalares integrados no cubren todo. Una cadena de fecha-hora, una URL, un lote de JSON — estos necesitan escalares personalizados. Se declaran así:

scalar DateTime
scalar JSON
scalar URL

La declaración del escalar indica el nombre que se utilizará. La lógica real de serialización, deserialización y validación vive en la implementación del servidor — no en el archivo de esquema. Bibliotecas como graphql-scalars ofrecen implementaciones listas para usar para tipos comunes, así que no necesitas escribirlas desde cero.

Usa escalares personalizados cuando una String es técnicamente correcta pero semánticamente incorrecta. Un campo tipado como DateTime comunica intención; un campo tipado como String obliga al cliente a adivinar el formato.

Enums

Los enums restringen un campo a un conjunto fijo de valores de cadena. Son más confiables que cadenas brutas porque el esquema enforces los valores permitidos al nivel de tipo:

enum UserRole {
  ADMIN
  EDITOR
  VIEWER
}

enum PostStatus {
  DRAFT
  PUBLISHED
  ARCHIVED
}

Un campo tipado como UserRole nunca devolverá una cadena inesperada. Un campo tipado como String podría devolver cualquier cosa. Usa enums cada vez que el conjunto de valores es conocido, estable y significativo para los clientes — hace que la introspección del esquema sea significativamente más útil.

Interfaces y Uniones

Cuando un campo puede devolver tipos diferentes de objetos, GraphQL ofrece dos mecanismos: interfaces y uniones.

Interfaces definen un conjunto compartido de campos. Los tipos que implementan la interfaz deben incluir esos campos:

interface Node {
  id: ID!
}

type User implements Node {
  id: ID!
  name: String!
}

type Post implements Node {
  id: ID!
  title: String!
}

Uniones agrupan tipos sin requerir campos compartidos. Son útiles cuando los tipos posibles no tienen nada en común estructuralmente:

union SearchResult = User | Post | Comment

type Query {
  search(query: String!): [SearchResult!]!
}

Los clientes usan fragmentos inline para manejar cada tipo en una unión o interfaz: ... on User { name }. Si estás devolviendo datos polimórficos, prefiere interfaces cuando los tipos comparten campos, y uniones cuando no comparten campos.

Directivas

Las directivas modifican el comportamiento en el nivel de campo o tipo. Dos están integradas en cada implementación de GraphQL:

  • @deprecated(reason: "Use newField instead") — marca un campo como descontinuado en la introspección
  • @skip(if: Boolean) y @include(if: Boolean) — condiciones en el lado del cliente en consultas

También puedes definir directivas personalizadas para cosas como controles de autenticación, pistas de límite de velocidad o anotaciones de caché. Se declaran en el esquema y se implementan en el servidor:

directive @auth(requires: UserRole = ADMIN) on FIELD_DEFINITION

type Mutation {
  deleteUser(id: ID!): Boolean! @auth(requires: ADMIN)
}

GraphQL vs REST: Cuándo usar cuál

El enfoque primero en esquema de GraphQL tiene beneficios en situaciones específicas. Es la opción correcta cuando:

  • Varios clientes (web, móvil, terceros) necesitan subconjuntos diferentes del mismo conjunto de datos
  • Quieres evolucionar la API sin versionado — puedes agregar campos libremente, descontinuar en lugar de eliminar
  • El dominio es naturalmente de forma de grafo con relaciones complejas entre entidades
  • Quieres una API auto-documentada que los clientes puedan explorar mediante introspección

REST sigue siendo la mejor opción cuando:

  • Estás construyendo puntos de acceso simples CRUD con cargas predecibles y planas
  • La caché HTTP es crítica — las solicitudes POST de GraphQL no se almacenan de forma nativa
  • El equipo es pequeño y la superficie de la API es estable — el sobrecarga de REST es menor
  • Estás enfrentando el problema de N+1 y no quieres configurar DataLoader para solucionarlo

El problema de N+1 merece una pausa. En un resolución de GraphQL que carga posts y cada publicación de author, una implementación ingenua ejecuta una consulta de base de datos por cada publicación para cargar al autor. Con 50 publicaciones, eso son 51 consultas por una sola solicitud. REST no tiene este problema porque controlas exactamente qué SQL se ejecuta por punto de acceso. En GraphQL, se soluciona con agrupación (DataLoader o equivalente) — es resoluble, pero es otra cosa más que debes configurar correctamente.

Formatea y valida tu SDL

Los archivos de esquema acumulan indentación inconsistente, espaciado desigual y desviación estructural a medida que crece el equipo. Antes de cometer cambios en el esquema, ejecútalo a través de un formateador para normalizar el espaciado, ordenar campos y detectar errores de sintaxis antes de que lleguen al CI.

El Formateador de Esquemas GraphQL on iotools.cloud hace exactamente esto — pega tu SDL, obtén una salida limpia y consistentemente formateada con errores de validación mostrados en línea. Maneja esquemas multitypo, escalares personalizados, directivas y los casos especiales que confunden el formato manual. Útil como paso final antes de cometer o compartir un esquema con otro equipo.

¿Quieres eliminar publicidad? Adiós publicidad hoy

Instalar extensiones

Agregue herramientas IO a su navegador favorito para obtener acceso instantáneo y búsquedas más rápidas

añadir Extensión de Chrome añadir Extensión de borde añadir Extensión de Firefox añadir Extensión de Opera

¡El marcador ha llegado!

Marcador es una forma divertida de llevar un registro de tus juegos, todos los datos se almacenan en tu navegador. ¡Próximamente habrá más funciones!

ANUNCIO · ¿ELIMINAR?
ANUNCIO · ¿ELIMINAR?
ANUNCIO · ¿ELIMINAR?

Noticias Aspectos técnicos clave

Involucrarse

Ayúdanos a seguir brindando valiosas herramientas gratuitas

Invítame a un café
ANUNCIO · ¿ELIMINAR?