🛠 ¿Debería WordPress tener una API GraphQL en el core?
Actualización 01/05/2024: Echa un vistazo a la comparación Gato GraphQL vs WP REST API.
WordPress 5.7 saldrá pronto. Como ha sido durante muchas releases ya, la WP REST API también traerá varias nuevas características.
Entre las nuevas características, una llamó mi atención: "Image Editor Accepts a List of Modifiers".
El endpoint
/wp/v2/media/<id>/editintroducido en WordPress 5.5 vino con una API limitada que aceptaba declaraciones de rotación y crop de nivel superior. En 50124 esta API se hizo más potente y flexible aceptando un array de modificaciones en el nuevo parámetro de peticiónmodifiers.
import apiFetch from '@wordpress/api-fetch';
const data = {
modifiers: [
{
type: 'crop',
args: {
left : 0,
top : 0,
width : 80,
height: 80
}
},
{
type: 'rotate',
args: {
angle: 90
}
}
]
};
apiFetch( { data, method: 'POST', path: '/wp/v2/media/5/edit' } );Este desarrollo ha tomado un tiempo.
Primero, en WordPress 5.5, se introdujo el endpoint de edición de imágenes.
Este endpoint era inicialmente algo rígido, requiriendo pasar todos los datos juntos sobre todas las operaciones a aplicar sobre la imagen. Por ejemplo, para rotar la imagen, y modificar su tamaño, pasaríamos estos datos:
{
"x": 0,
"y": 0,
"width": 80,
"height": 80,
"rotate": 90
}Luego, en WordPress 5.6, se introdujeron las operaciones en bulk en la WP REST API.
Finalmente, en la próxima WordPress 5.7, las operaciones a aplicar sobre la imagen se han desacoplado, así que tenemos las operaciones "crop" y "rotate". Estas operaciones pueden ejecutarse por sí mismas, pero también juntas en la misma petición vía batching.
Como se vio anteriormente, pasar datos al endpoint ahora se ve mucho más elegante:
{
"modifiers": [
{
"type": "crop",
"args": {
"left" : 0,
"top" : 0,
"width" : 80,
"height": 80
}
},
{
"type": "rotate",
"args": {
"angle": 90
}
}
]
}¿Rehacer lo que ya existe?
La WP REST API no es la única API para WordPress. Hay (al menos) dos alternativas:
- GraphQL, vía WPGraphQL
- GraphQL + persisted queries, vía Gato GraphQL
(☝🏽 Este soy yo, tu anfitrión para esta entrada de blog ☝🏽)
GraphQL es un tipo de API más reciente, que sobresale en operaciones en bulk. Si usas GraphQL, no hay necesidad de gastar tiempo y energía desarrollando una solución personalizada para ellas, como es el caso para REST.
De hecho, podría verse a REST como "copiando" esta característica de GraphQL.

Soportar operaciones en bulk en la WP REST API tomó al menos 2, posiblemente 3, ciclos de release para lograr. Esto no es una cantidad insignificante de tiempo, y requirió la contribución de varias personas.
Si WordPress también pudiera hacer uso de GraphQL, y el endpoint de edición de imágenes se basara en GraphQL en lugar de REST, entonces estos contribuidores podrían trabajar en otros desarrollos.
¿No estaría WordPress mejor, y desarrollado mucho más rápido, si pudiera usar las mejores cualidades de cada API, cuando sea conveniente?
Operaciones en bulk en GraphQL
Mostraré no una, sino varias formas en las que Gato GraphQL soporta operaciones en bulk.
La primera es la más simple: añadir varios campos al root de la consulta. Por ejemplo, esta consulta loguea al usuario, y luego añade un comentario:
mutation LogUserInAndAddCommentToPost {
loginUser(
by: { credentials: { usernameOrEmail: "test", password: "pass" } }
) {
id
name
}
addCommentToCustomPost(
input: {
customPostID: 1459
commentAs: { html: "Adding a comment: bla bla bla" }
}
) {
id
content
date
}
}(Por cierto, este es el cliente GraphiQL. Aquí hay un tutorial sobre su uso.)
Ahora, estas dos operaciones se aplicaron a distintos objetos, pero queremos aplicar varias operaciones al mismo objeto.
Hagamos eso ahora: esta consulta añade dos comentarios a la misma entrada.
mutation AddTwoCommentsToPost {
firstComment: addCommentToCustomPost(
input: {
customPostID: 1459
commentAs: { html: "This is my first response" }
}
) {
id
content
date
}
secondComment: addCommentToCustomPost(
input: {
customPostID: 1459
commentAs: { html: "This is my second response" }
}
) {
id
content
date
}
}Estos dos comentarios se añadieron a una entrada ya existente. ¿Pero qué pasaría si la entrada también necesita crearse en primer lugar?
En ese caso, la consulta simple ya no funcionará, porque no sabemos el ID de la entrada aún por crear, que se necesita como argumento para las otras operaciones (fíjate en el ? en el argumento del campo):
mutation CreatePostAndAddTwoCommentsToPost {
createPost(input: { title: "Some post" }) {
id # <= I don't know what this value will be
}
addCommentToCustomPost(input: {
customPostID: ?,
commentAs: { html: "Blah blah blah" }
}) {
id
content
date
}
}Pero no desesperes, que Gato GraphQL te cubre las espaldas. ¡Proporciona no una, sino dos soluciones!

