Como consumir GraphQL de WPGraphQL desde JS en el frontend en WordPress

Contents

Introducción

En este tutorial vas a aprender, con todo lujo de detalles, a consumir GraphQL expuesto por WPGraphQL desde JavaScript en el frontend de WordPress. Cubriremos desde los conceptos básicos hasta ejemplos prácticos: cómo montar consultas, enviar variables, autenticar peticiones (nonce y JWT), integrar con librerías como Apollo Client o graphql-request, manejar paginación, errores, caching y recomendaciones de seguridad y rendimiento para producción.

Requisitos y preámbulos

  • Un sitio WordPress con el plugin WPGraphQL instalado y activado.
  • Acceso para añadir código PHP en tu tema o plugin (p. ej. functions.php o un plugin propio) para encolar y pasar datos al script frontend.
  • Conocimientos básicos de JavaScript y GraphQL (queries, variables, fragments).

1. ¿Cuál es el endpoint GraphQL de WPGraphQL?

Por defecto WPGraphQL expone el endpoint en:

  • /graphql (ruta relativa a la URL de tu sitio, p. ej. https://midominio.com/graphql)

El endpoint acepta peticiones POST con el body en JSON: { query: …, variables: {…} } y responde JSON con la forma estándar GraphQL: { data: …, errors: […] }.

2. Configuración básica en WordPress: encolar tu script y pasar datos

Es una práctica común pasar al script frontend la URL del endpoint y el nonce de WordPress para peticiones autenticadas. Usa wp_enqueue_script y wp_localize_script (o wp_add_inline_script) para inyectar variables.

 esc_url_raw( home_url( /graphql ) ),
            nonce      => wp_create_nonce( wp_rest ) // se puede usar para autenticación con nonce
        )
    )
}
add_action( wp_enqueue_scripts, mi_tema_enqueue_scripts )
?>

3. Ejemplo mínimo: consumir GraphQL con fetch (cliente ligero)

Este ejemplo muestra una consulta simple que pide títulos y slugs de posts. Se utiliza fetch nativo y se manejan errores básicos. Ideal para proyectos muy simples o sitios sin librerías de GraphQL.

// app.js
const GRAPHQL_URL = window.WPGRAPHQL_SETTINGS.graphqlUrl

const query = 
  query GetPosts(first: Int = 10) {
    posts(first: first) {
      nodes {
        id
        title
        slug
        date
      }
    }
  }


async function fetchGraphQL(query, variables = {}) {
  const res = await fetch(GRAPHQL_URL, {
    method: POST,
    headers: {
      Content-Type: application/json
      // X-WP-Nonce: window.WPGRAPHQL_SETTINGS.nonce // si necesitas autenticar como usuario logueado
    },
    body: JSON.stringify({ query, variables })
  })
  const json = await res.json()
  if (!res.ok  json.errors) {
    const message = json.errors ? JSON.stringify(json.errors) : res.statusText
    throw new Error(GraphQL error:    message)
  }
  return json.data
}

// Uso
fetchGraphQL(query, { first: 5 })
  .then(data => {
    console.log(Posts:, data.posts.nodes)
  })
  .catch(err => {
    console.error(err)
  })

4. Enviar encabezados de autenticación

Hay varios escenarios de autenticación dependiendo de si necesitas realizar consultas públicas o privadas:

  • Consultas públicas: No requieren autenticación.
  • Usuarios autenticados en frontend: Puedes usar el nonce de WP REST (X-WP-Nonce) para validar la sesión del usuario WPGraphQL puede respetarlo si lo configuras.
  • JWT / Token-based: Para APIs headless o apps externas es habitual usar un plugin JWT (p. ej. JWT Auth) y enviar Authorization: Bearer lttokengt.

Ejemplo enviando nonce:

const res = await fetch(GRAPHQL_URL, {
  method: POST,
  headers: {
    Content-Type: application/json,
    X-WP-Nonce: window.WPGRAPHQL_SETTINGS.nonce
  },
  body: JSON.stringify({ query, variables })
})

5. Uso de librerías: graphql-request (muy simple) y Apollo Client (completo)

graphql-request (ligero)

Instalación:

  1. npm install graphql-request

Ejemplo:

import { GraphQLClient, gql } from graphql-request

const client = new GraphQLClient(window.WPGRAPHQL_SETTINGS.graphqlUrl, {
  headers: {
    Content-Type: application/json
    // X-WP-Nonce: window.WPGRAPHQL_SETTINGS.nonce
  }
})

