AEM GraphQL API för användning med innehållsfragment graphql-api-for-use-with-content-fragments

Lär dig hur du använder innehållsfragment i Adobe Experience Manager (AEM) med AEM GraphQL API för leverans av headless-innehåll.

AEM GraphQL API som används med innehållsfragment är till stor del baserat på GraphQL-API:t med öppen källkod.

Genom att använda GraphQL API i AEM kan du effektivt leverera innehållsfragment till JavaScript-klienter i headless CMS-implementeringar:

  • Undvika iterativa API-begäranden som REST,
  • se till att leveransen begränsas till de specifika kraven,
  • Det går att skicka exakt det som behövs för återgivningen som svar på en enda API-fråga.
NOTE
GraphQL används i två (separata) scenarier i Adobe Experience Manager (AEM):

Förutsättningar prerequisites

Kunder som använder GraphQL bör installera AEM Content Fragment med GraphQL Index Package 1.0.5. Mer information finns i versionsinformationen.

GRAPHQL API graphql-api

GraphQL är:

  • "…ett frågespråk för API:er och en körningsmiljö för att utföra dessa frågor med dina befintliga data. GraphQL ger en fullständig och begriplig beskrivning av data i ditt API. Det ger kunderna möjlighet att fråga efter exakt vad de behöver och ingenting mer, gör det enklare att utveckla API:er över tid och aktiverar kraftfulla utvecklingsverktyg.".

    Se GraphQL.org

  • "… en öppen specifikation för ett flexibelt API-lager. Placera GraphQL över era befintliga backend-system så att ni kan skapa produkter snabbare än någonsin …".

    Se Utforska GraphQL.

  • "… ett datameddelande och en specifikation som utvecklats internt av Facebook 2012 innan det publicerades 2015. Det är ett alternativ till REST-baserade arkitekturer i syfte att öka utvecklarnas produktivitet och minimera mängden data som överförs. GraphQL används i produktion av hundratals organisationer av alla storlekar…"

    Se GraphQL Foundation.

Mer information om GraphQL API finns i följande avsnitt (bland annat):

Implementeringen av GraphQL för AEM baseras på GraphQL Java™-standardbibliotek. Se:

GraphQL Terminologi graphql-terminology

GraphQL använder följande:

  • Frågor

  • Scheman och typer:

    • Scheman genereras av AEM baserat på modeller för innehållsfragment.
    • Med hjälp av dina scheman kan GraphQL presentera de typer och åtgärder som är tillåtna för implementeringen av GraphQL AEM.
  • Fält

  • GraphQL-slutpunkt

    • Sökvägen i AEM som svarar på GraphQL-frågor och ger åtkomst till GraphQL-scheman.

    • Mer information finns i Aktivera GraphQL-slutpunkten.

Se (GraphQL.org) Introduktion till GraphQL för utförlig information, inklusive Bästa praxis.

GraphQL Query Types graphql-query-types

Med GraphQL kan du utföra frågor för att returnera:

AEM innehåller funktioner för att konvertera frågor (båda typerna) till beständiga frågor som cachas av Dispatcher och CDN.

GraphQL Query Best Practices (Dispatcher och CDN) graphql-query-best-practices

Beständiga frågor är den metod som rekommenderas för publiceringsinstanser som:

  • de är cachelagrade
  • de hanteras centralt av AEM
NOTE
Vanligtvis finns det ingen dispatcher/CDN på författaren, så det blir ingen prestandavinst att använda beständiga frågor där, förutom att testa dem.

GraphQL-frågor som använder förfrågningar om POST rekommenderas inte eftersom de inte cachelagras, så i en standardinstans är Dispatcher konfigurerat att blockera sådana frågor.

Även om GraphQL har stöd för GET-förfrågningar kan dessa förfrågningar få en träffgräns (till exempel längden på URL:en) som kan undvikas med beständiga frågor.

Mer information finns i Aktivera cachelagring av beständiga frågor.

NOTE
Möjligheten att utföra direkta frågor kan vara föråldrad vid något tillfälle i framtiden.

