API GraphQL AEM per l’utilizzo con Frammenti di contenuto graphql-api-for-use-with-content-fragments

Scopri come utilizzare Frammenti di contenuto in Adobe Experience Manager (AEM) con l’API GraphQL dell’AEM per la distribuzione di contenuti headless.

L’API GraphQL dell’AEM utilizzata con i Frammenti di contenuto si basa in larga misura sull’API GraphQL standard open-source.

L’utilizzo dell’API GraphQL in AEM consente la consegna efficiente di Frammenti di contenuto ai client JavaScript in implementazioni CMS headless:

  • evita richieste API iterative come con REST,
  • garantisce che la consegna sia limitata ai requisiti specifici,
  • consente la consegna in massa di ciò che è esattamente necessario per il rendering come risposta a una singola query API.
NOTE
GraphQL viene utilizzato in due scenari (separati) in Adobe Experience Manager (AEM):

Prerequisiti prerequisites

I clienti che utilizzano GraphQL devono installare il pacchetto 1.0.5 dell’indice Frammento di contenuto AEM con GraphQL. Per ulteriori dettagli, consulta le note sulla versione.

API GraphQL graphql-api

GraphQL è:

  • …un linguaggio di query per le API e un runtime per l’esecuzione di tali query con i dati esistenti. GraphQL fornisce una descrizione completa e comprensibile dei dati nell’API. Offre ai clienti la possibilità di chiedere esattamente ciò di cui hanno bisogno e nient'altro, semplifica l'evoluzione delle API nel tempo e abilita potenti strumenti per sviluppatori.".

    Vedi GraphQL.org

  • …una specifica aperta per un livello API flessibile. Posiziona GraphQL sui backend esistenti per creare prodotti più rapidamente che mai…".

    Vedi Esplorare GraphQL.

  • "…un linguaggio e una specifica di query di dati sviluppati internamente da Facebook nel 2012 prima di essere resi open source nel 2015. Offre un’alternativa alle architetture basate su REST allo scopo di aumentare la produttività degli sviluppatori e ridurre al minimo le quantità di dati trasferiti. GraphQL viene utilizzato in produzione da centinaia di organizzazioni di tutte le dimensioni…”

    Vedi GraphQL Foundation.

Per ulteriori informazioni sull’API di GraphQL, consulta le sezioni seguenti (tra molte altre risorse):

L’implementazione di GraphQL per AEM si basa sulla libreria Java™ standard di GraphQL. Consulta:

Terminologia GraphQL graphql-terminology

GraphQL utilizza quanto segue:

  • Query

  • Schemi e tipi:

    • Gli schemi vengono generati da AEM in base ai modelli di Frammenti di contenuto.
    • Utilizzando i tuoi schemi, GraphQL presenta i tipi e le operazioni consentiti per l’implementazione GraphQL per AEM.
  • Campi

  • Endpoint GraphQL

Consulta(GraphQL.org) Introduzione a GraphQL per informazioni complete, che comprendono le Best practice.

Tipi di query GraphQL graphql-query-types

Con GraphQL è possibile eseguire query per ottenere:

AEM fornisce funzionalità per convertire le query (di entrambi i tipi) in query persistenti memorizzate nella cache da Dispatcher e CDN.

Best practice per le query GraphQL (Dispatcher e CDN) graphql-query-best-practices

Le query persistenti sono il metodo consigliato da utilizzare nelle istanze di pubblicazione come:

  • vengono memorizzate nella cache;
  • sono gestiti centralmente dall’AEM
NOTE
In genere non esiste una rete Dispatcher/CDN sull’authoring, quindi non vi è alcun miglioramento delle prestazioni nell’utilizzo di query persistenti, a parte testarle.

Le query GraphQL con l’utilizzo di POST non sono consigliate in quanto non sono memorizzate nella cache. Quindi, in un’istanza predefinita, Dispatcher è configurato per bloccarle.

Anche se GraphQL supporta le richieste di GET, queste possono raggiungere dei limiti (ad esempio, la lunghezza dell’URL) che possono essere evitati utilizzando query persistenti.

Per ulteriori dettagli, vedere Abilitare la memorizzazione nella cache delle query persistenti.

NOTE
In futuro, la capacità di eseguire query dirette potrebbe diventare obsoleta.

Interfaccia GraphiQL graphiql-interface

È disponibile un'implementazione dell'interfaccia standard GraphiQL da utilizzare con AEM GraphQL.

NOTE
GraphiQL è incluso in tutti gli ambienti dell’AEM (ma è accessibile/visibile solo quando configuri gli endpoint).
Nelle versioni precedenti, era necessario un pacchetto per installare l’IDE GraphiQL. Se hai installato questo pacchetto, ora puoi rimuoverlo.

Questa interfaccia consente di inserire e testare direttamente le query.

Ad esempio:

  • http://localhost:4502/content/graphiql.html

Fornisce funzioni quali evidenziazione della sintassi, completamento automatico, suggerimento automatico, nonché una cronologia e una documentazione online:

Interfaccia di GraphiQL

Casi di utilizzo per ambienti di authoring e pubblicazione use-cases-author-publish-environments