La primera es usar la característica Ejecución de múltiples consultas.
En esta consulta, ejecutamos la primera operación, exportamos su resultado vía la directiva @export, y luego inyectamos este valor como entrada a la segunda consulta:
mutation AddComment {
addCommentToCustomPost(
customPostID: 1459
commentAs: { html: "Some insightful comment" }
) {
id @export(as: "newCommentID")
content
date
}
}
mutation AddResponseToComment @depends(on: "AddComment") {
replyComment(
parentCommentID: $newCommentID
commentAs: { html: "Debunking your insightful comment" }
) {
id
date
content
parent {
id
}
}
}Más elegante aún, podemos usar Mutaciones anidadas.
En esta consulta, ejecutamos la primera operación, y anidamos la segunda operación dentro, así que se aplicará al objeto creado durante la primera operación (y luego repetir, anidando una 3ª operación, etc):
mutation AddCommentAndResponseAndResponse {
addCommentToCustomPost(
input: {
customPostID: 1459
commentAs: { html: "Some insightful comment" }
}
) {
id
content
date
reply(input: { commentAs: { html: "Debunking your insightful comment" } }) {
id
date
content
parent {
id
}
reply(input: { commentAs: { html: "No, it was right!" } }) {
id
date
content
parent {
id
}
}
}
}
}Como bonus, las operaciones en bulk pueden aplicarse no solo a una sola entidad, sino a muchas entidades a la vez, en la misma petición.
En esta consulta, los nuevos comentarios y todas sus respuestas se están añadiendo a varias entradas:
mutation AddCommentAndResponseToManyPosts {
posts(ids: [1657, 1153, 1499, 1459]) {
id
addComment(input: { commentAs: { html: "Some insightful comment" } }) {
id
content
date
reply(
input: { commentAs: { html: "Debunking your insightful comment" } }
) {
id
date
content
parent {
id
}
}
}
}
}Y el plugin tiene aún un truco más bajo la manga: usando la característica de campos embebibles, podemos personalizar el contenido pasado a cada argumento de campo, ¡usando datos del propio objeto!
En esta consulta, los comentarios contienen información del objeto sobre el cual se están creando:
mutation AddCustomCommentAndResponseToManyPosts {
posts(ids: [1657, 1153, 1499, 1459]) {
id
addComment(
input: {
commentAs: { html: "The post has ID {{ id }} and title {{ title }}" }
}
) {
id
content
date
reply(
input: {
commentAs: {
html: "The parent comment was posted on {{ dateStr(format: \"d/m/Y\") }}. Cool, right?"
}
}
) {
id
date
content
parent {
id
}
}
}
}
}Obteniendo lo mejor de REST y GraphQL cuando sea conveniente
A medida que se desarrolla y expande Full Site Editing, WordPress dependerá cada vez más de sus API(s).
Respecto a las características existentes, la REST API hasta ahora ha funcionado muy bien. No hay necesidad de reconstruir lo que no está roto.
Sin embargo, respecto a nuevas características aún por desarrollar, ¿no se beneficiaría WordPress de usar REST o GraphQL, dependiendo de lo que sea más conveniente para esa característica específica?
La respuesta es tuya...