GraphiQL-gränssnitt graphiql-interface

En implementering av standardgränssnittet GraphiQL finns tillgänglig för användning med AEM GraphQL.

NOTE
GraphiQL ingår i alla miljöer med AEM (men är bara tillgängligt/synligt när du konfigurerar slutpunkterna).
I tidigare versioner behövde du ett paket för att installera GraphiQL IDE. Om du har installerat det här paketet kan det nu tas bort.

Med det här gränssnittet kan du direkt mata in och testa frågor.

Till exempel:

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

Den innehåller funktioner som syntaxmarkering, automatisk komplettering, autoföreslå, samt historik och onlinedokumentation:

Gränssnittet GraphiQL

Användningsexempel för författarmiljöer och Publish-miljöer use-cases-author-publish-environments

Användningsexemplen kan bero på vilken typ av AEM som används:

  • Publish-miljö; används för att:

    • Frågedata för JS-program (standardfall)
  • Författarmiljö, används för att:

    • Fråga efter data för"innehållshanteringssyften":

      • GraphQL i AEM är ett skrivskyddat API.
      • REST API kan användas för CR(u)D-åtgärder.

Behörigheter permission

Behörigheterna krävs för åtkomst till Assets.

GraphQL-frågor körs med tillstånd från den AEM användaren av den underliggande begäran. Om användaren inte har läsåtkomst till vissa fragment (som lagras som Assets) blir de inte en del av resultatuppsättningen.

Användaren måste också ha tillgång till en GraphQL-slutpunkt för att kunna köra GraphQL-frågor.

Schemagenerering schema-generation

GraphQL är ett typbestämt API, vilket innebär att data måste vara tydligt strukturerade och ordnade efter typ.

GraphQL-specifikationen innehåller en serie riktlinjer för hur du skapar ett robust API för att förhöra data i en viss instans. Om du vill slutföra de här riktlinjerna måste en klient hämta Schema, som innehåller alla typer som krävs för en fråga.

För innehållsfragment baseras GraphQL-scheman (struktur och typer) på Enabled Content Fragment Models och deras datatyper.

CAUTION
Alla GraphQL-scheman (härledda från modeller för innehållsfragment som har aktiverats) kan läsas via GraphQL slutpunkt.
Denna möjlighet innebär att ni måste se till att inga känsliga data är tillgängliga, eftersom de kan läcka på det här sättet. Den innehåller till exempel information som kan finnas som fältnamn i modelldefinitionen.

Om en användare till exempel har skapat en innehållsfragmentmodell med namnet Article, genererar AEM en GraphQL-typ ArticleModel. Fälten i den här typen motsvarar fälten och datatyperna som definieras i modellen. Dessutom skapas några startpunkter för frågor som arbetar med den här typen, till exempel articleByPath eller articleList.

  1. En innehållsfragmentmodell:

    Content Fragment Model for use with GraphQL

  2. Motsvarande GraphQL-schema (utdata från den automatiska dokumentationen för GraphiQL):
    GraphQL-schema baserat på innehållsfragmentmodell

    Den här bilden visar att den genererade typen ArticleModel innehåller flera fält.

    • Tre av dem har kontrollerats av användaren: author, main och referencearticle.

    • De andra fälten lades till automatiskt av AEM och representerar användbara metoder för att tillhandahålla information om ett visst innehållsfragment. I detta exempel
      (hjälpfälten) _path, _metadata, _variations.

  3. När en användare har skapat ett innehållsfragment baserat på artikelmodellen kan det sedan förhöras via GraphQL. Se till exempel Exempelfrågor (baserat på en innehållsfragmentstruktur som används med GraphQL).

I GraphQL for AEM är schemat flexibelt. Denna flexibilitet innebär att den genereras automatiskt varje gång en innehållsfragmentmodell skapas, uppdateras eller tas bort. Cacheminnen för dataschemat uppdateras också när du uppdaterar en innehållsfragmentmodell.