I casi d’uso possono dipendere dal tipo di ambiente AEM:

  • ambiente di pubblicazione; utilizzato per:

    • effettuare query sui dati per l’applicazione JS (caso di utilizzo standard)
  • ambiente di authoring; utilizzato per:

    • effettuare query sui dati a “scopo di gestione dei contenuti”:

      • GraphQL nell’AEM è un’API di sola lettura.
      • L’API REST può essere utilizzata per le operazioni CR(u)D.

Autorizzazioni permission

Le autorizzazioni sono necessarie per accedere ad Assets.

Le query GraphQL vengono eseguite con l’autorizzazione dell’utente AEM della richiesta sottostante. Se l’utente non dispone dell’accesso in lettura ad alcuni frammenti (memorizzati come Assets), questi non entrano a far parte del set di risultati.

Inoltre, l’utente deve avere accesso a un endpoint GraphQL per poter eseguire query GraphQL.

Generazione schema schema-generation

GraphQL è un’API tipizzata, il che significa che i dati devono essere chiaramente strutturati e organizzati per tipo.

La specifica GraphQL fornisce una serie di linee guida su come creare una solida API per l’interrogazione dei dati su una determinata istanza. Per completare queste linee guida, un client deve recuperare lo schema, che contiene tutti i tipi necessari per una query.

Per quanto riguarda i Frammenti di contenuto, gli schemi GraphQL (struttura e tipi) sono basati su modelli di Frammenti di contenuto abilitati e i relativi tipi di dati.

CAUTION
Tutti gli schemi GraphQL (derivati dai modelli di Frammenti di contenuto che sono stati abilitati) sono leggibili attraverso l’endpoint GraphQL.
Ciò significa che devi assicurarti che non siano disponibili dati sensibili, in quanto potrebbero trapelare in questo modo. Ad esempio, include informazioni che potrebbero essere presenti come nomi di campo nella definizione del modello.

Ad esempio, se un utente ha creato un modello di frammento di contenuto denominato Article, AEM genera un tipo GraphQL ArticleModel. I campi all’interno di questo tipo corrispondono ai campi e ai tipi di dati definiti nel modello. Inoltre, crea alcuni punti di ingresso per le query che operano su questo tipo, come articleByPath o articleList.

  1. Modello di Frammento di contenuto:

    Modello di Frammento di contenuto da utilizzare con GraphQL

  2. Lo schema GraphQL corrispondente (output dalla documentazione automatica GraphiQL):
    Schema GraphQL basato su modello di Frammento di contenuto

    Questa immagine mostra che il tipo generato ArticleModel contiene diversi campi.

    • Tre di essi sono stati controllati dall'utente: author, main e referencearticle.

    • Gli altri campi sono stati aggiunti automaticamente dall’AEM e rappresentano metodi utili per fornire informazioni su un determinato frammento di contenuto. In questo esempio,
      (i campi di supporto) _path, _metadata, _variations.

  3. Un Frammento di contenuto basato sul modello di articolo creato da un utente può essere interrogato tramite GraphQL. Per esempi, consulta la sezione Query di esempio (basata su una struttura di Frammento di contenuto di esempio da utilizzare con GraphQL).

In GraphQL per AEM, lo schema è flessibile. Questa flessibilità significa che viene generata automaticamente ogni volta che viene creato, aggiornato o eliminato un modello per frammenti di contenuto. Le cache dello schema dati vengono aggiornate anche quando si rivede un modello di Frammento di contenuto.

Il servizio GraphQL di Sites ascolta (in background) le modifiche apportate a un modello di Frammento di contenuto. Quando vengono rilevati aggiornamenti, viene rigenerata solo la parte dello schema. Questa ottimizzazione consente di risparmiare tempo e garantisce stabilità.

Ad esempio, se:

  1. Installi un pacchetto contenente Content-Fragment-Model-1 e Content-Fragment-Model-2:

    1. sono generati tipi di GraphQL per Model-1 e Model-2.
  2. Poi modifica Content-Fragment-Model-2:

    1. Solo il tipo di GraphQL Model-2 viene aggiornato.

    2. Mentre Model-1 rimane lo stesso.

NOTE
Questo dettaglio è importante da notare solo nel caso in cui si desideri eseguire aggiornamenti in blocco sui modelli per frammenti di contenuto tramite l’API REST o in altro modo.

Lo schema viene gestito attraverso lo stesso endpoint delle query GraphQL, dove il client gestisce il fatto che lo schema viene chiamato con l’estensione GQLschema. Ad esempio, l'esecuzione di una semplice richiesta GET su /content/cq:graphql/global/endpoint.GQLschema genera l'output dello schema con il tipo di contenuto text/x-graphql-schema;charset=iso-8859-1.

Generazione schema: modelli non pubblicati schema-generation-unpublished-models

Quando i frammenti di contenuto sono nidificati, può accadere che venga pubblicato un modello di Frammento di contenuto principale, ma non il modello di riferimento.

NOTE
L’interfaccia utente dell’AEM impedisce che ciò accada, ma se la pubblicazione viene effettuata a livello di programmazione o con pacchetti di contenuti può verificarsi.

In questo caso, AEM genera uno schema incompleto per il modello di Frammento di contenuto padre. Significa che il Riferimento frammento, che dipende dal modello non pubblicato, viene rimosso dallo schema.

Campi fields