const query = gql
  query GetPost(id: ID!) {
    post(id: id, idType: DATABASE_ID) {
      title
      content
      date
    }
  }


const data = await client.request(query, { id: 42 })
console.log(data)

Apollo Client (cuando necesitas cache, SSR y ecosistema)

Apollo ofrece política de cache avanzada, manejo de errores, enlace de autenticación y más. Ejemplo de inicialización para frontend SPA:

import { ApolloClient, InMemoryCache, HttpLink } from @apollo/client

const httpLink = new HttpLink({
  uri: window.WPGRAPHQL_SETTINGS.graphqlUrl,
  credentials: same-origin, // para que incluya cookies cuando aplique
  headers: {
    // X-WP-Nonce: window.WPGRAPHQL_SETTINGS.nonce
  }
})

const client = new ApolloClient({
  link: httpLink,
  cache: new InMemoryCache({
    typePolicies: {
      Query: {
        fields: {
          posts: {
            // policy para paginación por cursor si lo deseas
            keyArgs: false,
            merge(existing = {}, incoming = {}) {
              return {
                ...incoming,
                nodes: [...(existing.nodes  []), ...(incoming.nodes  [])]
              }
            }
          }
        }
      }
    }
  })
})

// Uso: client.query({ query: gql..., variables: {...} })

6. Variables, fragments y consultas complejas

Siempre que uses variables evita interpolar directamente valores dentro de la string de la consulta esto mejora seguridad y reutilización. También usa fragments para evitar repetir campos.

import { gql } from @apollo/client

const postFields = gql
  fragment PostFields on Post {
    id
    title
    excerpt
    slug
    date
  }


const GET_POSTS = gql
  query GetPosts(first: Int = 10, after: String) {
    posts(first: first, after: after) {
      pageInfo {
        hasNextPage
        endCursor
      }
      nodes {
        ...PostFields
      }
    }
  }
  {postFields}

7. Paginación: cursor-based (recomendada) y page-based

WPGraphQL suele proveer paginación por cursor (relay style) con campos pageInfo/edges/nodes. Implementa lógica para solicitar más nodos usando endCursor y hasNextPage.

// ejemplo de cargar más con fetch
let after = null
async function loadMore() {
  const data = await fetchGraphQL(
    query(first: Int, after: String) {
      posts(first: first, after: after) {
        pageInfo { hasNextPage endCursor }
        nodes { id title slug }
      }
    }
  , { first: 10, after })
  // append nodes a UI...
  if (data.posts.pageInfo.hasNextPage) {
    after = data.posts.pageInfo.endCursor
  } else {
    after = null
  }
}

8. Manejo de errores y retries

GraphQL puede devolver errores en la propiedad errors además de un status HTTP 200. Siempre revisa y muestra mensajes apropiados. Para resiliencia añade reintentos exponenciales o usa librerías como retry o políticas integradas en Apollo.

async function fetchGraphQLWithRetries(query, variables = {}, retries = 3) {
  let attempt = 0
  while (attempt < retries) {
    try {
      const res = await fetch(GRAPHQL_URL, { ... })
      const json = await res.json()
      if (json.errors) throw new Error(JSON.stringify(json.errors))
      return json.data
    } catch (err) {
      attempt  
      if (attempt >= retries) throw err
      await new Promise(r => setTimeout(r, 200  attempt)) // backoff
    }
  }
}

9. CORS, cookies y same-origin

Si tu frontend no está servido desde el mismo dominio de WordPress (p. ej. app independiente), debes configurar cabeceras CORS en el servidor. Para peticiones autenticadas con cookies asegúrate de usar credentials: include o same-origin y configurar el servidor para permitirlas.

10. SSR y SSG (Next.js, Nuxt o similar)

Para renderizado en servidor, realiza las peticiones GraphQL desde el servidor (getServerSideProps / getStaticProps en Next.js) usando la URL completa del endpoint y, si usas tokens, pásalos desde variables de entorno o cookies del request. No expongas secretos en JavaScript del cliente.

// Ejemplo Next.js: getServerSideProps
export async function getServerSideProps(context) {
  const res = await fetch(process.env.WP_GRAPHQL_URL   /graphql, {
    method: POST,
    headers: { Content-Type: application/json },
    body: JSON.stringify({
      query: query { posts(first:5){ nodes{ id title slug } } }
    })
  })
  const json = await res.json()
  return { props: { posts: json.data.posts.nodes } }
}