Tjänsten Sites GraphQL avlyssnar (i bakgrunden) alla ändringar som görs i en innehållsfragmentmodell. När uppdateringar upptäcks återskapas endast den delen av schemat. Denna optimering sparar tid och ger stabilitet.

Om du till exempel:

  1. Installera ett paket som innehåller Content-Fragment-Model-1 och Content-Fragment-Model-2:

    1. GraphQL-typer för Model-1 och Model-2 genereras.
  2. Ändra sedan Content-Fragment-Model-2:

    1. Endast GraphQL-typen Model-2 uppdateras.

    2. Model-1 är fortfarande detsamma.

NOTE
Den här informationen är viktig att notera om du vill göra satsvisa uppdateringar på modeller för innehållsfragment via REST-API:t, eller på något annat sätt.

Schemat hanteras via samma slutpunkt som GraphQL-frågorna, där klienthanteraren hanterar det faktum att schemat anropas med tillägget GQLschema. Om du till exempel utför en enkel GET-begäran på /content/cq:graphql/global/endpoint.GQLschema resulterar det i utdata från schemat med innehållstypen text/x-graphql-schema;charset=iso-8859-1.

Schemagenerering - opublicerade modeller schema-generation-unpublished-models

När innehållsfragment är kapslade kan det hända att en överordnad Content Fragment Model publiceras, men ingen refererad modell gör det.

NOTE
Det AEM användargränssnittet förhindrar detta, men om publiceringen görs programmatiskt eller med innehållspaket kan det ske.

När detta inträffar genererar AEM ett ofullständigt-schema för den överordnade innehållsfragmentmodellen. Det innebär att fragmentreferensen, som är beroende av den opublicerade modellen, tas bort från schemat.

Fält fields

Inom schemat finns det enskilda fält av två baskategorier:

  • Fält som du genererar.

    Ett urval av datatyper används för att skapa fält baserat på hur du konfigurerar innehållsfragmentmodellen. Fältnamnen hämtas från fältet Egenskapsnamn i datatypen .

    • Det finns även inställningen Återge som att ta hänsyn till, eftersom användare kan konfigurera vissa datatyper. Ett textfält med en rad kan till exempel konfigureras att innehålla flera enkelradiga texter genom att välja multifield i listrutan.
  • GraphQL för AEM genererar även flera hjälpfält.

    Dessa fält används för att identifiera ett innehållsfragment eller för att få mer information om ett innehållsfragment.

Datatyper data-types

GraphQL för AEM har stöd för en lista med typer. Alla Content Fragment Model-datatyper som stöds och motsvarande GraphQL-typer visas:

Content Fragment Model - datatyp
GraphQL Type
Beskrivning
Enkelradig text
String, [String]
Används för enkla strängar som författarnamn och platsnamn.
Flerradstext
String
Används för att skriva ut text, t.ex. brödtexten i en artikel
Nummer
Float, [Float]
Används för att visa flyttal och reguljära tal
Boolean
Boolean
Används för att visa kryssrutor → enkla sant/falskt-satser
Datum och tid
Calendar
Används för att visa datum och tid i ett ISO 8086-format. Beroende på vilken typ som valts finns det tre olika varianter att använda i AEM GraphQL: onlyDate, onlyTime, dateTime
Uppräkning
String
Används för att visa ett alternativ från en lista med alternativ som definieras när modellen skapas
Taggar
[String]
Används för att visa en lista över strängar som representerar taggar som används i AEM
Innehållsreferens
String
Används för att visa sökvägen till en annan resurs i AEM
Fragmentreferens
En modelltyp

Ett fält: Model - Modelltyp, refererad direkt

Multifält, med en refererad typ: [Model] - Array av typen Model, refererad direkt från matris

Multifält, med flera refererade typer: [AllFragmentModels] - Array med alla modelltyper, refererad från matris med unionstyp
Används för att referera till en eller flera innehållsfragment av vissa modelltyper, som definieras när modellen skapades

Hjälpfält helper-fields

