View a markdown version of this page

Resolver - AWS AppSync GraphQL

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Resolver

Nelle sezioni precedenti, hai appreso i componenti dello schema e dell'origine dati. Ora, dobbiamo affrontare il modo in cui lo schema e le fonti di dati interagiscono. Tutto inizia con il resolver.

Un resolver è un'unità di codice che gestisce il modo in cui i dati di quel campo verranno risolti quando viene effettuata una richiesta al servizio. I resolver sono collegati a campi specifici all'interno dei tipi presenti nello schema. Sono più comunemente usati per implementare le operazioni di modifica dello stato per le operazioni sui campi di interrogazione, mutazione e sottoscrizione. Il resolver elaborerà la richiesta di un cliente, quindi restituirà il risultato, che può essere un gruppo di tipi di output come oggetti o scalari:

Runtime del resolver

In AWS AppSync, devi prima specificare un runtime per il tuo resolver. Un runtime del resolver indica l'ambiente in cui viene eseguito un resolver. Determina inoltre la lingua in cui verranno scritti i resolver. AWS AppSync attualmente supporta APPSYNC_JS per JavaScript e Velocity Template Language (VTL). Vedi le caratteristiche JavaScript di runtime per i resolver e le funzioni per o il riferimento all'utilità di template di mappatura Resolver per JavaScript VTL. https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference.html

Struttura del resolver

Code-wise, i resolver possono essere strutturati in un paio di modi. Esistono risolutori di unità e pipeline.

Risolutori di unità

Un risolutore di unità è composto da codice che definisce un singolo gestore di richieste e risposte che viene eseguito su una fonte di dati. Il gestore della richiesta accetta un oggetto di contesto come argomento e restituisce il payload della richiesta utilizzato per chiamare l'origine dati. Il gestore della risposta riceve un payload dall'origine dati con il risultato della richiesta eseguita. Il gestore della risposta trasforma il payload in una risposta GraphQL per risolvere il campo GraphQL.

La richiesta GraphQL fluisce attraverso gestori di richieste e risposte che interagiscono con l'origine dati.

Risolutori di pipeline

Quando si implementano i risolutori di pipeline, seguono una struttura generale:

  • Fase preliminare: quando il client effettua una richiesta, i dati della richiesta vengono trasmessi ai resolver per i campi dello schema utilizzati (in genere le query, le mutazioni, le sottoscrizioni). Il resolver inizierà a elaborare i dati della richiesta con un gestore before step, che consente di eseguire alcune operazioni di preelaborazione prima che i dati passino attraverso il resolver.

  • Funzione/i: dopo l'esecuzione del passaggio precedente, la richiesta viene passata all'elenco delle funzioni. La prima funzione dell'elenco verrà eseguita sull'origine dati. Una funzione è un sottoinsieme del codice del resolver contenente il proprio gestore di richieste e risposte. Un gestore di richieste prenderà i dati della richiesta ed eseguirà operazioni sull'origine dati. Il gestore della risposta elaborerà la risposta dell'origine dati prima di restituirla all'elenco. Se è presente più di una funzione, i dati della richiesta verranno inviati alla funzione successiva nell'elenco da eseguire. Le funzioni nell'elenco verranno eseguite in serie nell'ordine definito dallo sviluppatore. Una volta eseguite tutte le funzioni, il risultato finale viene passato al passaggio successivo.

  • Dopo il passaggio: l'after step è una funzione di gestione che consente di eseguire alcune operazioni finali sulla risposta della funzione finale prima di passarla alla risposta GraphQL.

Flusso di richieste GraphQL che mostra l'elaborazione sequenziale tramite funzioni di richiesta e risposta con interazioni con l'origine dei dati.

Struttura del gestore Resolver

I gestori sono in genere funzioni chiamate e: Request Response