Nello schema sono presenti singoli campi, di due categorie di base:

  • Campi generati dall’utente.

    Per creare campi in base alla modalità di configurazione del modello di frammento di contenuto, viene utilizzata una selezione di Tipi di dati. I nomi dei campi vengono ricavati dal campo Nome proprietà del Tipo di dato.

    • È inoltre necessario prendere in considerazione l'impostazione Rendering come, in quanto gli utenti possono configurare determinati tipi di dati. Ad esempio, un campo di testo a riga singola può essere configurato per contenere più testi a riga singola scegliendo multifield dal menu a discesa.
  • GraphQL for AEM genera anche diversi campi di supporto.

    Questi campi vengono utilizzati per identificare un frammento di contenuto o per ottenere ulteriori informazioni su di esso.

Tipi di dati data-types

GraphQL per AEM supporta un elenco di tipi. Vengono rappresentati tutti i tipi di dati dei modelli di Frammento di contenuto supportati e i corrispondenti tipi GraphQL:

Modello di Frammento di contenuto: tipo di dati
Tipo GraphQL
Descrizione
Testo su riga singola
String, [String]
Utilizzato per stringhe semplici come i nomi degli autori e i nomi delle posizioni.
Testo su più righe
String
Utilizzato per l’output di testo, ad esempio il corpo di un articolo
Numero
Float, [Float]
Utilizzato per visualizzare il numero a virgola mobile e i numeri regolari
Booleano
Boolean
Utilizzato per visualizzare le caselle di controllo → semplici istruzioni true/false
Data e ora
Calendar
Utilizzato per visualizzare la data e l’ora in formato ISO 8086. A seconda del tipo selezionato, sono disponibili tre versioni da utilizzare in AEM GraphQL: onlyDate, onlyTime, dateTime
Enumerazione
String
Utilizzato per visualizzare un’opzione da un elenco di opzioni definito durante la creazione del modello
Tag
[String]
Utilizzato per visualizzare un elenco di stringhe che rappresentano tag utilizzati in AEM
Riferimento contenuto
String
Utilizzato per visualizzare il percorso per un’altra risorsa in AEM
Riferimento frammento
Un tipo di modello

Campo singolo: Model - Tipo di modello, a cui si fa riferimento direttamente

Multifield, con un tipo a cui si fa riferimento: [Model] - Array di tipo Model, a cui si fa riferimento direttamente dall'array

Multifield, con più tipi a cui si fa riferimento: [AllFragmentModels] - Array di tutti i tipi di modello, a cui si fa riferimento dall'array con tipo di unione
Utilizzato per fare riferimento a uno o più frammenti di contenuto di alcuni tipi di modelli, definiti al momento della creazione del modello

Campi di supporto helper-fields

Oltre ai tipi di dati per i campi generati dall'utente, GraphQL for AEM genera anche diversi campi helper per identificare un frammento di contenuto o per fornire informazioni aggiuntive su un frammento di contenuto.

Tali campi di supporto sono contrassegnati con un _ precedente per distinguere tra ciò che è stato definito dall’utente e ciò che è stato generato automaticamente.

Percorso path

In AEM GraphQL, il campo del percorso viene utilizzato come identificatore. Rappresenta il percorso della risorsa Frammenti di contenuto all’interno dell’archivio AEM. Questo percorso viene scelto come identificatore di un frammento di contenuto in quanto:

  • è univoco all’interno di AEM,
  • può essere facilmente recuperato.

Nel codice seguente vengono visualizzati i percorsi di tutti i frammenti di contenuto creati in base al modello per frammenti di contenuto Person.

{
  personList {
    items {
      _path
    }
  }
}

Per recuperare un singolo frammento di contenuto di un tipo specifico, devi prima determinarne il percorso. Esempio:

{
  authorByPath(_path: "/content/dam/path/to/fragment/john-doe") {
    item {
      _path
      firstName
      name
    }
  }
}

Vedi Query di esempio: un singolo frammento di città specifico.

Metadati metadata

Tramite GraphQL, AEM espone inoltre i metadati di un frammento di contenuto. I metadati sono informazioni che descrivono un frammento di contenuto, ad esempio quanto segue:

  • titolo di un frammento di contenuto
  • il percorso della miniatura
  • la descrizione di un frammento di contenuto
  • e la data di creazione, tra le altre.

Poiché i metadati vengono generati tramite l’Editor schemi e, pertanto, non dispongono di una struttura specifica, il tipo di TypedMetaData GraphQL è stato implementato per esporre i metadati di un frammento di contenuto. TypedMetaData espone le informazioni raggruppate per i seguenti tipi scalari:

Campo
stringMetadata:[StringMetadata]!
stringArrayMetadata:[StringArrayMetadata]!
intMetadata:[IntMetadata]!
intArrayMetadata:[IntArrayMetadata]!
floatMetadata:[FloatMetadata]!
floatArrayMetadata:[FloatArrayMetadata]!
booleanMetadata:[BooleanMetadata]!
booleanArrayMetadata:[booleanArrayMetadata]!
calendarMetadata:[CalendarMetadata]!
calendarArrayMetadata:[CalendarArrayMetadata]!

Ogni tipo scalare rappresenta una coppia nome-valore singola o un array di coppie nome-valore, in cui il valore di tale coppia è del tipo all'interno del quale è stato raggruppato.

Ad esempio, se desideri recuperare il titolo di un frammento di contenuto, questa proprietà è una proprietà Stringa e puoi quindi eseguire una query per tutti i metadati stringa:

Per eseguire una query per i metadati:

{
  personByPath(_path: "/content/dam/path/to/fragment/john-doe") {
    item {
      _path
      _metadata {
        stringMetadata {
          name
          value
        }
      }
    }
  }
}

Puoi visualizzare tutti i tipi di metadati GraphQL se visualizzi lo schema GraphQL generato. Tutti i tipi di modello hanno lo stesso TypedMetaData.

NOTE
Differenza tra metadati normali e quelli di array
Nota: StringMetadata e StringArrayMetadata si riferiscono a ciò che è memorizzato nell’archivio, non alla modalità di recupero.
Ad esempio, chiamando il campo stringMetadata, si riceve un array di tutti i metadati archiviati nell'archivio come String. Se si chiama stringArrayMetadata, verrà visualizzato un array di tutti i metadati archiviati nell'archivio come String[].

Vedi Query di esempio per metadati: elenca i metadati per riconoscimenti con titolo GB.

Varianti variations

Il campo _variations è stato implementato per semplificare l’esecuzione delle query sulle varianti di un frammento di contenuto. Esempio:

{
  personByPath(_path: "/content/dam/path/to/fragment/john-doe") {
    item {
      _variations
    }
  }
}
NOTE
Il campo _variations non contiene una variante master, poiché tecnicamente i dati originali (a cui si fa riferimento come Master nell'interfaccia utente) non sono considerati una variante esplicita.

Vedi Query di esempio: tutte le città con una variante denominata.

NOTE
Se per un frammento di contenuto non esiste la variante determinata, i dati originali (noti anche come variante primaria) vengono restituiti come impostazione predefinita (fallback).

Variabili GraphQL graphql-variables

GraphQL consente di inserire variabili nella query. Per ulteriori informazioni, consulta la documentazione di GraphQL per variabili.

Ad esempio, per ottenere tutti i frammenti di contenuto di tipo Article che hanno una variante specifica, puoi specificare la variabile variation in GraphiQL.

Variabili GraphQL

### query
query GetArticlesByVariation($variation: String!) {
    articleList(variation: $variation) {
        items {
            _path
            author
            _variations
        }
    }
}

### in query variables
{
    "variation": "uk"
}

Direttive GraphQL graphql-directives

In GraphQL è possibile modificare la query basata su variabili, denominate Direttive GraphQL.

Ad esempio, puoi includere il campo adventurePrice in una query per tutti i AdventureModels basati su una variabile includePrice.

Direttive GraphQL

### query
query GetAdventureByType($includePrice: Boolean!) {
  adventureList {
    items {
      adventureTitle
      adventurePrice @include(if: $includePrice)
    }
  }
}

### in query variables
{
    "includePrice": true
}

Filtro filtering

Puoi inoltre utilizzare il filtro nelle query GraphQL per restituire dati specifici.

Il filtro utilizza una sintassi basata su operatori ed espressioni di tipo logico.

La parte più atomica è una singola espressione che può essere applicata al contenuto di un determinato campo. Confronta il contenuto del campo con un valore costante specificato.

Ad esempio, l'espressione seguente confronta il contenuto del campo con il valore some text e ha esito positivo se il contenuto è uguale al valore. In caso contrario, l’espressione non riesce.:

{
  value: "some text"
  _op: EQUALS
}

Per confrontare i campi con un determinato valore è possibile utilizzare i seguenti operatori:

Operatore
Tipi
L’espressione ha esito positivo se …
EQUALS
String, ID, Boolean
… il valore è uguale al contenuto del campo
EQUALS_NOT
String, ID
… il valore not è uguale al contenuto del campo
CONTAINS
String
… il contenuto del campo contiene il valore ({ value: "mas", _op: CONTAINS } corrisponde a Christmas, Xmas, master, …)
CONTAINS_NOT
String
… il contenuto del campo non contiene il valore
STARTS_WITH
ID
… l'ID inizia con un determinato valore ({ value: "/content/dam/", _op: STARTS_WITH corrisponde a /content/dam/path/to/fragment, ma non a /namespace/content/dam/something
EQUAL
Int, Float
… il valore è uguale al contenuto del campo
UNEQUAL
Int, Float
… il valore non è uguale al contenuto del campo
GREATER
Int, Float
… il contenuto del campo è maggiore del valore
GREATER_EQUAL
Int, Float
… il contenuto del campo è maggiore o uguale al valore
LOWER
Int, Float
… il contenuto del campo è inferiore al valore
LOWER_EQUAL
Int, Float
… il contenuto del campo è inferiore o uguale al valore
AT
Calendar, Date, Time
… il contenuto del campo è uguale al valore (inclusa l’impostazione del fuso orario)
NOT_AT
Calendar, Date, Time
… il contenuto del campo non è uguale al valore
BEFORE
Calendar, Date, Time
… il punto nel tempo indicato dal valore è precedente a quello indicato dal contenuto del campo
AT_OR_BEFORE
Calendar, Date, Time
… il punto nel tempo indicato dal valore è precedente o uguale a quello indicato dal contenuto del campo
AFTER
Calendar, Date, Time
… il punto nel tempo indicato dal valore è successivo a quello indicato dal contenuto del campo
AT_OR_AFTER
Calendar, Date, Time
… il punto nel tempo indicato dal valore è successivo o uguale a quello indicato dal contenuto del campo

Alcuni tipi consentono inoltre di specificare opzioni aggiuntive che modificano la modalità di valutazione di un'espressione:

Opzione
Tipi
Descrizione
_ignoreCase
String
Ignora le maiuscole/minuscole di una stringa, ad esempio un valore di time corrisponde a TIME, time, tImE, …
_sensitiveness
Float
Consente un certo margine per valori float da considerare uguali (per aggirare i limiti tecnici dovuti alla rappresentazione interna dei valori float; dovrebbe essere evitata, in quanto questa opzione potrebbe avere un impatto negativo sulle prestazioni

Le espressioni possono essere combinate in un set tramite un operatore logico (_logOp):

  • OR - l'insieme di espressioni ha esito positivo se almeno un'espressione ha esito positivo
  • AND - l'insieme di espressioni ha esito positivo se tutte le espressioni hanno esito positivo (impostazione predefinita)

Ogni campo può essere filtrato in base al proprio set di espressioni. I set di espressioni di tutti i campi menzionati nell’argomento filtro vengono infine combinati dal proprio operatore logico.

Una definizione di filtro (passata come argomento filter a una query) contiene:

  • Sottodefinizione per ogni campo. È possibile accedere al campo tramite il nome, ad esempio è presente un campo lastName nel filtro per il campo lastName nel tipo di dati (campo)
  • Ogni sottodefinizione contiene l'array _expressions, che fornisce il set di espressioni, e il campo _logOp che definisce l'operatore logico con cui le espressioni devono essere combinate
  • Ciascuna espressione è definita dal valore (campo value) e dall’operatore (campo _operator) con cui il contenuto di un campo deve essere confrontato

È possibile omettere _logOp se si desidera combinare gli elementi con AND e _operator se si desidera verificare l'uguaglianza, poiché questi valori sono predefiniti.

L’esempio seguente illustra una query completa che filtra tutte le persone con una lastName di Provo o contenenti sjö, indipendentemente dal caso:

{
  authorList(filter: {
    lastname: {
      _logOp: OR
      _expressions: [
        {
          value: "sjö",
          _operator: CONTAINS,
          _ignoreCase: true
        },
        {
          value: "Provo"
        }
      ]
    }
  }) {
    items {
      lastName
      firstName
    }
  }
}

Quando si esegue una query GraphQL utilizzando variabili facoltative, se per la variabile facoltativa è stato fornito un valore specifico not, la variabile verrà ignorata nella valutazione del filtro. Ciò significa che i risultati della query conterranno tutti i valori, sia null che non null, per la proprietà correlata alla variabile di filtro.

NOTE
Se un valore null è specificato in modo esplicito per tale variabile, il filtro corrisponderà solo a null valori per la proprietà corrispondente.

Ad esempio, nella query seguente, dove non è specificato alcun valore per la proprietà lastName:

query getAuthorsFilteredByLastName($authorLastName: String) {
  authorList(filter:
    {
      lastName: {_expressions: {value: $authorLastName}
      }}) {
    items {
      lastName
    }
  }
}

Verranno restituiti tutti gli autori:

{
  "data": {
    "authorList": {
      "items": [
        {
          "lastName": "Hammer"
        },
        {
          "lastName": "Provo"
        },
        {
          "lastName": "Wester"
        },
        {
          "lastName": null
        },
         ...
      ]
    }
  }
}

È anche possibile filtrare i campi nidificati, ma non è consigliabile, in quanto potrebbe causare problemi di prestazioni.

Per altri esempi, consulta:

Ordinamento sorting

NOTE
Per ottenere prestazioni ottimali, è consigliabile Aggiornare i frammenti di contenuto per il paging e l'ordinamento nel filtro di GraphQL.

Questa funzione consente di ordinare i risultati della query in base a un campo specificato.

I criteri di ordinamento:

  • è un elenco di valori separati da virgole che rappresenta il percorso del campo

    • il primo campo dell'elenco definisce l'ordinamento principale

      • il secondo campo viene utilizzato se due valori del criterio di ordinamento primario sono uguali
      • il terzo campo viene utilizzato se i primi due criteri sono uguali e così via.
    • notazione punteggiata, ovvero field1.subfield.subfield e così via.

  • con una direzione d’ordine opzionale

    • ASC (crescente) o DESC (decrescente); con l’applicazione di ASC come predefinito
    • la direzione può essere specificata per campo; questa capacità significa che è possibile ordinare un campo in ordine crescente, un altro in ordine decrescente (nome, nome DESC)

Esempio:

query {
  authorList(sort: "lastName, firstName") {
    items {
      firstName
      lastName
    }
  }
}

Inoltre:

{
  authorList(sort: "lastName DESC, firstName DESC") {
    items {
        lastName
        firstName
    }
  }
}

È inoltre possibile ordinare in base a un campo all’interno di un frammento nidificato utilizzando il formato nestedFragmentname.fieldname.

NOTE
Questo formato potrebbe avere un impatto negativo sulle prestazioni.

Esempio:

query {
  articleList(sort: "authorFragment.lastName")  {
    items {
      title
      authorFragment {
        firstName
        lastName
        birthDay
      }
      slug
    }
  }
}

Paging paging

NOTE
Per ottenere prestazioni ottimali, è consigliabile Aggiornare i frammenti di contenuto per il paging e l'ordinamento nel filtro di GraphQL.

Questa funzione consente di eseguire il paging sui tipi di query che restituiscono un elenco. Vengono forniti due metodi:

  • offset e limit in una query List
  • first e after in una query Paginated

Query elenco: offset e limite list-offset-limit

In una ...Listquery puoi utilizzare offset e limit per ottenere un sottoinsieme specifico di risultati:

  • offset: specifica il primo set di dati da restituire
  • limit: specifica il numero massimo di set di dati da restituire

Ad esempio, per un output con la pagina dei risultati contenente fino a cinque articoli, a partire dal quinto articolo dell’elenco dei risultati completo:

query {
   articleList(offset: 5, limit: 5) {
    items {
      authorFragment {
        lastName
        firstName
      }
    }
  }
}
NOTE
  • Il paging richiede un ordinamento stabile per funzionare correttamente in più query che richiedono pagine diverse dello stesso set di risultati. Per impostazione predefinita, utilizza il percorso dell’archivio di ogni elemento del set di risultati per assicurarsi che l’ordine sia sempre lo stesso. Se si utilizza un ordinamento diverso e tale ordinamento non può essere eseguito a livello di query JCR, si verifica un impatto negativo sulle prestazioni. Il motivo è che l’intero set di risultati deve essere caricato in memoria prima che le pagine vengano determinate.

  • Maggiore è l’offset, maggiore sarà il tempo necessario per saltare gli elementi dal set completo dei risultati della query JCR. Una soluzione alternativa per i set di risultati di grandi dimensioni è quella di utilizzare la query impaginata con il metodo first e after.

Query impaginata: prima e dopo paginated-first-after

Il tipo di query ...Paginated riutilizza la maggior parte delle funzionalità del tipo di query ...List (filtro, ordinamento), ma invece di utilizzare gli argomenti offset/limit utilizza first/after come definiti in Specifica delle connessioni del cursore GraphQL. È possibile trovare un’introduzione meno formale in Introduzione a GraphQL.

  • first: i primi elementi n da restituire.
    Il valore predefinito è 50.
    Il massimo è 100.
  • after: cursore che determina l'inizio della pagina richiesta. L'elemento rappresentato dal cursore non è incluso nel set di risultati. Il cursore di un elemento è determinato dal campo cursor della struttura edges.

Ad esempio, restituisce la pagina dei risultati contenenti fino a cinque avventure, a partire dalla voce del cursore specificata nell’elenco dei risultati completo:

query {
    adventurePaginated(first: 5, after: "ODg1MmMyMmEtZTAzMy00MTNjLThiMzMtZGQyMzY5ZTNjN2M1") {
        edges {
          cursor
          node {
            title
          }
        }
        pageInfo {
          endCursor
          hasNextPage
        }
    }
}
NOTE
  • Per impostazione predefinita, il paging utilizza l’UUID del nodo dell’archivio che rappresenta il frammento per l’ordinamento, al fine di garantire che l’ordine dei risultati sia sempre lo stesso. Quando viene utilizzato sort, l’UUID viene utilizzato implicitamente per garantire un ordinamento univoco; anche per due elementi con chiavi di ordinamento identiche.

  • A causa di vincoli tecnici interni, le prestazioni peggiorano se l’ordinamento e il filtro vengono applicati ai campi nidificati. Pertanto, utilizza i campi di filtro/ordinamento memorizzati a livello principale. Questa tecnica è inoltre consigliata se si desidera eseguire query su set di risultati impaginati di grandi dimensioni.

Query persistenti GraphQL: abilitazione della memorizzazione in cache in Dispatcher graphql-persisted-queries-enabling-caching-dispatcher

CAUTION
Se la memorizzazione nella cache in Dispatcher è abilitata, il filtro CORS non è necessario e tale sezione può essere ignorata.

La memorizzazione nella cache delle query persistenti non è abilitata per impostazione predefinita in Dispatcher. L’abilitazione predefinita non è possibile perché i clienti che utilizzano CORS (Cross-Origin Resource Sharing) con più origini devono rivedere, e possibilmente aggiornare, la configurazione di Dispatcher.

NOTE
Dispatcher non memorizza in cache l'intestazione Vary.
La memorizzazione nella cache di altre intestazioni relative a CORS può essere abilitata in Dispatcher, ma potrebbe non essere sufficiente in presenza di più origini CORS.

Abilita la memorizzazione nella cache delle query persistenti enable-caching-persisted-queries

Per abilitare la memorizzazione nella cache delle query persistenti, sono necessari i seguenti aggiornamenti ai file di configurazione di Dispatcher:

  • <conf.d/rewrites/base_rewrite.rules>

    code language-xml
    # Allow the dispatcher to be able to cache persisted queries - they need an extension for the cache file
    RewriteCond %{REQUEST_URI} ^/graphql/execute.json
    RewriteRule ^/(.*)$ /$1;.json [PT]
    
    note note
    NOTE
    Dispatcher aggiunge il suffisso .json a tutti gli URL di query persistenti, in modo che il risultato possa essere memorizzato nella cache.
    In questo modo, la query sarà conforme ai requisiti di Dispatcher per i documenti che possono essere memorizzati in cache. Per ulteriori dettagli vedi Come vengono restituiti i documenti da Dispatcher?
  • <conf.dispatcher.d/filters/ams_publish_filters.any>

    code language-xml
    # Allow GraphQL Persisted Queries & preflight requests
    /0110 { /type "allow" /method '(GET|POST|OPTIONS)' /url "/graphql/execute.json*" }
    

Configurazione CORS in Dispatcher cors-configuration-in-dispatcher

I clienti che utilizzano richieste CORS potrebbero dover rivedere e aggiornare la configurazione CORS in Dispatcher.

  • L'intestazione Origin non deve essere passata a AEM Publish tramite Dispatcher:

    • Controllare il file clientheaders.any.
  • Al contrario, le richieste CORS devono essere valutate per le origini consentite a livello di Dispatcher. Questo approccio assicura inoltre che le intestazioni relative a CORS siano impostate correttamente, in un’unica posizione, in tutti i casi.

    • Tale configurazione deve essere aggiunta al file vhost. Di seguito è riportato un esempio di configurazione; per semplicità, è stata fornita solo la parte CORS. Puoi adattarlo ai tuoi casi d’uso specifici.
    code language-xml
    <VirtualHost *:80>
       ServerName "publish"
    
       # ...
    
       <IfModule mod_headers.c>
           Header add X-Vhost "publish"
    
            ################## Start of the CORS specific configuration ##################
    
            SetEnvIfExpr "req_novary('Origin') == ''"  CORSType=none CORSProcessing=false
            SetEnvIfExpr "req_novary('Origin') != ''"  CORSType=cors CORSProcessing=true CORSTrusted=false
    
            SetEnvIfExpr "req_novary('Access-Control-Request-Method') == '' && %{REQUEST_METHOD} == 'OPTIONS' && req_novary('Origin') != ''  " CORSType=invalidpreflight CORSProcessing=false
            SetEnvIfExpr "req_novary('Access-Control-Request-Method') != '' && %{REQUEST_METHOD} == 'OPTIONS' && req_novary('Origin') != ''  " CORSType=preflight CORSProcessing=true CORSTrusted=false
            SetEnvIfExpr "req_novary('Origin') -strcmatch 'https://%{HTTP_HOST}*'"  CORSType=samedomain CORSProcessing=false
    
            # For requests that require CORS processing, check if the Origin can be trusted
            SetEnvIfExpr "%{HTTP_HOST} =~ /(.*)/ " ParsedHost=$1
    
            ################## Adapt the regex to match CORS origin for your environment
            SetEnvIfExpr "env('CORSProcessing') == 'true' && req_novary('Origin') =~ m#(https://.*.your-domain.tld(:\d+)?$)#" CORSTrusted=true
    
            # Extract the Origin header
            SetEnvIfNoCase ^Origin$ ^https://(.*)$ CORSTrustedOrigin=https://$1
    
            # Flush If already set
            Header unset Access-Control-Allow-Origin
            Header unset Access-Control-Allow-Credentials
    
            # Trusted
            Header always set Access-Control-Allow-Credentials "true" "expr=reqenv('CORSTrusted') == 'true'"
            Header always set Access-Control-Allow-Origin "%{CORSTrustedOrigin}e" "expr=reqenv('CORSTrusted') == 'true'"
            Header always set Access-Control-Allow-Methods "GET" "expr=reqenv('CORSTrusted') == 'true'"
            Header always set Access-Control-Max-Age 1800 "expr=reqenv('CORSTrusted') == 'true'"
            Header always set Access-Control-Allow-Headers "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers" "expr=reqenv('CORSTrusted') == 'true'"
    
            # Non-CORS or Not Trusted
            Header unset Access-Control-Allow-Credentials "expr=reqenv('CORSProcessing') == 'false' || reqenv('CORSTrusted') == 'false'"
            Header unset Access-Control-Allow-Origin "expr=reqenv('CORSProcessing') == 'false' || reqenv('CORSTrusted') == 'false'"
            Header unset Access-Control-Allow-Methods "expr=reqenv('CORSProcessing') == 'false' || reqenv('CORSTrusted') == 'false'"
            Header unset Access-Control-Max-Age "expr=reqenv('CORSProcessing') == 'false' || reqenv('CORSTrusted') == 'false'"
    
            # Always vary on origin, even if its not there.
            Header merge Vary Origin
    
            # CORS - send 204 for CORS requests which are not trusted
            RewriteCond expr "reqenv('CORSProcessing') == 'true' && reqenv('CORSTrusted') == 'false'"
            RewriteRule "^(.*)" - [R=204,L]
    
            ################## End of the CORS specific configuration ##################
    
       </IfModule>
    
       <Directory />
    
           # ...
    
       </Directory>
    
       # ...
    
    </VirtualHost>
    

GraphQL per AEM: riepilogo delle estensioni graphql-extensions

Le operazioni di base delle query con GraphQL per AEM sono conformi alle specifiche standard di GraphQL. Per le query GraphQL con AEM, sono disponibili alcune estensioni:

Filtro CORS cors-filter

CAUTION
Se la memorizzazione nella cache di in Dispatcher è stata abilitata, il filtro CORS non è necessario e quindi questa sezione può essere ignorata.
NOTE
Per una panoramica dettagliata dei criteri di condivisione delle risorse CORS in AEM, vedi Comprendere la condivisione CORS.

Per accedere all’endpoint GraphQL, configura un criterio CORS nell’archivio Git del cliente. Questa configurazione viene eseguita aggiungendo un file di configurazione OSGi CORS appropriato per uno o più endpoint desiderati.

Questa configurazione deve specificare un'origine del sito Web attendibile alloworigin o alloworiginregexp per la quale deve essere consentito l'accesso.

Ad esempio, per concedere l'accesso all'endpoint GraphQL e all'endpoint delle query persistenti per https://my.domain puoi utilizzare:

{
  "supportscredentials":true,
  "supportedmethods":[
    "GET",
    "HEAD",
    "POST"
  ],
  "exposedheaders":[
    ""
  ],
  "alloworigin":[
    "https://my.domain"
  ],
  "maxage:Integer":1800,
  "alloworiginregexp":[
    ""
  ],
  "supportedheaders":[
    "Origin",
    "Accept",
    "X-Requested-With",
    "Content-Type",
    "Access-Control-Request-Method",
    "Access-Control-Request-Headers"
  ],
  "allowedpaths":[
    "/content/_cq_graphql/global/endpoint.json",
    "/graphql/execute.json/.*"
  ]
}

Se hai configurato un percorso personalizzato per l’endpoint, puoi utilizzarlo in allowedpaths.

Filtro referrer referrer-filter

Oltre alla configurazione CORS, è necessario configurare un filtro Referrer per consentire l’accesso da host di terze parti.

Questo filtro viene eseguito aggiungendo un file di configurazione del filtro di riferimento OSGi appropriato che:

  • specifica un nome host fidato del sito web; allow.hosts oppure allow.hosts.regexp,
  • concede l’accesso per questo nome host.

Ad esempio, per concedere l’accesso alle richieste con il Referrer my.domain puoi:

{
    "allow.empty":false,
    "allow.hosts":[
      "my.domain"
    ],
    "allow.hosts.regexp":[
      ""
    ],
    "filter.methods":[
      "POST",
      "PUT",
      "DELETE",
      "COPY",
      "MOVE"
    ],
    "exclude.agents.regexp":[
      ""
    ]
}
CAUTION
Spetta al cliente:
  • concedere l’accesso solo ai domini attendibili;
  • assicurarsi che non siano esposte informazioni sensibili
  • non utilizzare una sintassi con carattere jolly [*]; questa funzionalità disabilita l'accesso autenticato all'endpoint GraphQL e lo espone al mondo intero.
CAUTION
Tutti gli schemi GraphQL (derivati dai modelli per frammenti di contenuto che sono stati abilitati) sono leggibili attraverso l’endpoint GraphQL.
Questa funzionalità implica la necessità di assicurarsi che non siano disponibili dati sensibili, in quanto potrebbero trapelare in questo modo. Ad esempio, include informazioni che potrebbero essere presenti come nomi di campo nella definizione del modello.

Limitazioni limitations

Per proteggere da potenziali problemi, esistono limitazioni predefinite imposte alle query:

  • La query non può contenere più di 1 metro (1024 * 1024) di caratteri
  • La query non può contenere più di 15000 token
  • La query non può contenere più di 200000 token di spazio vuoto

È inoltre necessario essere a conoscenza di:

  • Se la query GraphQL contiene campi con lo stesso nome in due o più modelli, viene restituito un errore di conflitto di campi e vengono soddisfatte le seguenti condizioni:

    • Quindi dove:

      • Due (o più modelli) sono utilizzati come riferimenti possibili; quando sono definiti come un Tipo di modello consentito nel riferimento Frammento di contenuto.

      e:

      • Questi due modelli hanno campi con un nome comune; ciò significa che lo stesso nome si verifica in entrambi i modelli.

      e

      • Tali campi sono di tipi di dati diversi.
    • Ad esempio:

      • Quando due (o più) frammenti con modelli diversi (ad esempio, M1, M2) vengono utilizzati come possibili riferimenti (Riferimento contenuto o Riferimento frammento) da un altro frammento; ad esempio, Fragment1 MultiField/List

      • E questi due frammenti con modelli diversi (M1, M2) hanno campi con lo stesso nome, ma tipi diversi.
        Per maggiore chiarezza:

        • M1.Title come Text
        • M2.Title come Text/MultiField
      • Se la query GraphQL contiene il campo Title, si verificherà un errore di conflitto di campi.

Autenticazione authentication

Vedi Autenticazione per query GraphQL AEM remote su frammenti di contenuto.

Domande frequenti faqs

Domande poste:

  1. D: “quali sono le differenze tra l’API di GraphQL per AEM e l’API di Query Builder?

    • R:
      l’API di GraphQL per AEM offre il controllo totale dell’output JSON ed è uno standard di settore per l’esecuzione di query sui contenuti.
      In futuro, l'AEM prevede di investire nell'API GraphQL dell'AEM.
      "

Tutorial: guida introduttiva ad AEM headless e GraphQL tutorial

Cerchi un pratico tutorial? Dai un’occhiata al tutorial Guida introduttiva di AEM headless e GraphQL, che illustra come creare ed esporre contenuti, utilizzati da un’app esterna, mediante le API GraphQL di AEM in uno scenario CMS headless.

recommendation-more-help
19ffd973-7af2-44d0-84b5-d547b0dffee2