Förutom datatyperna för användargenererade fält genererar GraphQL för AEM även flera hjälpfält som hjälper till att identifiera ett innehållsfragment eller att tillhandahålla ytterligare information om ett innehållsfragment.

Dessa hjälpfält är markerade med en _ som föregår vad som har definierats av användaren och vad som har genererats automatiskt.

Bana path

Sökvägsfältet används som en identifierare i AEM GraphQL. Den representerar sökvägen till Content Fragment-resursen i AEM. Den här sökvägen väljs som identifierare för ett innehållsfragment eftersom den:

  • är unikt inom AEM,
  • kan enkelt hämtas.

I följande kod visas sökvägarna för alla innehållsfragment som har skapats baserat på innehållsfragmentmodellen Person.

{
  personList {
    items {
      _path
    }
  }
}

Om du vill hämta ett enstaka innehållsfragment av en viss typ måste du också bestämma sökvägen först. Till exempel:

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

Se Exempelfråga - Ett enskilt specifikt stadsfragment.

Metadata metadata

Via GraphQL visar AEM också metadata för ett innehållsfragment. Metadata är den information som beskriver ett innehållsfragment, till exempel följande:

  • titeln på ett innehållsfragment
  • miniatyrbildssökvägen
  • beskrivningen av ett innehållsfragment
  • och det datum då den skapades, bland annat.

Eftersom metadata genereras via Schemaredigeraren och därför inte har någon specifik struktur, implementerades GraphQL-typen TypedMetaData för att visa metadata för ett innehållsfragment. TypedMetaData visar information grupperad efter följande skalärtyper:

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

Varje skalär typ representerar antingen ett namn/värde-par eller en array med namn/värde-par, där värdet för det paret är av den typ som det grupperades i.

Om du till exempel vill hämta titeln för ett innehållsfragment är den här egenskapen en String-egenskap, så du vill fråga efter alla strängmetadata:

Så här frågar du efter metadata:

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

Du kan visa alla metadata för GraphQL-typer om du visar det genererade GraphQL-schemat. Alla modelltyper har samma TypedMetaData.

NOTE
Skillnad mellan normala metadata och arraymetadata
Tänk på att både StringMetadata och StringArrayMetadata refererar till det som lagras i databasen, inte till hur du hämtar det.
Genom att anropa fältet stringMetadata får du till exempel en array med alla metadata som lagras i databasen som en String. Om du anropar stringArrayMetadata får du en array med alla metadata som lagras i databasen som String[].

Se Exempelfråga för metadata - Visa en lista över metadata för utdelade med namnet GB.

Variationer variations

Fältet _variations har implementerats för att förenkla frågor om variationer som ett innehållsfragment har. Till exempel:

{
  personByPath(_path: "/content/dam/path/to/fragment/john-doe") {
    item {
      _variations
    }
  }
}
NOTE
Fältet _variations innehåller inte någon master-variant, eftersom originaldata (som refereras till som Master i användargränssnittet) inte betraktas som en explicit variant.

Se Exempelfråga - Alla städer med en namngiven variant.

NOTE
Om den angivna variationen inte finns för ett innehållsfragment returneras originaldata (kallas även huvudvariant) som ett (reservformat) standardvärde.

GraphQL Variables graphql-variables

GraphQL tillåter att variabler placeras i frågan. Mer information finns i GraphQL-dokumentation för variabler.

Om du till exempel vill hämta alla innehållsfragment av typen Article som har en viss variation, kan du ange variabeln variation i GraphiQL.

GraphQL-variabler

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

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

GraphQL Direktiv graphql-directives

I GraphQL finns det en möjlighet att ändra frågan baserat på variabler, så kallade GraphQL-direktiv.

Där kan du till exempel inkludera fältet adventurePrice i en fråga för alla AdventureModels, baserat på variabeln includePrice.

GraphQL-direktiv

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

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

Filtrering filtering

Du kan också använda filtrering i dina GraphQL-frågor för att returnera specifika data.

Vid filtrering används en syntax som baseras på logiska operatorer och uttryck.