export function request(ctx) { // Code goes here } export function response(ctx) { // Code goes here }

In un risolutore di unità, ci sarà solo un set di queste funzioni. In un pipeline resolver, ci sarà un set di queste per la fase precedente e successiva e un set aggiuntivo per funzione. Per visualizzare come potrebbe apparire, esaminiamo un tipo semplice: Query

type Query { helloWorld: String! }

Questa è una semplice query con un campo chiamato helloWorld di tipoString. Supponiamo di voler sempre che questo campo restituisca la stringa «Hello World». Per implementare questo comportamento, dobbiamo aggiungere il resolver a questo campo. In un risolutore di unità, potremmo aggiungere qualcosa del genere:

export function request(ctx) { return {} } export function response(ctx) { return "Hello World" }

requestPuò essere lasciato vuoto semplicemente perché non stiamo richiedendo o elaborando dati. Possiamo anche supporre che la nostra fonte di dati lo siaNone, il che indica che questo codice non deve eseguire alcuna chiamata. La risposta restituisce semplicemente «Hello World». Per testare questo resolver, dobbiamo fare una richiesta utilizzando il tipo di query:

query helloWorldTest { helloWorld }

Questa è una query chiamata helloWorldTest che restituisce il helloWorld campo. Una volta eseguito, anche il helloWorld field resolver esegue e restituisce la risposta:

{ "data": { "helloWorld": "Hello World" } }

Restituire costanti come questa è la cosa più semplice che si possa fare. In realtà, restituirai input, elenchi e altro ancora. Ecco un esempio più complicato:

type Book { id: ID! title: String } type Query { getBooks: [Book] }

Qui stiamo restituendo un elenco diBooks. Supponiamo di utilizzare una tabella DynamoDB per archiviare i dati dei libri. I nostri gestori potrebbero assomigliare a questo:

/** * Performs a scan on the dynamodb data source */ export function request(ctx) { return { operation: 'Scan' }; } /** * return a list of scanned post items */ export function response(ctx) { return ctx.result.items; }

La nostra richiesta utilizzava un'operazione di scansione integrata per cercare tutte le voci della tabella, memorizzava i risultati nel contesto e li passava alla risposta. La risposta ha preso gli elementi dei risultati e li ha restituiti nella risposta:

{ "data": { "getBooks": { "items": [ { "id": "abcdefgh-1234-1234-1234-abcdefghijkl", "title": "book1" }, { "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "title": "book2" }, ... ] } } }

Contesto del risolutore

In un resolver, ogni passaggio della catena di gestori deve essere a conoscenza dello stato dei dati dei passaggi precedenti. Il risultato di un gestore può essere archiviato e passato a un altro come argomento. GraphQL definisce quattro argomenti di base del resolver:

Argomenti di base del resolver Description
obj, root, parent e così via. Il risultato del genitore.
args Gli argomenti forniti al campo nella query GraphQL.
context Un valore che viene fornito a ogni resolver e contiene importanti informazioni contestuali come l'utente attualmente connesso o l'accesso a un database.
info Un valore che contiene informazioni specifiche del campo relative alla query corrente, nonché i dettagli dello schema.

In AWS AppSync, l'argomento context (ctx) può contenere tutti i dati sopra menzionati. È un oggetto creato per richiesta e contiene dati come credenziali di autorizzazione, dati sui risultati, errori, metadati della richiesta, ecc. Il contesto è un modo semplice per i programmatori di manipolare i dati provenienti da altre parti della richiesta. Prendete di nuovo questo frammento:

/** * Performs a scan on the dynamodb data source */ export function request(ctx) { return { operation: 'Scan' }; } /** * return a list of scanned post items */ export function response(ctx) { return ctx.result.items; }

Alla richiesta viene assegnato il contesto (ctx) come argomento; questo è lo stato della richiesta. Esegue una scansione di tutti gli elementi di una tabella, quindi memorizza nuovamente il risultato nel contesto inresult. Il contesto viene quindi passato all'argomento della risposta, che accede a result e ne restituisce il contenuto.

Richieste e analisi

Quando si effettua una query al servizio GraphQL, questa deve essere eseguita attraverso un processo di analisi e convalida prima di essere eseguita. La tua richiesta verrà analizzata e tradotta in un albero di sintassi astratto. Il contenuto dell'albero viene convalidato eseguendo diversi algoritmi di convalida rispetto allo schema. Dopo la fase di convalida, i nodi dell'albero vengono attraversati ed elaborati. I resolver vengono richiamati, i risultati vengono archiviati nel contesto e viene restituita la risposta. Ad esempio, prendiamo questa query:

query { Person { //object type name //scalar age //scalar } }

Stiamo tornando Person con i campi a e. name age Quando si esegue questa query, l'albero avrà un aspetto simile a questo:

Diagramma ad albero delle interrogazioni che mostra l'oggetto Person con i campi nome ed età come nodi secondari.

Dall'albero, sembra che questa richiesta cercherà Query nella radice lo schema. All'interno della query, il Person campo verrà risolto. Dagli esempi precedenti, sappiamo che questo potrebbe essere un input dell'utente, un elenco di valori, ecc. Person è molto probabilmente legato a un tipo di oggetto che contiene i campi di cui abbiamo bisogno (nameeage). Una volta trovati questi due campi secondari, vengono risolti nell'ordine indicato (nameseguito daage). Una volta che l'albero è stato completamente risolto, la richiesta è completata e verrà rispedita al cliente.