Iterazione e Manipolazione del Valore dei Campi
Aggiunta di meta-direttive allo schema GraphQL, per iterare e manipolare gli elementi del valore dei campi di tipo array e oggetto:
@underArrayItem@underJSONObjectProperty@underEachArrayItem@underEachJSONObjectProperty@objectClone
@underArrayItem
@underArrayItem fa in modo che la direttiva annidata venga applicata su un elemento specifico dell'array.
Nella query qui sotto, solo il primo elemento dell'array contenente i nomi delle categorie viene trasformato in maiuscolo:
query {
posts {
categoryNames
@underArrayItem(index: 0)
@strUpperCase
}
}...producendo:
{
"data": {
"posts": {
"categoryNames": [
"NEWS",
"sports"
]
}
}
}@underJSONObjectProperty
@underJSONObjectProperty fa in modo che la direttiva annidata riceva una voce dall'oggetto JSON interrogato.
Questa direttiva è particolarmente utile per estrarre e manipolare un dato desiderato dopo aver interrogato un'API esterna, che molto probabilmente avrà un tipo generico JSONObject (come quando si usa il campo funzione _sendJSONObjectItemHTTPRequest dell'estensione HTTP Client).
Nella query qui sotto, otteniamo un oggetto JSON proveniente dalla WP REST API, e usiamo @underJSONObjectProperty per manipolare la proprietà type della risposta, trasformandola in maiuscolo:
query {
postData: _sendJSONObjectItemHTTPRequest(input: {
url: "https://newapi.getpop.org/wp-json/wp/v2/posts/1/?_fields=id,type,title,date"
})
@underJSONObjectProperty(by: { key: "type" })
@strUpperCase
}Questo produrrà:
{
"data": {
"postData": {
"id": 1,
"date": "2019-08-02T07:53:57",
"type": "POST",
"title": {
"rendered": "Hello world!"
}
}
}
}Oltre a ricevere una "key" per puntare a una proprietà che si trova al primo livello dell'oggetto JSON, questa direttiva può anche ricevere un "path" per navigare all'interno della struttura interna dell'oggetto, usando . come separatore tra i livelli.
Nella query qui sotto, l'endpoint della WP REST API per un articolo fornisce la proprietà "title.rendered". Possiamo navigare fino a quel sottoelemento effettivo, e trasformarlo in casing del titolo:
query {
postData: _sendJSONObjectItemHTTPRequest(input: {
url: "https://newapi.getpop.org/wp-json/wp/v2/posts/1/?_fields=id,type,title,date"
})
@underJSONObjectProperty(by: { path: "title.rendered" })
@strTitleCase
}Questo produrrà:
{
"data": {
"postData": {
"id": 1,
"date": "2019-08-02T07:53:57",
"type": "post",
"title": {
"rendered": "HELLO WORLD!"
}
}
}
}@underEachArrayItem
@underEachArrayItem itera sugli elementi dell'array di un certo campo dell'entità interrogata, ed esegue la o le direttive annidate su ciascuno di essi.
Ad esempio, il campo Post.categoryNames è di tipo [String]. Usando @underEachArrayItem, possiamo iterare i nomi delle categorie e applicare loro la direttiva @strTranslate.
In questa query, le categorie dell'articolo vengono tradotte dall'inglese al francese:
query {
posts {
id
title
categoryNames
@underEachArrayItem
@strTranslate(
from: "en",
to: "fr"
)
}
}...producendo:
{
"data": {
"posts": [
{
"id": 662,
"title": "Explaining the privacy policy",
"categoryNames": [
"Non classé"
]
},
{
"id": 28,
"title": "HTTP caching improves performance",
"categoryNames": [
"Avancé"
]
},
{
"id": 25,
"title": "Public or Private API mode, for extra security",
"categoryNames": [
"Ressource",
"Blog",
"Avancé"
]
}
]
}
}@underEachArrayItem può passare sia l'indice che il valore dell'elemento iterato come variabile dinamica alla o alle sue direttive annidate, tramite gli arg di direttiva passIndexOnwardsAs e passValueOnwardsAs.
Questa query dimostra l'uso delle variabili dinamiche $index e $value:
{
_echo(value: ["first", "second", "third"])
@underEachArrayItem(
passIndexOnwardsAs: "index"
passValueOnwardsAs: "value"
)
@applyField(
name: "_echo"
arguments: {
value: {
index: $index,
value: $value
}
},
setResultInResponse: true
)
}Il risultato è:
{
"data": {
"_echo": [
{
"index": 0,
"value": "first"
},
{
"index": 1,
"value": "second"
},
{
"index": 2,
"value": "third"
}
]
}
}@underEachArrayItem può anche limitare le posizioni dell'array su cui iterare, tramite il param filter->by, che può accettare la voce include oppure exclude.
Questa query:
{
including: _echo([
"first",
"second",
"third"
])
@underEachArrayItem(
filter: {
by: {
include: [0, 2]
}
}
)
@strUpperCase
excluding: _echo([
"first",
"second",
"third"
])
@underEachArrayItem(
filter: {
by: {
exclude: [0, 2]
}
}
)
@strUpperCase
}...produce:
{
"data": {
"including": [
"FIRST",
"second",
"THIRD"
],
"excluding": [
"first",
"SECOND",
"third"
]
}
}@underEachJSONObjectProperty
@underEachJSONObjectProperty è simile a @underEachArrayItem, ma opera su elementi JSONObject.
In questa query, iteriamo tutte le voci dell'oggetto JSON e sostituiamo qualsiasi voce null con una stringa vuota:
{
_echo(
value: {
first: "hello",
second: "world",
third: null
}
)
@underEachJSONObjectProperty
@default(value: "")
}...producendo:
{
"data": {
"_echo": {
"first": "hello",
"second": "world",
"third": ""
}
}
}@underEachJSONObjectProperty può passare la chiave e il valore su cui sta iterando come variabile dinamica alla o alle sue direttive annidate, tramite gli arg di direttiva passKeyOnwardsAs e passValueOnwardsAs.
Questa query dimostra l'uso delle variabili dinamiche $key e $value:
{
_echo(value: {
uno: "first",
dos: "second",
tres: "third"
})
@underEachJSONObjectProperty(
passKeyOnwardsAs: "key"
passValueOnwardsAs: "value"
)
@applyField(
name: "_echo"
arguments: {
value: {
key: $key,
value: $value
}
},
setResultInResponse: true
)
}Il risultato è:
{
"data": {
"_echo": {
"uno": {
"key": "uno",
"value": "first"
},
"dos": {
"key": "dos",
"value": "second"
},
"tres": {
"key": "tres",
"value": "third"
}
}
}
}@underEachJSONObjectProperty può anche limitare le chiavi dell'oggetto JSON su cui iterare, tramite il param filter->by, che può accettare la voce includeKeys oppure excludeKeys.
Questa query:
{
includingKeys: _echo(value: {
uno: "first",
dos: "second",
tres: "third"
})
@underEachJSONObjectProperty(
filter: {
by: {
includeKeys: ["uno", "tres"]
}
}
)
@strUpperCase
excludingKeys: _echo(value: {
uno: "first",
dos: "second",
tres: "third"
})
@underEachJSONObjectProperty(
filter: {
by: {
excludeKeys: ["uno", "tres"]
}
}
)
@strUpperCase
}...produce:
{
"data": {
"includingKeys": {
"uno": "FIRST",
"dos": "second",
"tres": "THIRD"
},
"excludingKeys": {
"uno": "first",
"dos": "SECOND",
"tres": "third"
}
}
}@objectClone
Gli oggetti JSON possono essere acceduti per riferimento nei resolver dei campi (e non per copia/duplicazione dell'oggetto). In questo caso, quando l'oggetto JSON viene modificato, questa modifica sarà visibile a tutti i campi che recuperano questo oggetto JSON.
Questo è il caso del campo Block.attributes:
{
posts {
blocks(filterBy: { include: "core/heading" } ) {
attributes
}
}
}...che produce:
{
"data": {
"posts": [
{
"blocks": [
{
"attributes": {
"content": "Image Block (Full width)",
"level": 2
}
},
{
"attributes": {
"content": "Gallery Block",
"level": 2
}
}
]
}
]
}
}Nella query qui sotto, mentre originalAttributes recupera semplicemente gli attributi, transformedAttributes tradurrà anche la proprietà content in francese:
{
posts {
blocks(filterBy: { include: "core/heading" } ) {
originalAttributes: attributes
transformedAttributes: attributes
@underJSONObjectProperty(by: { key: "content" })
@strTranslate(to: "fr")
}
}
}Tuttavia, poiché l'entità Block interrogata fa riferimento allo stesso oggetto JSON sia in originalAttributes che in transformedAttributes, le trasformazioni eseguite da quest'ultimo campo influenzeranno anche il primo (questo è indipendente dall'ordine in cui appaiono nella query).
Di conseguenza, entrambi i campi vengono tradotti in francese:
{
"data": {
"posts": [
{
"blocks": [
{
"originalAttributes": {
"content": "Bloc d'image (pleine largeur)",
"level": 2
},
"transformedAttributes": {
"content": "Bloc d'image (pleine largeur)",
"level": 2
}
},
{
"originalAttributes": {
"content": "Bloc Galerie",
"level": 2
},
"transformedAttributes": {
"content": "Bloc Galerie",
"level": 2
}
}
]
}
]
}
}Possiamo evitare questo problema aggiungendo la direttiva @objectClone sul campo transformedAttributes, in modo che le modifiche vengano eseguite su un oggetto JSON clonato:
{
posts {
blocks(filterBy: { include: "core/heading" } ) {
originalAttributes: attributes
transformedAttributes: attributes
@objectClone
@underJSONObjectProperty(by: { key: "content" })
@strTranslate(to: "fr")
}
}
}...producendo:
{
"data": {
"posts": [
{
"blocks": [
{
"originalAttributes": {
"content": "Image Block (Full width)",
"level": 2
},
"transformedAttributes": {
"content": "Bloc d'image (pleine largeur)",
"level": 2
}
},
{
"originalAttributes": {
"content": "Gallery Block",
"level": 2
},
"transformedAttributes": {
"content": "Bloc Galerie",
"level": 2
}
}
]
}
]
}
}Altri esempi
In questa query, @underEachArrayItem racchiude @underJSONObjectProperty, che a sua volta racchiude @strUpperCase, trasformando la proprietà "title.rendered" in maiuscolo, per le molteplici voci di articoli ottenute tramite la WP REST API:
query {
postListData: _sendJSONObjectCollectionHTTPRequest(
url: "https://newapi.getpop.org/wp-json/wp/v2/posts/?per_page=3&_fields=id,type,title,date"
)
@underEachArrayItem
@underJSONObjectProperty(by: { path: "title.rendered" })
@strUpperCase
}...producendo:
{
"data": {
"postListData": [
{
"id": 1692,
"date": "2022-04-26T10:10:08",
"type": "post",
"title": {
"rendered": "MY BLOGROLL"
}
},
{
"id": 1657,
"date": "2020-12-21T08:24:18",
"type": "post",
"title": {
"rendered": "A TALE OF TWO CITIES – TEASER"
}
},
{
"id": 1499,
"date": "2019-08-08T02:49:36",
"type": "post",
"title": {
"rendered": "COPE WITH WORDPRESS: POST DEMO CONTAINING PLENTY OF BLOCKS"
}
}
]
}
}