Den mest atomiska delen är ett enstaka uttryck som kan tillämpas på innehållet i ett visst fält. Innehållet i fältet jämförs med ett givet konstantvärde.

Följande uttryck jämför till exempel fältets innehåll med värdet some text och fungerar om innehållet är lika med värdet. Annars misslyckas uttrycket:

{
  value: "some text"
  _op: EQUALS
}

Följande operatorer kan användas för att jämföra fält med ett visst värde:

Operator
Typer
Uttrycket lyckas om …
EQUALS
String, ID, Boolean
… värdet är detsamma som innehållet i fältet
EQUALS_NOT
String, ID
… värdet är inte detsamma som innehållet i fältet
CONTAINS
String
… innehållet i fältet innehåller värdet ({ value: "mas", _op: CONTAINS } träffar Christmas, Xmas, master, …)
CONTAINS_NOT
String
… innehållet i fältet innehåller inte värdet
STARTS_WITH
ID
… ID:t börjar med ett visst värde ({ value: "/content/dam/", _op: STARTS_WITH matchar /content/dam/path/to/fragment, men inte /namespace/content/dam/something)
EQUAL
Int, Float
… värdet är detsamma som innehållet i fältet
UNEQUAL
Int, Float
… värdet är inte detsamma som innehållet i fältet
GREATER
Int, Float
… fältets innehåll är större än värdet
GREATER_EQUAL
Int, Float
… fältets innehåll är större än eller lika med värdet
LOWER
Int, Float
… fältets innehåll är lägre än värdet
LOWER_EQUAL
Int, Float
… fältets innehåll är lägre än eller lika med värdet
AT
Calendar, Date, Time
… fältets innehåll är detsamma som värdet (inklusive tidszonsinställning)
NOT_AT
Calendar, Date, Time
… innehållet i fältet är inte detsamma som värdet
BEFORE
Calendar, Date, Time
… den tidpunkt som anges av värdet ligger före den tidpunkt som anges av fältets innehåll
AT_OR_BEFORE
Calendar, Date, Time
… den tidpunkt som anges av värdet är före eller vid samma tidpunkt som anges av fältets innehåll
AFTER
Calendar, Date, Time
… tidpunkten som anges av värdet är efter tidpunkten som anges av fältets innehåll
AT_OR_AFTER
Calendar, Date, Time
… den tidpunkt som anges av värdet är efter eller vid samma tidpunkt som anges av fältets innehåll

I vissa typer kan du även ange ytterligare alternativ som ändrar hur ett uttryck utvärderas:

Alternativ
Typer
Beskrivning
_ignoreCase
String
Ignorerar skiftläget för en sträng, till exempel värdet time matchar TIME, time, tImE, …
_sensitiveness
Float
Tillåter en viss marginal för float-värden att anses vara densamma (för att kringgå tekniska begränsningar på grund av den interna representationen av float-värden). Bör undvikas eftersom det här alternativet kan ha en negativ inverkan på prestandan

Uttryck kan kombineras till en uppsättning med hjälp av en logisk operator (_logOp):

  • OR - uttrycksuppsättningen lyckas om minst ett uttryck lyckas
  • AND - uttrycksuppsättningen lyckas om alla uttryck lyckas (standard)

Varje fält kan filtreras med en egen uppsättning uttryck. Uttrycksuppsättningarna för alla fält som omnämns i filterargumentet kombineras till slut av den egna logiska operatorn.

En filterdefinition (skickas som filter-argument till en fråga) innehåller:

  • En underdefinition för varje fält (fältet kan nås via sitt namn, till exempel finns det ett lastName-fält i filtret för fältet lastName i datatypen (fältet))
  • Varje underdefinition innehåller arrayen _expressions som innehåller uttrycksuppsättningen och fältet _logOp som definierar den logiska operatorn som uttrycken ska kombineras med
  • Varje uttryck definieras av värdet (value fält) och operatorn (_operator fält) ska innehållet i ett fält jämföras med

Du kan utelämna _logOp om du vill kombinera objekt med AND och _operator om du vill kontrollera om de är lika, eftersom dessa värden är standardvärden.

I följande exempel visas en fullständig fråga som filtrerar alla personer som har lastName av Provo eller som innehåller sjö, oberoende av fallet:

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

När en GraphQL-fråga körs med valfria variabler, och ett specifikt värde inte har angetts för den valfria variabeln, ignoreras variabeln i filterutvärderingen. Det innebär att frågeresultaten innehåller alla värden, både null och inte null, för egenskapen som är relaterad till filtervariabeln.

NOTE
Om ett null-värde är explicit angivet för en sådan variabel, kommer filtret endast att matcha null-värden för motsvarande egenskap.

I frågan nedan, där inget värde har angetts för egenskapen lastName:

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

Alla författare returneras:

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

Du kan även filtrera efter kapslade fält, men det rekommenderas inte eftersom det kan leda till prestandaproblem.

Ytterligare exempel finns i:

Sortering sorting

Med den här funktionen kan du sortera frågeresultaten enligt ett angivet fält.

Sorteringskriterierna:

  • är en kommaavgränsad lista med värden som representerar fältsökvägen

    • det första fältet i listan definierar den primära sorteringsordningen

      • det andra fältet används om två värden för det primära sorteringsvillkoret är lika
      • det tredje fältet används om de första två kriterierna är lika, och så vidare.
    • punktnotation, d.v.s. field1.subfield.subfield, osv.

  • med valfri orderriktning

    • ASC (stigande) eller DESC (fallande); som standard används ASC
    • riktningen kan anges per fält. Det innebär att du kan sortera ett fält i stigande ordning och ett annat i fallande ordning (namn, firstName DESC)

Till exempel:

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

Och dessutom:

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

Du kan också sortera på ett fält i ett kapslat fragment med formatet nestedFragmentname.fieldname.

NOTE
Det här formatet kan påverka prestandan negativt.

Till exempel:

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

Sidindelning paging

Med den här funktionen kan du utföra sidindelning på frågetyper som returnerar en lista. Det finns två metoder:

  • offset och limit i en List-fråga
  • first och after i en Paginated-fråga

Listfråga - förskjutning och begränsning list-offset-limit

I en ...Listfråga kan du använda offset och limit för att returnera en viss delmängd av resultaten:

  • offset: Anger den första datauppsättningen som ska returneras
  • limit: Anger maximalt antal datauppsättningar som ska returneras

Om du till exempel vill visa en resultatsida som innehåller upp till fem artiklar, med början från den femte artikeln i resultatlistan complete :

query {
   articleList(offset: 5, limit: 5) {
    items {
      authorFragment {
        lastName
        firstName
      }
    }
  }
}
NOTE
  • Sidindelning kräver en stabil sorteringsordning för att fungera korrekt i flera frågor som begär olika sidor i samma resultatuppsättning. Som standard används databassökvägen för varje objekt i resultatuppsättningen för att säkerställa att ordningen alltid är densamma. Om en annan sorteringsordning används, och om sorteringen inte kan göras på JCR-frågenivå, så har resultatet en negativ effekt. Orsaken är att hela resultatuppsättningen måste läsas in i minnet innan sidorna bestäms.

  • Ju högre förskjutning, desto längre tid tar det att hoppa över objekten från den fullständiga JCR-frågeresultatuppsättningen. En alternativ lösning för stora resultatuppsättningar är att använda den numrerade frågan med metoden first och after.

Sidnumrerad fråga - första och efter paginated-first-after

Frågetypen ...Paginated återanvänder de flesta av ...List-frågetypsfunktionerna (filtrering, sortering), men i stället för att använda offset/limit-argument använder den first/after-argumenten som definierats av GraphQL Cursor Connections Specification. En mindre formell introduktion finns i GraphQL-introduktionen.

  • first: De n första objekten som ska returneras.
    Standardvärdet är 50.
    Det maximala antalet är 100.
  • after: Markören som bestämmer början på den begärda sidan. Det objekt som markören representerar tas inte med i resultatuppsättningen. Markören för ett objekt bestäms av fältet cursor i strukturen edges.

Du kan till exempel skriva ut en resultatsida som innehåller upp till fem äventyr, med början från markörobjektet i resultatlistan complete :

query {
    adventurePaginated(first: 5, after: "ODg1MmMyMmEtZTAzMy00MTNjLThiMzMtZGQyMzY5ZTNjN2M1") {
        edges {
          cursor
          node {
            title
          }
        }
        pageInfo {
          endCursor
          hasNextPage
        }
    }
}
NOTE
  • Som standard används UUID för databasnoden som representerar fragmentet för att säkerställa att resultatordningen alltid är densamma. När sort används används UUID implicit för att säkerställa en unik sortering, även för två objekt med identiska sorteringsnycklar.

  • På grund av interna tekniska begränsningar försämras prestanda om sortering och filtrering används i kapslade fält. Använd därför filter-/sorteringsfält som lagras på rotnivå. Den här tekniken rekommenderas också om du vill fråga efter stora sidnumrerade resultatuppsättningar.

GraphQL Persisted Queries - aktivera cachelagring i Dispatcher graphql-persisted-queries-enabling-caching-dispatcher

CAUTION
Om cachelagring i Dispatcher är aktiverat behövs inte CORS-filtret, så avsnittet kan ignoreras.

Cachelagring av beständiga frågor är inte aktiverat som standard i Dispatcher. Standardaktivering är inte möjlig eftersom kunder som använder CORS (Cross-Origin Resource Sharing) med flera ursprung måste granska och eventuellt uppdatera sin Dispatcher-konfiguration.

NOTE
Dispatcher cachelagrar inte huvudet Vary.
Cachelagring av andra CORS-relaterade rubriker kan aktiveras i Dispatcher, men kan vara otillräcklig om det finns flera CORS-ursprung.

Aktivera cachelagring av beständiga frågor enable-caching-persisted-queries

För att aktivera cachelagring av beständiga frågor krävs följande uppdateringar av Dispatcher konfigurationsfiler:

  • <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 lägger till suffixet .json i alla beständiga fråge-URL:er, så att resultatet kan cachas.
    Detta för att säkerställa att frågan uppfyller Dispatcher krav för dokument som kan cachas. Mer information finns i Hur returnerar Dispatcher dokument?
  • <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*" }
    

CORS-konfiguration i Dispatcher cors-configuration-in-dispatcher

Kunder som använder CORS-begäranden kan behöva granska och uppdatera sin CORS-konfiguration i Dispatcher.

  • Rubriken Origin får inte skickas till AEM publicera via Dispatcher:

    • Kontrollera filen clientheaders.any.
  • CORS-begäranden måste i stället utvärderas för tillåtna ursprung på Dispatcher-nivå. På så sätt säkerställs också att CORS-relaterade rubriker ställs in korrekt, på ett och samma ställe, i samtliga fall.

    • En sådan konfiguration bör läggas till i filen vhost. En exempelkonfiguration ges nedan. För enkelhetens skull har endast den korrespondensrelaterade delen angetts. Du kan anpassa den efter dina specifika användningsexempel.
    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 for AEM - i korthet graphql-extensions

Den grundläggande funktionen för frågor med GraphQL för AEM följer GraphQL standardspecifikation. Det finns några tillägg för GraphQL-frågor med AEM:

CORS-filter cors-filter

CAUTION
Om cachelagring i Dispatcher har aktiverats behövs inte CORS-filtret, så det här avsnittet kan ignoreras.
NOTE
En detaljerad översikt över CORS-resursdelningsprincipen i AEM finns i Förstå korsdomänsresursdelning (CORS).

Konfigurera en CORS-princip i kundens Git-databas för att få åtkomst till GraphQL-slutpunkten. Den här konfigurationen görs genom att en lämplig OSGi CORS-konfigurationsfil läggs till för en eller flera önskade slutpunkter.

Den här konfigurationen måste ange den betrodda webbplatsens ursprung alloworigin eller alloworiginregexp som åtkomst måste beviljas för.

Om du till exempel vill ge åtkomst till slutpunkten och den beständiga frågeslutpunkten för GraphQL för https://my.domain kan du använda:

{
  "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/.*"
  ]
}

Om du har konfigurerat en huvudsökväg för slutpunkten kan du även använda den i allowedpaths.

Referensfilter referrer-filter

Förutom CORS-konfigurationen måste ett referensfilter konfigureras så att åtkomst från tredjepartsvärdar tillåts.

Det här filtret görs genom att en lämplig konfigurationsfil för OSGi-referensfiltret läggs till:

  • anger ett betrott värdnamn för en webbplats, antingen allow.hosts eller allow.hosts.regexp,
  • ger åtkomst till det här värdnamnet.

Om du till exempel vill bevilja åtkomst för begäranden med referenten my.domain kan du:

{
    "allow.empty":false,
    "allow.hosts":[
      "my.domain"
    ],
    "allow.hosts.regexp":[
      ""
    ],
    "filter.methods":[
      "POST",
      "PUT",
      "DELETE",
      "COPY",
      "MOVE"
    ],
    "exclude.agents.regexp":[
      ""
    ]
}
CAUTION
Det är kundens ansvar att
  • endast ge åtkomst till betrodda domäner
  • se till att ingen känslig information exponeras
  • använder inte syntax för jokertecken [*]. Den här funktionen inaktiverar autentiserad åtkomst till GraphQL-slutpunkten och visar den även för hela världen.
CAUTION
Alla GraphQL scheman (härledda från modeller för innehållsfragment som har aktiverats) kan läsas via GraphQL slutpunkt.
Den här funktionen innebär att du måste se till att det inte finns några känsliga data tillgängliga eftersom de kan läcka på det här sättet. Den innehåller till exempel information som kan finnas som fältnamn i modelldefinitionen.

Begränsningar limitations

För att skydda dig mot potentiella problem finns det standardbegränsningar för dina frågor:

  • Frågan får inte innehålla fler än 1M (1024 * 1024) tecken
  • Frågan får inte innehålla fler än 15000 token
  • Frågan får inte innehålla fler än 200000 blankstegstoken

Du måste också vara medveten om:

  • Ett fältkonfliktsfel returneras när din GraphQL-fråga innehåller fält med samma namn i två (eller flera) modeller och följande villkor uppfylls:

    • Så här:

      • Två (eller flera modeller) används som möjliga referenser, när de definieras som en tillåten modelltyp i Content Fragment-referensen.

      och:

      • Dessa två modeller har fält med ett gemensamt namn, vilket betyder att samma namn används i båda modellerna.

      och

      • Dessa fält har olika datatyper.
    • Till exempel:

      • När två (eller flera) fragment med olika modeller (till exempel M1, M2) används som möjliga referenser (innehållsreferens eller fragmentreferens) från ett annat fragment, till exempel Fragment1 MultiField/List

      • Och dessa två fragment med olika modeller (M1, M2) har fält med samma namn, men olika typer.
        Så här illustrerar du:

        • M1.Title som Text
        • M2.Title som Text/MultiField
      • Ett fältkonfliktsfel uppstår sedan om GraphQL-frågan innehåller fältet Title.

Autentisering authentication

Se Autentisering för AEM GraphQL-frågor om innehållsfragment.

Vanliga frågor faqs

Frågor som har uppstått:

  1. Q: Hur skiljer sig GraphQL API för AEM från Query Builder API?

    • A:
      "AEM GraphQL API ger total kontroll över JSON-utdata och är en branschstandard för att fråga efter innehåll.
      I framtiden planerar AEM att investera i AEM GraphQL API.
      "

Självstudiekurs - Komma igång med AEM Headless och GraphQL tutorial

Söker du en praktisk självstudiekurs? Ta en titt på Komma igång med AEM Headless och GraphQL - en komplett självstudiekurs som visar hur du bygger upp och exponerar innehåll med hjälp av AEM GraphQL API:er och som används av en extern app i ett headless CMS-scenario.

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