🛠 Zou WordPress een GraphQL API in de kern moeten hebben?
Update 01/05/2024: Bekijk de vergelijking Gato GraphQL vs WP REST API.
WordPress 5.7 komt binnenkort uit. Zoals bij veel eerdere releases zal de WP REST API ook diverse nieuwe functies krijgen.
Eén van die nieuwe functies trok mijn aandacht: "Image Editor Accepts a List of Modifiers".
Het endpoint
/wp/v2/media/<id>/editdat werd geïntroduceerd in WordPress 5.5 had een beperkte API die rotatie- en bijsnijddeclaraties op het hoogste niveau accepteerde. In 50124 werd deze API krachtiger en flexibeler gemaakt door een array van aanpassingen te accepteren via de nieuwemodifiersrequest-parameter.
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' } );Deze ontwikkeling was al een tijdje in de maak.
Eerst werd in WordPress 5.5 het endpoint voor het bewerken van afbeeldingen geïntroduceerd.
Dit endpoint was aanvankelijk nogal rigide: alle gegevens over alle bewerkingen op de afbeelding moesten samen worden doorgegeven. Om een afbeelding te roteren en de grootte aan te passen, stuurde je bijvoorbeeld deze data:
{
"x": 0,
"y": 0,
"width": 80,
"height": 80,
"rotate": 90
}Daarna werden in WordPress 5.6 batchbewerkingen geïntroduceerd in de WP REST API.
Tot slot werden in het aankomende WordPress 5.7 de bewerkingen op de afbeelding losgekoppeld, zodat we afzonderlijke bewerkingen "crop" en "rotate" hebben. Deze bewerkingen kunnen afzonderlijk worden uitgevoerd, maar ook samen in één request via batching.
Zoals eerder te zien, ziet het doorgeven van data aan het endpoint er nu veel eleganter uit:
{
"modifiers": [
{
"type": "crop",
"args": {
"left" : 0,
"top" : 0,
"width" : 80,
"height": 80
}
},
{
"type": "rotate",
"args": {
"angle": 90
}
}
]
}Opnieuw uitvinden wat al bestaat?
De WP REST API is niet de enige API voor WordPress. Er zijn (minstens) twee alternatieven:
- GraphQL, via WPGraphQL
- GraphQL + persistente queries, via Gato GraphQL
(☝🏽 Dat ben ik, je gastheer voor deze blogpost ☝🏽)
GraphQL is een relatief nieuw type API dat uitblinkt in batchbewerkingen. Als je GraphQL gebruikt, hoef je geen tijd en energie te steken in het ontwikkelen van een eigen oplossing daarvoor, zoals dat wel het geval is bij REST.
REST kan dus worden gezien als het "kopiëren" van deze functie van GraphQL.

Het ondersteunen van batchbewerkingen in de WP REST API vergde minstens 2, mogelijk 3 releasecycli. Dat is geen geringe hoeveelheid tijd, en het vereiste de bijdrage van verschillende mensen.
Als WordPress ook gebruik zou kunnen maken van GraphQL, en het endpoint voor afbeeldingsbewerking gebaseerd was op GraphQL in plaats van REST, zouden deze bijdragers aan andere ontwikkelingen kunnen werken.
Zou WordPress er niet beter aan toe zijn, en zou het niet veel sneller worden ontwikkeld, als het het beste van elke API kon benutten wanneer dat handig is?
Batchbewerkingen in GraphQL
Ik laat niet één, maar meerdere manieren zien waarop Gato GraphQL batchbewerkingen ondersteunt.
De eerste is de eenvoudigste: meerdere velden toevoegen aan de root van de query. Deze query logt de gebruiker in en voegt daarna een reactie toe:
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
}
}(Dit is trouwens de GraphiQL-client. Hier is een tutorial over het gebruik ervan.)
Deze twee bewerkingen werden toegepast op verschillende objecten, maar we willen meerdere bewerkingen toepassen op hetzelfde object.
Laten we dat doen: deze query voegt twee reacties toe aan dezelfde post.
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
}
}Deze twee reacties werden toegevoegd aan een al bestaande post. Maar wat als de post ook eerst aangemaakt moet worden?
In dat geval werkt de eenvoudige query niet meer, omdat we het ID van de nog-aan-te-maken post niet kennen, wat nodig is als argument voor de andere bewerkingen (let op de ? in het veldargument):
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
}
}Maar wees gerust — Gato GraphQL heeft je gedekt. Het biedt niet één, maar twee oplossingen!

De eerste is het gebruik van de functie uitvoering van meerdere queries.
In deze query voeren we de eerste bewerking uit, exporteren het resultaat via de directive @export, en injecteren die waarde vervolgens als invoer voor de tweede query:
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
}
}
}Nog eleganter is het gebruik van geneste mutaties.
In deze query voeren we de eerste bewerking uit en nesten we de tweede bewerking daarin, zodat deze wordt toegepast op het object dat tijdens de eerste bewerking is aangemaakt (en daarna herhalen we dit, met een derde bewerking genest, enzovoort):
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
}
}
}
}
}Als bonus kunnen batchbewerkingen niet alleen op één entiteit worden toegepast, maar op meerdere entiteiten tegelijk, in hetzelfde request.
In deze query worden de nieuwe reacties en al hun antwoorden toegevoegd aan meerdere posts:
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
}
}
}
}
}En de plugin heeft nog een truc achter de hand: door de functie voor ingebedde velden te gebruiken, kunnen we de inhoud die aan elk veldargument wordt doorgegeven aanpassen met gegevens van het object zelf!
In deze query bevatten de reacties informatie over het object waarop ze worden aangemaakt:
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
}
}
}
}
}Het beste van REST en GraphQL benutten wanneer het uitkomt
Nu Full Site Editing verder wordt ontwikkeld en uitgebreid, zal WordPress steeds meer afhankelijk worden van zijn API('s).
Wat bestaande functies betreft heeft de REST API het tot nu toe heel goed gedaan. Er is geen reden om te herbouwen wat niet kapot is.
Maar wat betreft nieuwe, nog te ontwikkelen functies — zou WordPress er niet baat bij hebben om afhankelijk van de situatie REST of GraphQL te kunnen gebruiken, wat het meest handig is voor die specifieke functie?
Het antwoord is aan jou...