11. Persisted queries y reducción de payload

Para reducir tamaño y mejorar seguridad, puedes usar consultas persistentes: guardas consultas en el servidor y en el cliente envías sólo un identificador. Hay plugins y soluciones para WPGraphQL que facilitan esto (p. ej. wp-graphql-persisted-queries). Otra alternativa es comprimir y minimizar consultas o usar HTTP/2.

12. Optimización y performance

  • Solicita sólo los campos necesarios (evita overfetching).
  • Implementa cache en el cliente (Apollo InMemoryCache) y en el servidor (transient caching, Varnish, CDN).
  • Usa paginación para listas grandes y lazy loading en UI.
  • Considera usar fragment caché y cachés HTTP para respuestas públicas.
  • Evita N 1 queries en resolvers personalizados: si implementas resolvers en WPGraphQL atiende el rendimiento de consultas relacionadas.

13. Seguridad: validación y limitación

  • Limita la profundidad y complejidad de las consultas si te exponen a abusos (depth limiting).
  • Rate limiting a nivel de servidor o CDN para evitar DDoS.
  • Valida y sanitiza cualquier dato que pase desde el cliente al servidor, especialmente si implementas mutaciones que alteren contenido.
  • Usa tokens y scopes para endpoints sensibles, y evita exponer credenciales en el bundle público.

14. Mutations: crear, actualizar y borrar desde JS

WPGraphQL soporta mutations para crear y modificar contenido (si el esquema y permisos lo permiten). Para mutaciones autenticadas utiliza nonce o token y el usuario debe tener permisos adecuados.

const mutation = 
  mutation CreatePost(input: CreatePostInput!) {
    createPost(input: input) {
      post {
        id
        title
        slug
      }
      clientMutationId
    }
  }


const variables = {
  input: {
    clientMutationId: abc123,
    title: Mi nuevo post desde frontend,
    content: Contenido...,
    status: PUBLISH
  }
}

const res = await fetch(GRAPHQL_URL, {
  method: POST,
  headers: {
    Content-Type: application/json,
    X-WP-Nonce: window.WPGRAPHQL_SETTINGS.nonce
  },
  body: JSON.stringify({ query: mutation, variables })
})
const json = await res.json()
if (json.errors) throw new Error(JSON.stringify(json.errors))
console.log(Post creado:, json.data.createPost.post)

15. Plugins y extensiones útiles

16. Checklist final antes de pasar a producción

  1. Verificar permisos y roles para mutations y queries privadas.
  2. Habilitar límites de complejidad y profundidad si el endpoint es público.
  3. Configurar CORS correctamente si el frontend está en otro dominio.
  4. Configurar caching (CDN, cache de GraphQL o transients).
  5. Monitorizar errores y métricas (tiempos de respuesta, tasa de errores).
  6. Minimizar la exposición de secretos en cliente usar almacenamiento seguro en servidor para tokens.

Ejemplos adicionales y casos de uso

Ejemplo: Usar graphql-request con JWT

import { GraphQLClient, gql } from graphql-request

const token = localStorage.getItem(jwt_token) // token obtenido tras login
const client = new GraphQLClient(window.WPGRAPHQL_SETTINGS.graphqlUrl, {
  headers: {
    Authorization: Bearer {token}
  }
})

const query = gqlquery { viewer { id name } }
const data = await client.request(query)
console.log(Usuario:, data.viewer)

Ejemplo: registrar un script y pasar datos seguros desde servidor

 rest_url(/graphql), // alternativa para entornos con prefijos
        nonce => wp_create_nonce(wp_rest)
    ))
}
add_action(wp_enqueue_scripts, mi_plugin_enqueue)
?>

Conclusión

Consumir WPGraphQL desde JavaScript en el frontend es directo si conoces las piezas clave: endpoint /graphql, cómo pasar headers (nonce o tokens), y la manera de estructurar las consultas y mutaciones. Elige la herramienta adecuada para tu caso: fetch o graphql-request si buscas simplicidad Apollo si necesitas caching sofisticado, gestión de estado y SSR avanzado. Prioriza seguridad (noexponer secretos), rendimiento (cache y paginación) y manejo de errores para entregar una experiencia robusta al usuario.



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *