GraphQL - Guida rapida
GraphQL è una tecnologia lato server open source sviluppata da Facebook per ottimizzare le chiamate API RESTful. È un motore di esecuzione e un linguaggio di query dei dati. In questo capitolo, discuteremo dei vantaggi dell'utilizzo di GraphQL.
Perché GraphQL
Le API RESTful seguono un approccio orientato alle risorse chiaro e ben strutturato. Tuttavia, quando i dati diventano più complessi, i percorsi si allungano. A volte non è possibile recuperare i dati con una singola richiesta. È qui che GraphQL torna utile. GraphQL struttura i dati sotto forma di un grafico con la sua potente sintassi di query per attraversare, recuperare e modificare i dati.
Di seguito sono riportati i vantaggi dell'utilizzo del linguaggio di query GraphQL:
Chiedi quello che vuoi e prendilo
Invia una query GraphQL alla tua API e ottieni esattamente ciò di cui hai bisogno. Le query GraphQL restituiscono sempre risultati prevedibili. Le applicazioni che utilizzano GraphQL sono veloci e stabili. A differenza dei servizi Restful, queste applicazioni possono limitare i dati che dovrebbero essere recuperati dal server.
Il seguente esempio ti aiuterà a capirlo meglio:
Consideriamo un oggetto di business Student con gli attributi id, firstName, lastName e collegeName . Supponiamo che un'applicazione per dispositivi mobili debba recuperare solo firstName e id . Se progettiamo un endpoint REST come / api / v1 / students , finirà per recuperare i dati per tutti i campi per un oggetto student . Ciò significa che i dati vengono recuperati in eccesso dal servizio RESTful. Questo problema può essere risolto utilizzando GraphQL.
Considera la query GraphQL fornita di seguito:
{
students {
id
firstName
}
}
Questo restituirà valori solo per i campi id e firstname. La query non recupererà i valori per altri attributi dell'oggetto studente. La risposta alla domanda illustrata sopra è come mostrato di seguito:
{
"data": {
"students": [
{
"id": "S1001",
"firstName": "Mohtashim"
},
{
"id": "S1002",
"firstName": "Kannan"
}
]
}
}
Ottieni molte risorse in un'unica richiesta
Le query GraphQL aiutano a recuperare facilmente gli oggetti di business associati, mentre le tipiche API REST richiedono il caricamento da più URL. Le API GraphQL recuperano tutti i dati necessari alla tua applicazione in una singola richiesta. Le applicazioni che utilizzano GraphQL possono essere veloci anche su connessioni di rete mobile lente.
Consideriamo un altro oggetto aziendale, College , che ha gli attributi: nome e posizione. L' oggetto business Student ha una relazione di associazione con l'oggetto College. Se dovessimo utilizzare un'API REST per recuperare i dettagli degli studenti e del loro college, finiremo per fare due richieste al server come / api / v1 / students e / api / v1 / college . Ciò porterà a un recupero insufficiente dei dati con ogni richiesta. Pertanto, le applicazioni mobili sono costrette a effettuare più chiamate al server per ottenere i dati desiderati.
Tuttavia, l'applicazione mobile può recuperare i dettagli per gli oggetti Student e College in una singola richiesta utilizzando GraphQL.
Quella che segue è una query GraphQL per recuperare i dati:
{
students{
id
firstName
lastName
college{
name
location
}
}
}
L'output della query precedente contiene esattamente quei campi che abbiamo richiesto come mostrato di seguito -
{
"data": {
"students": [
{
"id": "S1001",
"firstName": "Mohtashim",
"lastName": "Mohammad",
"college": {
"name": "CUSAT",
"location": "Kerala"
}
},
{
"id": "S1002",
"firstName": "Kannan",
"lastName": "Sudhakaran",
"college": {
"name": "AMU",
"location": "Uttar Pradesh"
}
},
{
"id": "S1003",
"firstName": "Kiran",
"lastName": "Panigrahi",
"college": {
"name": "AMU",
"location": "Uttar Pradesh"
}
}
]
}
}
Descrivi cosa è possibile fare con un sistema di tipi
GraphQL è fortemente tipizzato e le query si basano sui campi e sui tipi di dati associati. In caso di mancata corrispondenza del tipo in una query GraphQL, le applicazioni server restituiscono messaggi di errore chiari e utili. Ciò aiuta a eseguire il debug senza problemi e a rilevare facilmente i bug da parte delle applicazioni client. GraphQL fornisce anche librerie lato client che possono aiutare a ridurre la conversione e l'analisi esplicita dei dati.
Di seguito viene fornito un esempio dei tipi di dati Student e College :
type Query {
students:[Student]
}
type Student {
id:ID!
firstName:String
lastName:String
fullName:String
college:College
}
type College {
id:ID!
name:String
location:String
rating:Float
students:[Student]
}
Muoviti più velocemente con potenti strumenti per sviluppatori
GraphQL fornisce ricchi strumenti di sviluppo per la documentazione e le query di test. GraphiQL è un ottimo strumento che genera la documentazione della query e del suo schema. Fornisce inoltre un editor di query per testare le API GraphQL e la capacità di completamento del codice intelligente durante la creazione di query.
In questo capitolo impareremo la configurazione ambientale per GraphQL. Per eseguire gli esempi in questo tutorial avrai bisogno di quanto segue:
Un computer con Linux, macOS o Windows.
Un browser web, preferibilmente l'ultima versione di Google Chrome.
È installata una versione recente di Node.js. Si consiglia l'ultima versione di LTS.
Visual Studio Code con estensione GraphQL per VSCode installata o qualsiasi editor di codice di tua scelta.
Come costruire un server GraphQL con Nodejs
Passeremo attraverso un approccio graduale dettagliato per costruire il server GraphQL con Nodejs come mostrato di seguito -
Passaggio 1: verifica delle versioni di Node e Npm
Dopo aver installato NodeJs, verificare la versione di node e npm utilizzando i seguenti comandi sul terminale:
C:\Users\Admin>node -v
v8.11.3
C:\Users\Admin>npm -v
5.6.0
Passaggio 2: creare una cartella del progetto e aprirla in VSCode
La cartella principale del progetto può essere denominata app di test.
Apri la cartella utilizzando l'editor di codice di Visual Studio utilizzando le istruzioni seguenti:
C:\Users\Admin>mkdir test-app
C:\Users\Admin>cd test-app
C:\Users\Admin\test-app>code.
Passaggio 3: creare package.json e installare le dipendenze
Creare un file package.json che conterrà tutte le dipendenze dell'applicazione del server GraphQL.
{
"name": "hello-world-server",
"private": true,
"scripts": {
"start": "nodemon --ignore data/ server.js"
},
"dependencies": {
"apollo-server-express": "^1.4.0",
"body-parser": "^1.18.3",
"cors": "^2.8.4",
"express": "^4.16.3",
"graphql": "^0.13.2",
"graphql-tools": "^3.1.1"
},
"devDependencies": {
"nodemon": "1.17.1"
}
}
Installa le dipendenze utilizzando il comando come indicato di seguito:
C:\Users\Admin\test-app>npm install
Passaggio 4: creare un database di file flat nella cartella dei dati
In questo passaggio, utilizziamo file flat per archiviare e recuperare i dati. Crea una cartella dati e aggiungi due filestudents.json e colleges.json.
Di seguito è riportato il file colleges.json file -
[
{
"id": "col-101",
"name": "AMU",
"location": "Uttar Pradesh",
"rating":5.0
},
{
"id": "col-102",
"name": "CUSAT",
"location": "Kerala",
"rating":4.5
}
]
Di seguito è riportato il file students.json file -
[
{
"id": "S1001",
"firstName":"Mohtashim",
"lastName":"Mohammad",
"email": "[email protected]",
"password": "pass123",
"collegeId": "col-102"
},
{
"id": "S1002",
"email": "[email protected]",
"firstName":"Kannan",
"lastName":"Sudhakaran",
"password": "pass123",
"collegeId": "col-101"
},
{
"id": "S1003",
"email": "[email protected]",
"firstName":"Kiran",
"lastName":"Panigrahi",
"password": "pass123",
"collegeId": "col-101"
}
]
Passaggio 5: creare un livello di accesso ai dati
Dobbiamo creare un datastore che carichi il contenuto della cartella dati. In questo caso, abbiamo bisogno di variabili di raccolta, studenti e college . Ogni volta che l'applicazione necessita di dati, utilizza queste variabili di raccolta.
Crea il file db.js con nella cartella del progetto come segue:
const { DataStore } = require('notarealdb');
const store = new DataStore('./data');
module.exports = {
students:store.collection('students'),
colleges:store.collection('colleges')
};
Passaggio 6: creare il file dello schema, schema.graphql
Crea un file schema nella cartella del progetto corrente e aggiungi i seguenti contenuti:
type Query {
test: String
}
Passaggio 7: creare un file Resolver, resolvers.js
Crea un file resolver nella cartella del progetto corrente e aggiungi i seguenti contenuti:
const Query = {
test: () => 'Test Success, GraphQL server is up & running !!'
}
module.exports = {Query}
Passaggio 8: creare Server.js e configurare GraphQL
Crea un file server e configura GraphQL come segue:
const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const db = require('./db');
const port = process.env.PORT || 9000;
const app = express();
const fs = require('fs')
const typeDefs = fs.readFileSync('./schema.graphql',{encoding:'utf-8'})
const resolvers = require('./resolvers')
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs, resolvers})
app.use(cors(), bodyParser.json());
const {graphiqlExpress,graphqlExpress} = require('apollo-server-express')
app.use('/graphql',graphqlExpress({schema}))
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
app.listen(
port, () => console.info(
`Server started on port ${port}`
)
);
Passaggio 9: eseguire l'applicazione e testare con GraphiQL
Verificare la struttura delle cartelle dell'app di test del progetto come segue:
test-app /
-->package.json
-->db.js
-->data
students.json
colleges.json
-->resolvers.js
-->schema.graphql
-->server.js
Esegui il comando npm start come indicato di seguito -
C:\Users\Admin\test-app>npm start
Il server è in esecuzione sulla porta 9000, quindi possiamo testare l'applicazione utilizzando lo strumento GraphiQL. Apri il browser e inserisci l'URL http: // localhost: 9000 / graphiql. Digita la seguente query nell'editor:
{
Test
}
Di seguito viene fornita la risposta dal server:
{
"data": {
"test": "Test Success, GraphQL server is running !!"
}
}
GraphQL è una specifica che descrive il comportamento di un server GraphQL. È un insieme di linee guida su come devono essere gestite le richieste e le risposte come i protocolli supportati, il formato dei dati che possono essere accettati dal server, il formato della risposta restituita dal server, ecc. La richiesta fatta da un client a GraphQL il server è chiamato Query. Un altro concetto importante di GraphQL è il suo livello di trasporto agnostico. Può essere utilizzato con qualsiasi protocollo di rete disponibile come TCP, websocket o qualsiasi altro protocollo di livello di trasporto. È anche neutro per i database, quindi puoi usarlo con database relazionali o NoSQL.
GraphQL Server può essere distribuito utilizzando uno dei tre metodi elencati di seguito:
- Server GraphQL con database connesso
- Server GraphQL che integra i sistemi esistenti
- Approccio ibrido
Server GraphQL con database connesso
Questa architettura ha un server GraphQL con un database integrato e può essere spesso utilizzata con nuovi progetti. Alla ricezione di una query, il server legge il payload della richiesta e recupera i dati dal database. Questo si chiama risoluzione della query. La risposta restituita al client aderisce al formato specificato nella specifica GraphQL ufficiale.
Nel diagramma sopra, il server GraphQL e il database sono integrati su un singolo nodo. Il client (desktop / mobile) comunica con il server GraphQL su HTTP. Il server elabora la richiesta, recupera i dati dal database e li restituisce al client.
GraphQL Server che integra i sistemi esistenti
Questo approccio è utile per le aziende che dispongono di infrastrutture legacy e API diverse. GraphQL può essere utilizzato per unificare microservizi, infrastruttura legacy e API di terze parti nel sistema esistente.
Nel diagramma sopra, un'API GraphQL funge da interfaccia tra il client e i sistemi esistenti. Le applicazioni client comunicano con il server GraphQL che a sua volta risolve la query.
Approccio ibrido
Infine, possiamo combinare i due approcci precedenti e creare un server GraphQL. In questa architettura, il server GraphQL risolverà qualsiasi richiesta ricevuta. Recupererà i dati dal database connesso o dalle API integrate. Questo è rappresentato nella figura seguente:
Questo capitolo discute i diversi componenti GraphQL e il modo in cui comunicano tra loro. Gli interi componenti dell'applicazione possono essere distinti come di seguito:
- Componenti lato server
- Componenti lato client
Componenti lato server
Il server GraphQL costituisce il componente principale sul lato server e consente di analizzare le query provenienti dalle applicazioni client GraphQL. Apollo Server è l'implementazione più comunemente utilizzata della specifica GraphQL. Altri componenti di programmazione del server includono quanto segue:
Sr.No. | Elementi essenziali e descrizione del server |
---|---|
1 | Schema Uno schema GraphQL è al centro di qualsiasi implementazione del server GraphQL e descrive le funzionalità disponibili per i client che si connettono ad esso. |
2 | Query Una query GraphQL è la richiesta dell'applicazione client per recuperare i dati dal database o dalle API legacy. |
3 | Resolver I resolver forniscono le istruzioni per trasformare un'operazione GraphQL in dati. Risolvono la query sui dati definendo le funzioni del resolver. |
Componenti lato client
Di seguito sono riportati i componenti lato client:
Sr.No. | Strumento e descrizione |
---|---|
1 | GraphiQL Interfaccia basata su browser per la modifica e il test di query e mutazioni GraphQL. |
2 | ApolloClient Il miglior strumento per creare applicazioni client GraphQL. Si integra bene con tutto il front-end javascript. |
Il diagramma seguente mostra un file Client-Server architecture. Il server web è costruito su NodeJs e framework Express. Viene effettuata una richiesta al server Apollo GraphQL dall'applicazione ReactJS (creata utilizzando la libreria client Apollo) o dall'applicazione browser GraphiQL. La query verrà analizzata e convalidata rispetto a uno schema definito nel server. Se lo schema della richiesta supera la convalida, verranno eseguite le funzioni di risoluzione associate. Il resolver conterrà il codice per recuperare i dati da un'API o da un database.
In questo capitolo, creeremo una semplice API che restituisce un messaggio di saluto, HelloWorld, e vi accediamo utilizzando GraphiQL.
Esempio
Questo esempio è basato su NodeJS, Express e Apollo server. Impareremo a mettere insieme tutti i concetti con i seguenti passaggi:
Passaggio 1: configurazione di Express
ExpressJS è un framework per applicazioni web che aiuta a creare siti web e applicazioni web. In questo esempio, costruiremo un'API GraphQL sopra il framework Express.
Il prossimo passo è creare una cartella hello-world-servere vai alla stessa cartella dal terminale. Aggiungi package.json e dai un nome al pacchetto. Poiché questo pacchetto viene utilizzato solo internamente, possiamo dichiararlo privato.
{
"name":"hello-world-server",
"private":true
}
Installa le dipendenze per il server Express come mostrato di seguito:
C:\Users\Admin\hello-world-server>npm install express body-parser cors
body-parser è un pacchetto middleware che aiuta Express a gestire le richieste HTTP Post in modo efficiente. cors è un altro pacchetto middleware che gestisce la condivisione di risorse tra le origini.
Creare un server.js file all'interno della cartella del progetto e digita quanto segue:
const bodyParser = require('body-parser')
const cors = require('cors')
const express = require('express')
const port = process.env.PORT|| 9000
const app = express()
//register middleware
app.use(bodyParser.json() , cors())
app.listen(port, () => console.log(`server is up and running at ${port}`)
Per verificare se il server Express è attivo e in esecuzione, eseguire il codice seguente nella finestra del terminale:
C:\Users\Admin\hello-world-server>node server.js
Il seguente output viene visualizzato nella console del server. Ciò mostra che il server Express è in esecuzione sulla porta 9000.
server is up and running at 9000
Se apri il browser e digiti http://localhost:9000, otterrai la seguente schermata:
Per arrestare il server, premere Ctrl + C.
Passaggio 2: installare GraphQL e Apollo Server
Ora che Express è configurato, il passaggio successivo consiste nel scaricare le seguenti dipendenze GraphQL:
- graphql
- graphql-tools
- apollo-server-express@1
Useremo Apollo server v1.0 poiché è una versione stabile. Digita i seguenti comandi per installare queste dipendenze:
C:\Users\Admin\hello-world-server>npm install graphql graphql-tools apollo-server-express@1
Possiamo verificare se queste dipendenze sono state installate correttamente controllando il file package.json file che abbiamo creato in precedenza.
{
"name": "hello-world-server",
"private": true,
"dependencies": {
"apollo-server-express": "^1.4.0",
"body-parser": "^1.18.3",
"cors": "^2.8.4",
"express": "^4.16.3",
"graphql": "^0.13.2",
"graphql-tools": "^3.1.1"
}
}
Passaggio 3: definire lo schema
Uno schema GraphQL definisce quale tipo di oggetto può essere recuperato da un servizio e quali campi ha. Lo schema può essere definito utilizzandoGraphQL Schema Definition Language. Ora aggiungi il seguente frammento di codice nel fileserver.js file -
// Adding Type Definitions
const typeDefinition = `
type Query {
greeting: String
}
In questo caso, la query contiene un attributo di saluto che restituisce un valore stringa .
Passaggio 4: creare un resolver
Il primo passo nella creazione di un resolver è aggiungere del codice per elaborare la richiesta del campo di saluto. Questo è specificato in un fileresolver. La struttura della funzione resolver deve corrispondere allo schema. Aggiungi il seguente frammento di codice nel fileserver.js file.
// Adding resolver
const resolverObject = {
Query : {
greeting: () => 'Hello GraphQL From TutorialsPoint !!'
}
}
Il secondo passo è associare lo schema e il resolver usando makeExecutableSchema. Questa funzione è predefinita nel modulo graphql-tools. Aggiungi il seguente frammento di codice nel file server.js file.
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs:typeDefinition, resolvers:resolverObject})
Passaggio 5: definire i percorsi per recuperare i dati dall'applicazione ReactJS / GraphiQL
Aggiungi il seguente frammento di codice nel file server.js file -
const {graphqlExpress, graphiqlExpress} = require('apollo-server-express')
//create routes for graphql and graphiql
app.use('/graphql',graphqlExpress({schema}))
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
La funzione graphqlExpress aiuta a registrare la rottahttp://localhost:9000/graphql. L'applicazione ReactJS può utilizzare questo endpoint per eseguire query sui dati. Allo stesso modo, la funzione graphqliExpress aiuta a registrare la rottahttp://localhost:9000/graphiql. Questo verrà utilizzato dal client del browser GraphiQL per testare l'API.
Il codice server.js completo è come indicato di seguito:
const bodyParser = require('body-parser')
const cors = require('cors')
const express = require('express')
const port = process.env.PORT||9000
const app = express()
app.use(bodyParser.json() , cors())
const typeDefinition = `
type Query {
greeting: String
}`
const resolverObject = {
Query : {
greeting: () => 'Hello GraphQL From TutorialsPoint !!'
}
}
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs:typeDefinition, resolvers:resolverObject})
const {graphqlExpress,graphiqlExpress} = require('apollo-server-express')
app.use('/graphql',graphqlExpress({schema}))
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
app.listen(port, () => console.log(`server is up and running ${port}`))
Passaggio 6: avviare l'applicazione
Eseguire server.js utilizzando Node.js come segue -
C:\Users\Admin\hello-world-server>node server.js
Passaggio 7: testare l'API GraphQL
Apri il browser e digita http://localhost:9000/graphiql. Nella scheda query di GraphiQL, inserisci quanto segue:
{
greeting
}
Di seguito viene fornita la risposta dal server:
{
"data": {
"greeting": "Hello GraphQL From TutorialsPoint !!"
}
}
L'immagine seguente illustra la risposta:
Note - Assicurati di utilizzare Apollo Server versione 1.0.
GraphQL è un linguaggio fortemente tipizzato. Type System definisce vari tipi di dati che possono essere utilizzati in un'applicazione GraphQL. Il sistema di tipi aiuta a definire lo schema, che è un contratto tra client e server. I tipi di dati GraphQL comunemente usati sono i seguenti:
Sr.No. | Tipi e descrizione |
---|---|
1 | Scalar Memorizza un singolo valore |
2 | Object Mostra il tipo di oggetto che può essere recuperato |
3 | Query Tipo di punto di ingresso ad altri tipi specifici |
4 | Mutation Punto di ingresso per la manipolazione dei dati |
5 | Enum Utile in una situazione in cui è necessario che l'utente scelga da un elenco prestabilito di opzioni |
Tipo scalare
I tipi scalari sono tipi di dati primitivi che possono memorizzare solo un singolo valore. I tipi scalari predefiniti offerti da GraphQL sono:
Int - Intero a 32 bit firmato
Float - Valore in virgola mobile a doppia precisione con segno
String - UTF: sequenza di 8 caratteri
Boolean - Vero o falso
ID - Un identificatore univoco, spesso utilizzato come identificatore univoco per recuperare un oggetto o come chiave per una cache.
La sintassi per definire un tipo scalare è la seguente:
field: data_type
Lo snippet fornito di seguito definisce un campo denominato saluto che restituisce un valore stringa.
greeting: String
Tipo di oggetto
Il tipo di oggetto è il tipo più comune utilizzato in uno schema e rappresenta un gruppo di campi. Ogni campo all'interno di un tipo di oggetto viene mappato a un altro tipo, consentendo così tipi nidificati. In altre parole, un tipo di oggetto è composto da più tipi scalari o tipi di oggetto.
Di seguito viene fornita la sintassi per definire un tipo di oggetto:
type object_type_name
{
field1: data_type
field2:data_type
....
fieldn:data_type
}
Puoi considerare il seguente frammento di codice:
--Define an object type--
type Student {
stud_id:ID
firstname: String
age: Int
score:Float
}
--Defining a GraphQL schema--
type Query
{
stud_details:[Student]
}
L'esempio sopra riportato definisce un oggetto di tipo di dati Student. Il campo stud_details nello schema Query radice restituirà un elenco di oggetti Student.
Tipo di query
Una query GraphQL viene utilizzata per recuperare i dati. È come richiedere una risorsa nelle API basate su REST. Per semplificare, il tipo di query è la richiesta inviata da un'applicazione client al server GraphQL. GraphQL utilizza l'estensioneSchema Definition Language (SDL)per definire una query. Il tipo di query è uno dei tanti tipi a livello di root in GraphQL.
La sintassi per la definizione di una query è la seguente:
type Query {
field1: data_type
field2:data_type
field2(param1:data_type,param2:data_type,...paramN:data_type):data_type
}
Un esempio di definizione di una query:
type Query {
greeting: String
}
Tipo di mutazione
Le mutazioni sono operazioni inviate al server a create, update o deletedati. Questi sono analoghi ai verbi PUT, POST, PATCH e DELETE per chiamare API basate su REST.
La mutazione è uno dei tipi di dati a livello di radice in GraphQL. Il tipo Query definisce i punti di ingresso per le operazioni di recupero dei dati mentre il tipo Mutazione specifica i punti di ingresso per le operazioni di manipolazione dei dati.
Di seguito viene fornita la sintassi per definire un tipo di mutazione:
type Mutation {
field1: data_type
field2(param1:data_type,param2:data_type,...paramN:data_type):data_type
}
Ad esempio, possiamo definire un tipo di mutazione per aggiungere un nuovo Studente come di seguito:
type Mutation {
addStudent(firstName: String, lastName: String): Student
}
Tipo di enumerazione
Un Enum è simile a un tipo scalare. Le enumerazioni sono utili in una situazione in cui il valore di un campo deve provenire da un elenco di opzioni prescritto.
La sintassi per definire un tipo Enum è:
type enum_name{
value1
value2
}
Il frammento di codice seguente illustra come definire un tipo di enumerazione:
type Days_of_Week{
SUNDAY
MONDAY
TUESDAY
WEDNESDAY
THURSDAY
FRIDAY
SATURDAY
}
Tipo di elenco
Gli elenchi possono essere utilizzati per rappresentare una matrice di valori di tipo specifico. Gli elenchi sono definiti con un modificatore di tipo [] che racchiude tipi di oggetto, scalari ed enumerazioni.
La seguente sintassi può essere utilizzata per definire un tipo di elenco:
field:[data_type]
L'esempio seguente definisce un tipo di elenco todos -
type Query {
todos: [String]
}
Tipo non annullabile
Per impostazione predefinita, ciascuno dei tipi scalari principali può essere impostato su null. In altre parole, questi tipi possono restituire un valore del tipo specificato oppure non possono avere alcun valore. Per sovrascrivere questo valore predefinito e specificare che un campo deve essere definito, è possibile aggiungere un punto esclamativo (!) A un tipo. Ciò garantisce la presenza di valore nei risultati restituiti dalla query.
La seguente sintassi può essere utilizzata per definire un campo non annullabile:
field:data_type!
Nell'esempio seguente, stud_id è dichiarato come campo obbligatorio.
type Student {
stud_id:ID!
firstName:String
lastName:String
fullName:String
college:College
}
Uno schema GraphQL è al centro di qualsiasi implementazione del server GraphQL. Descrive le funzionalità disponibili per le applicazioni client che si connettono ad esso. Possiamo usare qualsiasi linguaggio di programmazione per creare uno schema GraphQL e costruire un'interfaccia attorno ad esso.
Il runtime di GraphQL definisce uno schema generico basato su grafici per pubblicare le capacità del servizio dati che rappresenta. Le applicazioni client possono interrogare lo schema nell'ambito delle sue capacità. Questo approccio separa i client dai server e consente sia l'evoluzione che la scalabilità in modo indipendente.
In questo capitolo, utilizziamo il server Apollo per eseguire query GraphQL. IlmakeExecutableSchema la funzione in graphql-tools ti aiuta a legare schema e risolutori.
Sintassi della funzione makeExecutableSchema
Il makeExecutableSchemafunzione accetta un singolo argomento {} di tipo Object. La sintassi per l'utilizzo di questa funzione è fornita di seguito:
import { makeExecutableSchema } from 'graphql-tools';
const jsSchema = makeExecutableSchema({
typeDefs,
resolvers, // optional
logger, // optional
allowUndefinedInResolve = false, // optional
resolverValidationOptions = {}, // optional
directiveResolvers = null, // optional
schemaDirectives = null, // optional
parseOptions = {}, // optional
inheritResolversFromInterfaces = false // optional
});
Sr.No. | Parametro e descrizione |
---|---|
1 | typeDefs Questo è un argomento obbligatorio. Rappresenta una query GraphQL come una stringa UTF-8. |
2 | Resolvers Questo è un argomento opzionale (oggetto vuoto per impostazione predefinita). Questo ha funzioni che gestiscono la query. |
3 | logger Questo è un argomento facoltativo e può essere utilizzato per stampare gli errori sulla console del server. |
4 | parseOptions Questo è un argomento facoltativo e consente la personalizzazione dell'analisi quando si specifica typeDefs come stringa. |
5 | allowUndefinedInResolve Questo è vero per impostazione predefinita. Quando è impostato su false, le funzioni di risoluzione generano errori se restituiscono undefined. |
6 | resolverValidationOptions Questo è un argomento opzionale e accetta un oggetto con proprietà booleane. |
7 | inheritResolversFromInterfaces Questo è un argomento opzionale e accetta un argomento booleano per controllare l'ereditarietà degli oggetti dei resolver. |
Illustrazione
Creiamo una semplice applicazione per comprendere questo schema. Questo creerà uno schema per interrogare l'elenco degli studenti dal server. I dati degli studenti verranno archiviati in un file flat e utilizzeremo un modulo nodo chiamatonotarealdb per falsificare un database e leggere dal file flat.
Passaggio 1: scaricare e installare le dipendenze richieste per il progetto
Crea una cartella denominata schema-app. Cambia la tua directory in schema-app dal terminale. Quindi, seguire i passaggi da 3 a 5 spiegati nel capitolo Configurazione dell'ambiente per completare il download e il processo di installazione.
Passaggio 2: creare uno schema
Inserisci schema.graphql file nella cartella del progetto, schema-app e aggiungi il seguente codice -
type Query {
greeting:String
students:[Student]
}
type Student {
id:ID!
firstName:String
lastName:String
password:String
collegeId:String
}
La radice dello schema sarà il tipo Query. La query ha due campi: saluto e Studenti che restituisce rispettivamente String e un elenco di studenti. Student è dichiarato come un tipo di oggetto poiché contiene più campi. Il campo ID viene dichiarato come non annullabile.
Passaggio 3: creazione del risolutore
Crea un file resolvers.js nella cartella del progetto e aggiungi il seguente codice -
const db = require('./db')
const Query = {
greeting:() => {
return "hello from TutorialsPoint !!!"
},
students:() => db.students.list()
}
module.exports = {Query}
Qui il saluto e gli studenti sono i risolutori che gestiscono la query. students resolver functionrestituisce un elenco di studenti dal livello di accesso ai dati. Per accedere alle funzioni del resolver al di fuori del modulo, l'oggetto Query deve essere esportato utilizzandomodule.exports.
Passaggio 4: eseguire l'applicazione
Creare un file server.js e fare riferimento al passaggio 8 nel capitolo Configurazione dell'ambiente. Il passaggio successivo consiste nell'eseguire il comando npm start nel terminale. Il server sarà attivo e funzionante sulla porta 9000. Qui, usiamo GraphiQL come client per testare l'applicazione. Apri il browser e digita l'URL,http://localhost:9000/graphiql.
Digita la seguente query nell'editor:
{
greeting
students {
id
firstName
lastName
}
}
La query visualizzerà l'output come mostrato di seguito:
Note- Possiamo sostituire students.json con una chiamata API RESTful per recuperare i dati degli studenti o anche un database reale come MySQL o MongoDB. GraphQL diventa un sottile involucro attorno al livello dell'applicazione originale per migliorare le prestazioni.
Resolver è una raccolta di funzioni che generano risposta per una query GraphQL. In termini semplici, un risolutore agisce come un gestore di query GraphQL. Ogni funzione di risoluzione in uno schema GraphQL accetta quattro argomenti posizionali come indicato di seguito:
fieldName:(root, args, context, info) => { result }
Di seguito è riportato un esempio di funzioni del resolver:
//resolver function with no parameters and returning string
greeting:() => {
return "hello from TutorialsPoint !!!"
}
//resolver function with no parameters and returning list
students:() => db.students.list()
//resolver function with arguments and returning object
studentById:(root,args,context,info) => {
return db.students.get(args.id);
}
Di seguito sono riportati gli argomenti posizionali e la loro descrizione:
Sr.No. | Argomenti e descrizione |
---|---|
1 | root The object that contains the result returned from the resolver on the parent field. |
2 | args An object with the arguments passed into the field in the query. |
3 | context This is an object shared by all resolvers in a particular query. |
4 | info It contains information about the execution state of the query, including the field name, path to the field from the root. |
Resolver Result Format
Resolvers in GraphQL can return different types of values as given below −
Sr.No. | Arguments and Description |
---|---|
1 | null or undefined this indicates the object could not be found |
2 | array this is only valid if the schema indicates that the result of a field should be a list |
3 | promise resolvers often do asynchronous actions like fetching from a database or backend API, so they can return promises |
4 | scalar or object a resolver can also return other values |
Illustration
Let us create a simple application to understand resolver. This will create schema for querying a student by id from the server. The student data will be stored in a flat file and we will use a node module called notarealdb to fake a database and read from flat file.
The following is a step-wise process to create a simple application −
Step 1 − Download and Install Required Dependencies for the Project
Create a folder named resolver-app. Change your directory to resolver-app from the terminal. Later, follow steps 3 to 5 in the Environment Setup chapter.
Step 2 − Create a Schema
Add schema.graphql file in the project folder resolver-app and add the following code −
type Query {
greeting:String
students:[Student]
studentById(id:ID!):Student
}
type Student {
id:ID!
firstName:String
lastName:String
password:String
collegeId:String
}
The schema file shows that user can query for greeting, students and studentById. To retrieve students with specific id, we use data type ID! which shows a non nullable unique identifier field. The students field returns an array of students, and greeting returns a simple string value.
Step 3 − Create Resolver
Create a file resolvers.js in the project folder and add the following code −
const db = require('./db')
const Query = {
//resolver function for greeting
greeting:() => {
return "hello from TutorialsPoint !!!"
},
//resolver function for students returns list
students:() => db.students.list(),
//resolver function for studentbyId
studentById:(root,args,context,info) => {
//args will contain parameter passed in query
return db.students.get(args.id);
}
}
module.exports = {Query}
Here, studentById takes in three parameters. As discussed in this chapter, the studentId can be retrieved from args; root will contain the Query object itself. To return a specific student, we need to call get method with id parameter in the students collection.
Here greeting, students, studentById are the resolvers that handle the query. students resolver function returns a list of students from the data access layer. To access resolver functions outside the module, Query object has to be exported using module.exports.
Step 4 − Run the Application
Create a server.js file. Refer step 8 in the Environment Setup Chapter. Execute the command npm start in the terminal. The server will be up and running on 9000 port. Here, we use GraphiQL as a client to test the application.
Open the browser and enter the url, http://localhost:9000/graphiql. Type the following query in the editor −
{
studentById(id:"S1001") {
id
firstName
lastName
}
}
The output for the above query is as shown below −
{
"data": {
"studentById": {
"id": "S1001",
"firstName": "Mohtashim",
"lastName": "Mohammad"
}
}
}
A GraphQL operation can either be a read or a write operation. A GraphQL query is used to read or fetch values while a mutation is used to write or post values. In either case, the operation is a simple string that a GraphQL server can parse and respond to with data in a specific format. The popular response format that is usually used for mobile and web applications is JSON.
The syntax to define a query is as follows −
//syntax 1
query query_name{ someField }
//syntax 2
{ someField }
Following is an example of a query −
//query with name myQuery
query myQuery{
greeting
}
// query without any name
{
greeting
}
It is clear from the above example that the query keyword is optional.
GraphQL queries help to reduce over fetching of data. Unlike a Restful API, GraphQL allows a user to restrict fields that should be fetched from the server. This means smaller queries and lesser traffic over the network; which in turn reduces the response time.
Illustration 1 - Query Student Model with a Custom Field
In this example, we have a set of students stored in a json file. Each student model has fields like firstName, lastName and id but no fullName. Here, we will discuss how to make a query to retrieve fullName of all students. For this, we need to create fullName field in both schema resolver.
Let us see how to do this illustration using the below steps −
Step 1 − Download and Install Required Dependencies for the Project
Create a folder named query-app. Change your directory to query-app from the terminal. Later, follow steps 3 to 5 explained in the Environment Setup chapter.
Step 2 − Create a Schema
Add schema.graphql file in the project folder query-app and add the following code −
type Query {
greeting:String
students:[Student]
studentById(id:ID!):Student
}
type Student {
id:ID!
firstName:String
lastName:String
fullName:String
}
Note that there is no fullName field in the students.json file. However, we need to fetch the fullname of the student via a query. The fullName, in this case will be a custom field that isn't available with the data source.
Step 3 − Create Resolver
Create a file resolvers.js in the project folder and add the following code −
const db = require('./db')
const Query = {
//resolver function for greeting
greeting:() => {
return "hello from TutorialsPoint !!!"
},
//resolver function for students returns list
students:() => db.students.list(),
//resolver function for studentbyId
studentById:(root,args,context,info) => {
//args will contain parameter passed in query
return db.students.get(args.id);
}
}
//for each single student object returned,resolver is invoked
const Student = {
fullName:(root,args,context,info) => {
return root.firstName+":"+root.lastName
}
}
module.exports = {Query,Student}
Step 4 − Run the Application
Create a server.js file. Refer step 8 in the Environment Setup Chapter. Execute the command npm start in the terminal. The server will be up and running on 9000 port. Here, we use GraphiQL as a client to test the application.
Open browser and type the URL http://localhost:9000/graphiql. Type the following query in the editor −
{
students{
id
fullName
}
}
The response for the query is given below −
{
"data": {
"students": [
{
"id": "S1001",
"fullName": "Mohtashim:Mohammad"
},
{
"id": "S1002",
"fullName": "Kannan:Sudhakaran"
},
{
"id": "S1003",
"fullName": "Kiran:Panigrahi"
}
]
}
}
Create a server.js and add the following code −
const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const db = require('./db');
const port = 9000;
const app = express();
//loading type definitions from schema file
const fs = require('fs')
const typeDefs = fs.readFileSync('./schema.graphql',{encoding:'utf-8'})
//loading resolvers
const resolvers = require('./resolvers')
//binding schema and resolver
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs, resolvers})
//enabling cross domain calls and form post
app.use(cors(), bodyParser.json());
//enabling routes
const {graphiqlExpress,graphqlExpress} = require('apollo-server-express')
app.use('/graphql',graphqlExpress({schema}))
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
//registering port
app.listen(port, () => console.info(`Server started on port ${port}`));
Execute the command npm start in the terminal. The server will be up and running on 9000 port. Here, we use GraphiQL as a client to test the application.
Open the browser and type the URL http://localhost:9000/graphiql. Type the following query in the editor −
{
students{
id
fullName
}
}
The response for the query is given below −
{
"data": {
"students": [
{
"id": "S1001",
"fullName": "Mohtashim:Mohammad"
},
{
"id": "S1002",
"fullName": "Kannan:Sudhakaran"
},
{
"id": "S1003",
"fullName": "Kiran:Panigrahi"
}
]
}
}
Illustration 2 - Nested Query
Let us create a nested query for fetching the student details and their college details. We will work with the same project folder.
Step 1 − Edit the Schema
The schema file already has the student field. Let us add a field college and define its type.
type College {
id:ID!
name:String
location:String
rating:Float
}
type Student {
id:ID!
firstName:String
lastName:String
fullName:String
college:College
}
Passaggio 2: modifica il file resolver.js
Dobbiamo aggiungere una funzione di risoluzione del college come di seguito. La funzione di risoluzione del college verrà eseguita per ogni oggetto studente restituito. Il parametro radice del resolver in questo caso conterrà student .
const Student = {
fullName:(root,args,context,info) => {
return root.firstName+":"+root.lastName
},
college:(root) => {
return db.colleges.get(root.collegeId);
}
}
module.exports = {Query,Student}
Il resolver restituisce il college di ogni studente chiamando il metodo get della raccolta college e passando il collegeId . Abbiamo una relazione di associazione tra studente e college tramite collegeId .
Passaggio 3: testare l'applicazione
Apri la finestra del terminale e vai alla cartella del progetto. Digita il comando -npm start. Avvia il browser e inserisci l'URLhttp://localhost:9000/graphiql.
Immettere la seguente query nella finestra GraphiQL:
{
students{
id
firstName
college {
id
name
location
rating
}
}
}
La risposta per la query è la seguente:
{
"data": {
"students": [
{
"id": "S1001",
"firstName": "Mohtashim",
"college": {
"id": "col-102",
"name": "CUSAT",
"location": "Kerala",
"rating": 4.5
}
},
{
"id": "S1002",
"firstName": "Kannan",
"college": {
"id": "col-101",
"name": "AMU",
"location": "Uttar Pradesh",
"rating": 5
}
},
{
"id": "S1003",
"firstName": "Kiran",
"college": {
"id": "col-101",
"name": "AMU",
"location": "Uttar Pradesh",
"rating": 5
}
}
]
}
}
Che cos'è una variabile di query?
Se una query ha alcuni valori dinamici da trasmettere, rappresenta questi valori dinamici utilizzando le variabili. Pertanto, la query può essere riutilizzata dalle applicazioni client.
Illustrazione
Creiamo una semplice applicazione per comprendere la variabile di query.
Passaggio 1: modifica del file dello schema
Aggiungi un campo sayHello che accetta un parametro stringa e restituisce una stringa. I valori del nome saranno dinamici nell'applicazione client.
type Query {
sayHello(name:String!):String
}
Passaggio 2: modifica il file resolver.js
Aggiungi un resolver sayHello che accetta parametri come di seguito -
sayHello:(root,args,context,info) => `Hi ${args.name} GraphQL server says Hello to you!!`
Passaggio 3: dichiarare la variabile di query in GraphiQL
Una variabile viene dichiarata con $ seguito dal nome della variabile. Ad esempio: $ myname_Variable.
Una volta dichiarata $ myname_Variable, deve essere utilizzata con una sintassi di query con nome. La query, myQuery, prende il valore stringa e lo passa a sayHello come mostrato di seguito -
query myQuery($myname_Variable:String!) { sayHello(name:$myname_Variable)
}
Impostare il valore per $ myname_Variable come oggetto JSON nella sezione Variabili di query del client GraphiQL.
{
"myname_Variable": "Mohtashim"
}
L'output del codice sopra è il seguente:
{
"data": {
"sayHello": "Hi Mohtashim GraphQL server says Hello to you!!"
}
}
Come utilizzare la variabile di query con Enum
Vediamo come utilizzare una variabile di query quando il parametro di campo è enum type.
Passaggio 1: modifica il file schema.graphql
enum ColorType {
RED
BLUE
GREEN
}
type Query {
setFavouriteColor(color:ColorType):String
}
La funzione setFavouriteColor accetta enum come input e restituisce un valore stringa.
Passaggio 2: modifica il file resolvers.js
La funzione resolver setFavouriteColor prende radice e args . È possibile accedere al valore enum passato alla funzione in fase di esecuzione tramite il parametro args.
setFavouriteColor:(root,args) => {
return "Your Fav Color is :"+args.color;
}
Passaggio 3: dichiarare una variabile di query in GraphiQL
La query è denominata query_to_setColorche accetta una variabile del nome color_variable di ColorType. Questa variabile viene passata al metodo setFavouriteColor.
query query_to_setColor($color_variable:ColorType) {
setFavouriteColor(color:$color_variable)
}
Nella sezione della variabile di query di GraphiQL, digita il codice seguente:
{
"color_variable":"RED"
}
La risposta è mostrata di seguito:
{
"data": {
"setFavouriteColor": "Your Fav Color is: RED"
}
}
In questo capitolo impareremo le query di mutazione in GraphQL.
Le query di mutazione modificano i dati nell'archivio dati e restituiscono un valore. Può essere utilizzato per inserire, aggiornare o eliminare dati. Le mutazioni sono definite come parte dello schema.
La sintassi di una query di mutazione è fornita di seguito:
mutation{
someEditOperation(dataField:"valueOfField"):returnType
}
Illustrazione
Cerchiamo di capire come aggiungere un nuovo record studente nel datastore utilizzando una query di mutazione.
Passaggio 1: scaricare e installare le dipendenze richieste per il progetto
Crea una cartella del progetto con il nome mutazione-app. Cambia la tua directory in mutazione-app dal terminale. Seguire i passaggi da 3 a 5 spiegati nel capitolo Configurazione dell'ambiente.
Passaggio 2: creare un file schema.graphql
Inserisci schema.graphql file nella cartella del progetto mutation-app e aggiungi il seguente codice:
type Query {
greeting:String
}
type Mutation {
createStudent(collegeId:ID,firstName:String,lastName:String):String
}
Notare che la funzione createStudent restituisce un tipo String. Si tratta di un identificatore univoco (ID) che viene generato dopo la creazione di uno studente.
Passaggio 3: creare un file resolver.js
Crea un file resolvers.js nella cartella del progetto e aggiungi il seguente codice:
const db = require('./db')
const Mutation = {
createStudent:(root,args,context,info) => {
return db.students.create({collegeId:args.collegeId,
firstName:args.firstName,
lastName:args.lastName})
}
}
const Query = {
greeting:() => "hello"
}
module.exports = {Query,Mutation}
La funzione di mutazione punta alla raccolta degli studenti nel datastore. Per aggiungere un nuovo studente , richiama il metodo create nella raccolta degli studenti. L' oggetto args conterrà i parametri che vengono passati nella query. Il metodo create della raccolta di studenti restituirà l'id di un oggetto studente appena creato.
Passaggio 4: eseguire l'applicazione
Creare un server.jsfile. Fare riferimento al passaggio 8 nel capitolo Configurazione dell'ambiente. Esegui il comando npm start nel terminale. Il server sarà attivo e funzionante sulla porta 9000. Qui, usiamo GraphiQL come client per testare l'applicazione.
Il prossimo passo è aprire il browser e digitare l'URL http://localhost:9000/graphiql. Digita la seguente query nell'editor:
//college Id should be matched with data from colleges.json for easy retrieval
mutation {
createStudent(collegeId:"col-2",firstName:"Tim",lastName:"George")
}
La query precedente creerà un oggetto studente nel file student.json. La query restituirà un identificatore univoco. La risposta alla query è come mostrato di seguito:
{
"data": {
"createStudent": "SkQtxYBUm"
}
}
Per verificare se l'oggetto student è stato creato, possiamo utilizzare la query studentById. Puoi anche aprire il file students.json dalla cartella dei dati per verificare l'id.
Per utilizzare la query studentById, modifica il file schema.graphql come indicato di seguito -
type Query {
studentById(id:ID!):Student
}
type Student {
id:ID!
firstName:String
lastName:String
collegeId:String
}
Modifica il file resolver.js file come indicato di seguito -
const db = require('./db')
const Query = {
studentById:(root,args,context,info) => {
return db.students.get(args.id);
}
}
const Mutation = {
createStudent:(root,args,context,info) => {
return db.students.create({collegeId:args.collegeId,
firstName:args.firstName,
lastName:args.lastName})
}
}
module.exports = {Query,Mutation}
Di seguito è riportata la query per ottenere lo studente tramite ID univoco restituito dalla query di mutazione -
{
studentById(id:"SkQtxYBUm") {
id
firstName
lastName
}
}
La risposta dal server è la seguente:
{
"data": {
"studentById": {
"id": "SkQtxYBUm",
"firstName": "Tim",
"lastName":"George"
}
}
}
Restituzione di un oggetto in mutazione
È buona norma restituire un oggetto in mutazione. Ad esempio, l'applicazione client desidera recuperare i dettagli degli studenti e del college. In questo caso, invece di effettuare due richieste diverse, possiamo creare una query che restituisca un oggetto contenente gli studenti e i dettagli del loro college.
Passaggio 1: modifica del file dello schema
Aggiungi un nuovo metodo denominato addStudent che restituisce l'oggetto nel tipo di mutazione di schema.graphql.
Impariamo come accedere ai dettagli del college attraverso i dettagli degli studenti. Aggiungi il tipo di college nel file dello schema.
type Mutation {
addStudent_returns_object(collegeId:ID,firstName:String,lastName:String):Student
createStudent(collegeId:ID,firstName:String,lastName:String):String
}
type College {
id:ID!
name:String
location:String
rating:Float
}
type Student {
id:ID!
firstName:String
lastName:String
college:College
}
Passaggio 2: aggiorna il file resolvers.js
Aggiorna un file resolvers.js nella cartella del progetto e aggiungi il seguente codice -
const Mutation = {
createStudent:(root,args,context,info) => {
return db.students.create({
collegeId:args.collegeId,
firstName:args.firstName,
lastName:args.lastName
})
},
// new resolver function
addStudent_returns_object:(root,args,context,info) => {
const id = db.students.create({
collegeId:args.collegeId,
firstName:args.firstName,
lastName:args.lastName
})
return db.students.get(id)
}
}
//for each single student object returned,resolver is invoked
const Student = {
college:(root) => {
return db.colleges.get(root.collegeId);
}
}
module.exports = {Query,Student,Mutation}
Passaggio 3: avviare il server e digitare la query di richiesta in GraphiQL
Successivamente, avvieremo il server e richiederemo la query in GraphiQL con il seguente codice:
mutation {
addStudent_returns_object(collegeId:"col-101",firstName:"Susan",lastName:"George") {
id
firstName
college{
id
name
}
}
}
La query precedente aggiunge un nuovo studente e recupera l'oggetto studente insieme all'oggetto college. Ciò consente di risparmiare round trip al server.
La risposta è la seguente:
{
"data": {
"addStudent_returns_object": {
"id": "rklUl08IX",
"firstName": "Susan",
"college": {
"id": "col-101",
"name": "AMU"
}
}
}
}
Durante l'aggiunta o la modifica dei dati, è importante convalidare l'input dell'utente. Ad esempio, potremmo aver bisogno di assicurarci che il valore di un campo non sia sempre nullo. Possiamo usare! (non-nullable) tipo marker in GraphQL per eseguire tale convalida.
La sintassi per l'utilizzo di ! l'indicatore del tipo è come indicato di seguito:
type TypeName {
field1:String!,
field2:String!,
field3:Int!
}
La sintassi precedente garantisce che tutti i campi non siano nulli.
Se vogliamo implementare regole aggiuntive come il controllo della lunghezza di una stringa o il controllo se un numero rientra in un dato intervallo, possiamo definire validatori personalizzati. La logica di validazione personalizzata farà parte della funzione resolver. Cerchiamo di capirlo con l'aiuto di un esempio.
Illustrazione - Implementazione di validatori personalizzati
Creiamo un modulo di iscrizione con convalida di base. Il modulo avrà campi e-mail, nome e password.
Passaggio 1: scaricare e installare le dipendenze richieste per il progetto
Crea una cartella denominata validation-app. Cambia la directory in validation-app dal terminale. Seguire i passaggi da 3 a 5 spiegati nel capitolo Configurazione dell'ambiente.
Passaggio 2: creare uno schema
Inserisci schema.graphql file nella cartella del progetto validation-app e aggiungi il seguente codice -
type Query {
greeting:String
}
type Mutation {
signUp(input:SignUpInput):String
}
input SignUpInput {
email:String!,
password:String!,
firstName:String!
}
Note- Possiamo usare il tipo di input SignUpInput per ridurre il numero di parametri nella funzione signUp. Quindi, la funzione signUp accetta solo un parametro di tipo SignUpInput.
Passaggio 3: creazione di resolver
Crea un file resolvers.js nella cartella del progetto e aggiungi il seguente codice -
const Query = {
greeting:() => "Hello"
}
const Mutation ={
signUp:(root,args,context,info) => {
const {email,firstName,password} = args.input;
const emailExpression = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const isValidEmail = emailExpression.test(String(email).toLowerCase())
if(!isValidEmail)
throw new Error("email not in proper format")
if(firstName.length > 15)
throw new Error("firstName should be less than 15 characters")
if(password.length < 8 )
throw new Error("password should be minimum 8 characters")
return "success";
}
}
module.exports = {Query,Mutation}
La funzione resolver, signUp accetta i parametri email, password e firstName. Questi verranno passati attraverso la variabile di input in modo che sia possibile accedervi tramite args.input.
Passaggio 4: eseguire l'applicazione
Crea un file server.js. Fare riferimento al passaggio 8 nel capitolo Configurazione dell'ambiente. Esegui il comando npm start nel terminale. Il server sarà attivo e funzionante sulla porta 9000. Qui useremo GraphiQL come client per testare l'applicazione.
Apri il browser e inserisci l'URL http://localhost:9000/graphiql. Digita la seguente query nell'editor:
mutation doSignUp($input:SignUpInput) { signUp(input:$input)
}
Poiché l'input per la funzione di registrazione è un tipo complesso, è necessario utilizzare le variabili di query in graphiql. Per questo, dobbiamo prima dare un nome alla query e chiamarla doSignUp, $ input è una variabile di query.
La seguente variabile di query deve essere inserita nella scheda Variabili di query di graphiql -
{
"input":{
"email": "abc@abc",
"firstName": "kannan",
"password": "pass@1234"
}
}
L'array degli errori contiene i dettagli degli errori di convalida come mostrato di seguito:
{
"data": {
"signUp": null
},
"errors": [
{
"message": "email not in proper format",
"locations": [
{
"line": 2,
"column": 4
}
],
"path": [
"signUp"
]
}
]
}
Dobbiamo inserire un input appropriato per ogni campo come indicato di seguito -
{
"input":{
"email": "[email protected]",
"firstName": "kannan",
"password": "pass@1234"
}
}
La risposta è la seguente:
{
"data": {
"signUp": "success"
}
}
Qui, nella query sottostante, non stiamo assegnando alcuna password.
{
"input":{
"email": "[email protected]",
"firstName": "kannan"
}
}
Se non viene fornito un campo obbligatorio, il server qraphql visualizzerà il seguente errore:
{
"errors": [
{
"message": "Variable \"$input\" got invalid value {\"email\":\"[email protected]\",\"firstName\":\"kannan\"}; Field value.password of required type String! was not provided.",
"locations": [
{
"line": 1,
"column": 19
}
]
}
]
}
Le applicazioni Web inviano e recuperano i dati in modo asincrono (in background). AJAX consente ai siti Web di caricare contenuti sullo schermo senza aggiornare la pagina. jQuery fornisce diversi metodi per la funzionalità AJAX, semplificando così l'utilizzo di AJAX. In questo capitolo, impareremo come integrare GraphQL con jQuery.
Considera un'applicazione che utilizza l'architettura del server client. Possiamo costruire una pagina web front-end che richiede dati da un server GraphQL. La pagina web effettuerà chiamate AJAX utilizzando jQuery al server GraphQL.
Per integrare GraphQL con JQuery, esaminiamo le intestazioni della richiesta GraphiQL e comprendiamo i parametri della richiesta.
Avvia il file hello-worldapp (fare riferimento al capitolo 6 per la relativa illustrazione). Digita la query graphql {saluto} nella finestra GraphiQL. Fare clic con il pulsante destro del mouse e ispezionare o premere (ctrl + maiusc + I) su Chrome per accedere alla scheda di rete come mostrato di seguito -
Dal semplice hello-world esempio, possiamo capirlo http method usato è POST. Ora nel browser, scorri verso il basso fino alla sezione dell'intestazione per visualizzare il payload della richiesta .
Dopo aver fatto clic su view code, vedrai quanto segue nella sezione del payload della richiesta di chrome.
{"query":"{\n greeting\n}","variables":null,"operationName":null}
Nota anche l'URL della richiesta, http://localhost:9000/graphql che dovrebbe essere chiamato dall'applicazione client.
Illustrazione
Cerchiamo di capire come integrare GraphQL con JQuery utilizzando un processo graduale.
Configurazione del server
Impareremo a configurare il server utilizzando i seguenti passaggi:
Passaggio 1: scaricare e installare le dipendenze richieste per il progetto
Crea una cartella denominata jquery-server-app. Cambia la tua directory in jquery-server-app dal terminale. Seguire i passaggi da 3 a 5 spiegati nel capitolo Configurazione dell'ambiente.
Passaggio 2: creare uno schema
Aggiungi il file schema.graphql nella cartella del progetto jquery-server-app e aggiungi il seguente codice -
type Query
{
greeting: String
sayHello(name:String!):String
}
Il file ha definito due query greeting e sayHello. La query sayHello accetta un parametro stringa e restituisce un'altra stringa. Il parametro della funzione sayHello () non è nullo.
Passaggio 3: creazione di resolver
Crea un file resolvers.js nella cartella del progetto e aggiungi il seguente codice:
const Query =
{
greeting: () => 'Hello GraphQL From TutorialsPoint !!' ,
sayHello:(root,args,context,info) => `Hi ${args.name} GraphQL server says Hello to you!!`
}
module.exports = {Query}
Qui, greeting e sayHellosono due risolutori. Nel resolver sayHello, è possibile accedere al valore passato al parametro name tramite args. Per accedere alle funzioni del resolver al di fuori del modulo, l'oggetto Query deve essere esportato utilizzandomodule.exports.
Passaggio 4: eseguire l'applicazione
Crea un file server.js. Fare riferimento al passaggio 8 nel capitolo Configurazione dell'ambiente. Esegui il comando npm start nel terminale. Il server sarà attivo e funzionante sulla porta 9000. Qui, usiamo GraphiQL come client per testare l'applicazione.
Apri il browser e digita l'URL http://localhost:9000/graphiql. Digita la seguente query nell'editor:
{
greeting,
sayHello(name:"Mohtashim")
}
La risposta dal server è la seguente:
{
"data": {
"greeting": "Hello GraphQL From TutorialsPoint !!",
"sayHello": "Hi Mohtashim GraphQL server says Hello to you!!"
}
}
Configurazione del client
Dato che abbiamo già configurato il server, ora impareremo come configurare il client.
Passaggio 1: creare una nuova cartella jquery-client-app all'esterno della cartella del progetto corrente
Innanzitutto, creeremo una cartella denominata jquery-client-app fuori dalla cartella del progetto.
Passaggio 2: creare una pagina HTML index.html per l'integrazione con jQuery
Creeremo un'applicazione client in jquery e invocheremo entrambi i metodi. Di seguito è riportato il codice per index.html file. Il index.html pagina invia richieste al server quando i pulsanti - Greet e SayHellovengono cliccati. Faremo una richiesta asincrona utilizzando la funzione $ .ajax ().
<!DOCTYPE html>
<html>
<head>
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function() { $("#btnSayhello").click(function() {
const name = $("#txtName").val(); console.log(name); $("#SayhelloDiv").html('loading....');
$.ajax({url: "http://localhost:9000/graphql", contentType: "application/json",type:'POST', data: JSON.stringify({ query:`{ sayHello(name:"${name}")}`
}),
success: function(result) {
console.log(JSON.stringify(result))
$("#SayhelloDiv").html("<h1>"+result.data.sayHello +"</h1>"); } }); }); $("#btnGreet").click(function() {
$("#greetingDiv").html('loading....'); //https://kannan-first-graphql-app.herokuapp.com/graphql $.ajax({url: "http://localhost:9000/graphql",
contentType: "application/json",
type:'POST',
data: JSON.stringify({
query:`{greeting}`
}),
success: function(result) {
$("#greetingDiv").html("<h1>"+result.data.greeting+"</h1>");
}
});
});
});
</script>
</head>
<body>
<h1>Jquery Client </h1>
<hr/>
<section>
<button id = "btnGreet">Greet</button>
<br/> <br/>
<div id = "greetingDiv"> </div>
</section>
<br/> <br/> <br/>
<hr/>
<section>
Enter a name:<input id = "txtName" type = "text" value = "kannan"/>
<button id = "btnSayhello">SayHello</button>
<div id = "SayhelloDiv"> </div>
</section>
</body>
</html>
Apri questo file nel browser e fai clic sul pulsante per vedere la risposta. L'output sarà come indicato di seguito:
React è una libreria Javascript per la creazione di interfacce utente. Questo capitolo spiega come integrare GraphQL con un'applicazione React.
Illustrazione
Il modo più rapido per impostare un progetto React è utilizzare lo strumento Crea app React . Nelle sezioni successive impareremo come configurare sia il Server che il Client.
Configurazione del server
Per configurare il server, seguire i passaggi seguenti:
Passaggio 1: scaricare e installare le dipendenze richieste per il progetto
Crea una cartella react-server-app. Cambia la tua directory in react-server-app dal terminale. Seguire i passaggi da 3 a 5 spiegati nel capitolo Configurazione dell'ambiente.
Passaggio 2: creare uno schema
Inserisci schema.graphql file nella cartella del progetto react-server-app e aggiungi il seguente codice -
type Query
{
greeting: String
sayHello(name:String!):String
}
Il file ha definito due query: greeting e sayHello. La query sayHello accetta un parametro stringa e restituisce un'altra stringa. Il parametro della funzione sayHello () non è nullo.
Passaggio 3: creazione di resolver
Crea un file resolvers.js nella cartella del progetto e aggiungi il seguente codice -
const Query =
{
greeting: () => 'Hello GraphQL From TutorialsPoint !!' ,
sayHello:(root,args,context,info) => `Hi ${args.name} GraphQL server says Hello to you!!`
}
module.exports = {Query}
Qui saluto e SayHello sono due risolutori. Nel risolutore sayHello, è possibile accedere al valore passato al parametro name tramite args. Per accedere alle funzioni del resolver al di fuori del modulo, l'oggetto Query deve essere esportato utilizzando module.exports.
Passaggio 4: eseguire l'applicazione
Crea un file server.js. Fare riferimento al passaggio 8 nel capitolo Configurazione dell'ambiente. Esegui il comando npm start nel terminale. Il server sarà attivo e funzionante sulla porta 9000. Qui, usiamo GraphiQL come client per testare l'applicazione.
Apri il browser e digita l'URL http://localhost:9000/graphiql. Digita la seguente query nell'editor:
{
greeting,
sayHello(name:"Mohtashim")
}
Di seguito viene fornita la risposta dal server:
{
"data": {
"greeting": "Hello GraphQL From TutorialsPoint !!",
"sayHello": "Hi Mohtashim GraphQL server says Hello to you!!"
}
}
Configurazione del client
Apri un nuovo terminale per il cliente. Il terminale del server deve essere mantenuto in esecuzione prima di eseguire l'applicazione client. L'applicazione React verrà eseguita sulla porta numero 3000 e l'applicazione server sulla porta numero 9000.
Passaggio 1: crea un hello-world-client del progetto React
Nel terminale del client, digita il seguente comando:
npx create-react-app hello-world-client
Questo installerà tutto il necessario per una tipica applicazione React. Ilnpx utilità e create-react-appstrumento crea un progetto con il nome hello-world-client. Una volta completata l'installazione, apri il progetto in VSCode.
Passaggio 2: avvia hello-world-client
Cambia il percorso della cartella corrente nel terminale in hello-world-client. Digita npm start per avviare il progetto. Questo eseguirà un server di sviluppo sulla porta 3000 e aprirà automaticamente il browser e caricherà la pagina dell'indice.
Questo è mostrato nella schermata riportata di seguito:
Passaggio 3: modificare il componente dell'app
Nell'App.js all'interno della cartella src, aggiungi due funzioni, una per caricare i messaggi di saluto e un'altra per caricare i messaggi sayHello.
Di seguito è riportata la funzione loadGreeting che invia una query GraphQL per il saluto.
async function loadGreeting() {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:'{greeting}'})
})
const rsponseBody = await response.json();
return rsponseBody.data.greeting;
console.log("end of function")
}
Di seguito è riportato il file loadSayhello funzione che invia query GraphQL per sayHello -
async function loadSayhello(name) {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:`{sayHello(name:"${name}")}`})
})
}
Il completo App.js il file è mostrato di seguito -
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
async function loadGreeting() {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:'{greeting}'})
})
const rsponseBody = await response.json();
return rsponseBody.data.greeting;
console.log("end of function")
}
async function loadSayhello(name) {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:`{sayHello(name:"${name}")}`})
})
const rsponseBody = await response.json();
return rsponseBody.data.sayHello;
}
class App extends Component {
constructor(props) {
super(props);
this.state = {greetingMessage:'',sayHelloMessage:'',userName:''}
this.updateName = this.updateName.bind(this);
this.showSayHelloMessage = this.showSayHelloMessage.bind(this);
this.showGreeting = this.showGreeting.bind(this);
}
showGreeting() {
loadGreeting().then(g => this.setState({greetingMessage:g+" :-)"}))
}
showSayHelloMessage() {
const name = this.state.userName;
console.log(name)
loadSayhello(name).then(m => this.setState({sayHelloMessage:m}))
}
updateName(event) {
this.setState({userName:event.target.value})
}
render() {
return (
<div className = "App">
<header className = "App-header">
<img src = {logo} className = "App-logo" alt = "logo" />
<h1 className = "App-title">Welcome to React</h1>
</header>
<br/><br/>
<section>
<button id = "btnGreet" onClick = {this.showGreeting}>Greet</button>
<br/> <br/>
<div id = "greetingDiv">
<h1>{this.state.greetingMessage}</h1>
</div>
</section>
<hr/>
<section>
Enter a name:<input id = "txtName" type = "text" onChange = {this.updateName}
value = {this.state.userName}/>
<button id = "btnSayhello" onClick = {this.showSayHelloMessage}>SayHello</button>
<br/>
user name is:{this.state.userName} <br/>
<div id = "SayhelloDiv">
<h1>{this.state.sayHelloMessage}</h1>
</div>
</section>
</div>
);
}
}
export default App;
Una volta che entrambe le applicazioni sono in esecuzione, fare clic sul pulsante di saluto. Quindi, inserisci un nome nella casella di testo e fai clic sul pulsante sayHello. L'output sarà come indicato di seguito:
Abbiamo utilizzato Apollo Server per creare le specifiche graphql sul lato server. È facile e veloce costruire un server GraphQL pronto per la produzione. Ora capiamo il lato client.
Apollo Client è il modo migliore per utilizzare GraphQL per creare applicazioni client. Il client è progettato per aiutare lo sviluppatore a creare rapidamente un'interfaccia utente che recupera i dati con GraphQL e può essere utilizzata con qualsiasi front-end JavaScript.
Apollo Client supporta le seguenti piattaforme:
Sr.No. | Piattaforma e framework |
---|---|
1 | Javascript React, Angular, Vue, Meteor, Ember |
2 | WebComponents Polimero, lit-apollo |
3 | Native Mobile Android nativo con Java, iOS nativo con Swift |
La memorizzazione nella cache è una delle caratteristiche principali di Apollo Client. apollo-boost è un comodo pacchetto che include un mucchio di altre dipendenze.
Illustrazione
Vediamo come utilizzare Apollo Client per creare applicazioni client utilizzando i seguenti passaggi:
Configurazione del server
Dobbiamo seguire i passaggi seguenti per configurare un server:
Passaggio 1: scaricare e installare le dipendenze richieste per il progetto
Crea una cartella apollo-server-app. Cambia la tua directory in apollo-server-app dal terminale. Quindi, seguire i passaggi da 3 a 5 spiegati nel capitolo Configurazione dell'ambiente.
Passaggio 2: creare uno schema
Inserisci schema.graphql file nella cartella del progetto apollo-server-app e aggiungi il seguente codice -
type Query
{
students:[Student]
}
type Student {
id:ID!
firstName:String
lastName:String
college:College
}
type College {
id:ID!
name:String
location:String
rating:Float
}
Passaggio 3: aggiungere i resolver
Crea un file resolvers.js nella cartella del progetto e aggiungi il seguente codice -
const db = require('./db')
const Query = {
//resolver function for students returns list
students:() => db.students.list(),
}
const Student = {
college:(root) => {
return db.colleges.get(root.collegeId);
}
}
module.exports = {Query,Student}
Passaggio 4: eseguire l'applicazione
Creare un server.jsfile. Fare riferimento al passaggio 8 nel capitolo Configurazione dell'ambiente. Esegui il comando npm start nel terminale. Il server sarà attivo e funzionante sulla porta 9000. Qui useremo GraphiQL come client per testare l'applicazione.
Apri il browser e digita l'URL http://localhost:9000/graphiql. Digita la seguente query nell'editor.
{
students{
id
firstName
college{
name
}
}
}
La risposta per la query è la seguente:
{
"data": {
"students": [
{
"id": "S1001",
"firstName": "Mohtashim",
"college": {
"name": "CUSAT"
}
},
{
"id": "S1002",
"firstName": "Kannan",
"college": {
"name": "AMU"
}
},
{
"id": "S1003",
"firstName": "Kiran",
"college": {
"name": "AMU"
}
}
]
}
}
Configurazione del client
Apri un nuovo terminale per il cliente. Il terminale del server deve essere mantenuto in esecuzione prima di eseguire l'applicazione client. L'applicazione React verrà eseguita sulla porta numero 3000 e l'applicazione server sulla porta numero 9000.
Passaggio 1: creare un'applicazione React
Nel terminale del client, digita il seguente comando:
npx create-react-app hello-world-client
Questo installerà tutto il necessario per una tipica applicazione React. L'utilità npx e lo strumento create-react-app creano un progetto con nomehello-world-client. Una volta completata l'installazione, apri il progetto in VSCode.
Passaggio 2: avvia hello-world-client
Cambia il percorso della cartella corrente nel terminale in hello-world-client. Digita npm start per avviare il progetto. Questo eseguirà un server di sviluppo sulla porta 3000 e aprirà automaticamente il browser e caricherà la pagina dell'indice.
Questo è mostrato nella schermata riportata di seguito:
Passaggio 3: installare le librerie client di Apollo
Per installare un client Apollo, aprire un nuovo terminale e trovarsi nel percorso della cartella del progetto corrente. Digita il seguente comando:
npm install apollo-boost graphql
Questo scaricherà le librerie graphql per il lato client e anche il pacchetto Apollo Boost. Possiamo effettuare un controllo incrociato digitando npm view nelle dipendenze di apollo-boost. Questo avrà molte dipendenze come mostrato di seguito -
{
'apollo-cache': '^1.1.15',
'apollo-cache-inmemory': '^1.2.8',
'apollo-client': '^2.4.0',
'apollo-link': '^1.0.6',
'apollo-link-error': '^1.0.3',
'apollo-link-http': '^1.3.1',
'apollo-link-state': '^0.4.0',
'graphql-tag': '^2.4.2'
}
Possiamo vedere chiaramente che la libreria Apollo-Client è installata.
Passaggio 4: modificare il componente dell'app nel file index.js
Con Apollo Client, possiamo chiamare direttamente il server senza utilizzare l'API di recupero. Inoltre, le query e le mutazioni non devono essere incorporate in una stringa creata con la notazione back tick. Questo perché, ilgqlla funzione analizza direttamente le query. Ciò significa che un programmatore può scrivere direttamente query nello stesso modo quando scrive query nello strumento GraphiQL. gql è una funzione tag che analizzerà la stringa del modello scritta in notazione back tick nell'oggetto query graphql. Il metodo di query di Apollo Client restituisce una promessa.
Il seguente frammento di codice mostra come importare il client Apollo:
import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
const endPointUrl = 'http://localhost:9000/graphql'
const client = new ApolloClient({
link: new HttpLink({uri:endPointUrl}),
cache:new InMemoryCache()
});
Nel capitolo precedente, abbiamo discusso come utilizzare l'API di recupero per le richieste HTTP. Il codice seguente mostra come usaregqlfunzione. IlloadStudentsAsync la funzione usa il client graphql per interrogare il server.
async function loadStudentsAsync() {
const query = gql`
{
students{
id
firstName
lastName
college{
name
}
}
}`
const {data} = await client.query({query}) ;
return data.students;
}
Hai solo bisogno di mantenere il file index.js in srccartella e index.html nella cartella pubblica; tutti gli altri file generati automaticamente possono essere rimossi.
Di seguito viene fornita la struttura delle directory:
hello-world-client /
-->node_modules
-->public
index.html
-->src
index.js
-->package.json
Di seguito è riportato il file index.js nell'applicazione React -
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
// apollo client
import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
import gql from 'graphql-tag'
const endPointUrl = 'http://localhost:9000/graphql'
const client = new ApolloClient({
link: new HttpLink({uri:endPointUrl}),
cache:new InMemoryCache()
});
async function loadStudentsAsync() {
const query = gql`
{
students{
id
firstName
lastName
college{
name
}
}
}
`
const {data} = await client.query({query}) ;
return data.students;
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
students:[]
}
this.studentTemplate = [];
}
async loadStudents() {
const studentData = await loadStudentsAsync();
this.setState({
students: studentData
})
console.log("loadStudents")
}
render() {
return(
<div>
<input type = "button" value = "loadStudents" onClick = {this.loadStudents.bind(this)}/>
<div>
<br/>
<hr/>
<table border = "3">
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>college Name</td>
</tr>
</thead>
<tbody>
{
this.state.students.map(s => {
return (
<tr key = {s.id}>
<td>
{s.firstName}
</td>
<td>
{s.lastName}
</td>
<td>
{s.college.name}
</td>
</tr>
)
})
}
</tbody>
</table>
</div>
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
L'applicazione React caricherà gli studenti dal server GraphQL, dopo aver fatto clic sul pulsante loadStudents come mostrato di seguito -
L'autenticazione è il processo o l'azione di verifica dell'identità di un utente o di un processo. È importante che un'applicazione autentichi un utente per garantire che i dati non siano disponibili per un utente anonimo. In questa sezione impareremo come autenticare un client GraphQL.
Express JWT
In questo esempio, useremo jQuery per creare un'applicazione client. Per autenticare le richieste, useremo express-jwt modulo sul lato server.
Il modulo express-jwt è un middleware che consente di autenticare le richieste HTTP utilizzando i token JWT. JSON Web Token (JWT) è una lunga stringa che identifica l'utente connesso.
Una volta che l'utente accede correttamente, il server genera un token JWT. Questo token identifica distintamente un registro. In altre parole, il token è una rappresentazione dell'identità dell'utente. Quindi la prossima volta, quando il client arriva al server, deve presentare questo token per ottenere le risorse richieste. Il client può essere un'applicazione mobile o un'applicazione web.
Illustrazione
Seguiremo una procedura graduale per comprendere questa illustrazione.
Configurazione del server
Di seguito sono riportati i passaggi per configurare il server:
Passaggio 1: scaricare e installare le dipendenze richieste per il progetto
Crea una cartella auth-server-app. Cambia la tua directory in auth-server-app dal terminale. Seguire i passaggi da 3 a 5 spiegati nel capitolo Configurazione dell'ambiente.
Passaggio 2: creare uno schema
schema.graphql auth-server-apptype Query
{
greetingWithAuth:String
}
Passaggio 3: aggiungere i resolver
Crea un file resolvers.js nella cartella del progetto e aggiungi il seguente codice -
Il risolutore verificherà se un oggetto utente autenticato è disponibile nell'oggetto contesto di GraphQL. Solleverà un'eccezione se un utente autenticato non è disponibile.
const db = require('./db')
const Query = {
greetingWithAuth:(root,args,context,info) => {
//check if the context.user is null
if (!context.user) {
throw new Error('Unauthorized');
}
return "Hello from TutorialsPoint, welcome back : "+context.user.firstName;
}
}
module.exports = {Query}
Passaggio 4: creare il file Server.js
Il middleware di autenticazione autentica i chiamanti utilizzando un token Web JSON. L'URL per l'autenticazione è http://localhost:9000/login.
Questa è un'operazione post. L'utente deve inviare la sua email e password che verranno convalidate dal backend. Se viene generato un token valido utilizzando il metodo jwt.sign, il client dovrà inviarlo nell'intestazione per le richieste successive.
Se il token è valido, req.user verrà impostato con l'oggetto JSON decodificato per essere utilizzato dal middleware successivo per l'autorizzazione e il controllo dell'accesso.
Il codice seguente utilizza due moduli: jsonwebtoken ed express-jwt per autenticare le richieste -
Quando l'utente fa clic sul file greetpulsante, viene emessa una richiesta per il percorso / graphql. Se l'utente non è autenticato, gli verrà chiesto di autenticarsi.
All'utente viene presentato un modulo che accetta ID e-mail e password. Nel nostro esempio, la rotta / login è responsabile dell'autenticazione dell'utente.
La route / login verifica se nel database viene trovata una corrispondenza per le credenziali fornite dall'utente.
Se le credenziali non sono valide, all'utente viene restituita un'eccezione HTTP 401.
Se le credenziali sono valide, il server genera un token. Questo token viene inviato come parte della risposta all'utente. Questo viene fatto dalla funzione jwt.sign.
const expressJwt = require('express-jwt');
const jwt = require('jsonwebtoken');
//private key
const jwtSecret = Buffer.from('Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt', 'base64');
app.post('/login', (req, res) => {
const {email, password} = req.body;
//check database
const user = db.students.list().find((user) => user.email === email);
if (!(user && user.password === password)) {
res.sendStatus(401);
return;
}
//generate a token based on private key, token doesn't have an expiry
const token = jwt.sign({sub: user.id}, jwtSecret);
res.send({token});
});
Per ogni richiesta verrà chiamata la funzione app.use (). Questo a sua volta richiamerà il middleware expressJWT. Questo middleware decodificherà il token Web JSON. L'ID utente memorizzato nel token verrà recuperato e archiviato come utente di proprietà nell'oggetto richiesta.
//decodes the JWT and stores in request object
app.use(expressJwt({
secret: jwtSecret,
credentialsRequired: false
}));
Per rendere disponibile la proprietà utente nel contesto GraphQL, questa proprietà viene assegnata al file context oggetto come mostrato di seguito -
//Make req.user available to GraphQL context
app.use('/graphql', graphqlExpress((req) => ({
schema,
context: {user: req.user &&apm; db.students.get(req.user.sub)}
})));
Creare server.js nel percorso della cartella corrente. Il file server.js completo è il seguente:
const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const expressJwt = require('express-jwt'); //auth
const jwt = require('jsonwebtoken'); //auth
const db = require('./db');
var port = process.env.PORT || 9000
const jwtSecret = Buffer.from('Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt', 'base64');
const app = express();
const fs = require('fs')
const typeDefs = fs.readFileSync('./schema.graphql',{encoding:'utf-8'})
const resolvers = require('./resolvers')
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs, resolvers})
app.use(cors(), bodyParser.json(), expressJwt({
secret: jwtSecret,
credentialsRequired: false
}));
const {graphiqlExpress,graphqlExpress} = require('apollo-server-express')
app.use('/graphql', graphqlExpress((req) => ({
schema,
context: {user: req.user && db.students.get(req.user.sub)}
})));
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
//authenticate students
app.post('/login', (req, res) => {
const email = req.body.email;
const password = req.body.password;
const user = db.students.list().find((user) => user.email === email);
if (!(user && user.password === password)) {
res.sendStatus(401);
return;
}
const token = jwt.sign({sub: user.id}, jwtSecret);
res.send({token});
});
app.listen(port, () => console.info(`Server started on port ${port}`));
Passaggio 5: eseguire l'applicazione
Esegui il comando npm start nel terminale. Il server sarà attivo e funzionante sulla porta 9000. Qui, usiamo GraphiQL come client per testare l'applicazione.
Apri il browser e digita l'URL http://localhost:9000/graphiql. Digita la seguente query nell'editor:
{
greetingWithAuth
}
Nella risposta seguente, abbiamo ricevuto un errore poiché non siamo utenti autenticati.
{
"data": {
"greetingWithAuth": null
},
"errors": [
{
"message": "Unauthorized",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"greetingWithAuth"
]
}
]
}
Nella sezione successiva, creiamo un'applicazione client per l'autenticazione.
Configurazione del client JQuery
Nell'applicazione client, viene fornito un pulsante di saluto che richiamerà lo schema greetingWithAuth. Se fai clic sul pulsante senza effettuare l'accesso, ti verrà visualizzato il messaggio di errore come di seguito:
Una volta effettuato l'accesso con un utente disponibile nel database, apparirà la seguente schermata:
Accedere greeting, dobbiamo prima accedere all'URL http://localhost:9000/login percorso come di seguito.
La risposta conterrà il token generato dal server.
$.ajax({
url:"http://localhost:9000/login",
contentType:"application/json",
type:"POST",
data:JSON.stringify({email,password}),
success:function(response) {
loginToken = response.token;
$('#authStatus') .html("authenticated successfully") .css({"color":"green",'font-weight':'bold'}); $("#greetingDiv").html('').css({'color':''});
},
error:(xhr,err) => alert('error')
})
Dopo un accesso riuscito, possiamo accedere allo schema greetingWithAuth come indicato di seguito. Dovrebbe essere presente un'intestazione di autorizzazione per tutte le richieste successive con token di connessione.
{
url: "http://localhost:9000/graphql",
contentType: "application/json",
headers: {"Authorization": 'bearer '+loginToken}, type:'POST',
data: JSON.stringify({
query:`{greetingWithAuth}`
}
Quello che segue è il codice per index.html -
<!DOCTYPE html>
<html>
<head>
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function() { let loginToken = ""; $("#btnGreet").click(function() {
$.ajax({url: "http://localhost:9000/graphql", contentType: "application/json", headers: {"Authorization": 'bearer '+loginToken}, type:'POST', data: JSON.stringify({ query:`{greetingWithAuth}` }), success: function(result) { $("#greetingDiv").html("<h1>"+result.data.greetingWithAuth+"</h1>")
},
error:function(jQxhr,error) {
if(jQxhr.status == 401) {
$("#greetingDiv").html('please authenticate first!!') .css({"color":"red",'font-weight':'bold'}) return; } $("#greetingDiv").html('error').css("color","red");
}
});
});
$('#btnAuthenticate').click(function() { var email = $("#txtEmail").val();
var password = $("#txtPwd").val(); if(email && password) { $.ajax({
url:"http://localhost:9000/login",
contentType:"application/json",
type:"POST",
data:JSON.stringify({email,password}),
success:function(response) {
loginToken = response.token;
$('#authStatus') .html("authenticated successfully") .css({"color":"green",'font-weight':'bold'}); $("#greetingDiv").html('').css({'color':''});
},
error:(xhr,err) => alert('error')
})
}else alert("email and pwd empty")
})
});
</script>
</head>
<body>
<h1> GraphQL Authentication </h1>
<hr/>
<section>
<button id = "btnGreet">Greet</button>
<br/> <br/>
<div id = "greetingDiv"></div>
</section>
<br/> <br/> <br/>
<hr/>
<section id = "LoginSection">
<header>
<h2>*Login first to access greeting </h2>
</header>
<input type = "text" value = "[email protected]" placeholder = "enter email" id = "txtEmail"/>
<br/>
<input type = "password" value = "pass123" placeholder = "enter password" id = "txtPwd"/>
<br/>
<input type = "button" id = "btnAuthenticate" value = "Login"/>
<p id = "authStatus"></p>
</section>
</body>
</html>
La memorizzazione nella cache è il processo di archiviazione dei dati in un'area di archiviazione temporanea chiamata cache. Quando torni a una pagina che hai visitato di recente, il browser può ottenere quei file dalla cache anziché dal server originale. Ciò consente di risparmiare tempo e rete dal carico di traffico aggiuntivo.
Le applicazioni client che interagiscono con GraphQL sono responsabili della memorizzazione nella cache dei dati alla loro estremità. Un possibile modello per questo è riservare un campo, come id, come identificatore univoco globale.
InMemory Cache
InMemoryCache è un archivio dati normalizzato comunemente utilizzato nelle applicazioni client GraphQL senza l'uso di altre librerie come Redux.
Il codice di esempio per utilizzare InMemoryCache con ApolloClient è fornito di seguito:
import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
const cache = new InMemoryCache();
const client = new ApolloClient({
link: new HttpLink(),
cache
});
Il costruttore InMemoryCache accetta un oggetto di configurazione opzionale con proprietà per personalizzare la cache.
Sr.No. | Parametro e descrizione |
---|---|
1 | addTypename Un valore booleano per determinare se aggiungere __typename al documento (default: true) |
2 | dataIdFromObject Una funzione che accetta un oggetto dati e restituisce un identificatore univoco da utilizzare durante la normalizzazione dei dati nell'archivio |
3 | fragmentMatcher Per impostazione predefinita, InMemoryCache utilizza un abbinamento di frammenti euristico |
4 | cacheRedirects Una mappa di funzioni per reindirizzare una query a un'altra voce nella cache prima che venga eseguita una richiesta. |
Illustrazione
Creeremo un'applicazione a pagina singola in ReactJS con due schede: una per la scheda home e un'altra per gli studenti. La scheda Studenti caricherà i dati da un'API del server GraphQL. L'applicazione interrogherà i dati degli studenti quando l'utente passa dalla scheda Home alla scheda Studenti. I dati risultanti verranno memorizzati nella cache dall'applicazione.
Interrogeremo anche l'ora del server utilizzando getTimecampo per verificare se la pagina è memorizzata nella cache. Se i dati vengono restituiti dalla cache, la pagina visualizzerà l'ora della prima richiesta inviata al server. Se i dati sono il risultato di una nuova richiesta fatta al server, mostrerà sempre l'ora più recente dal server.
Configurazione del server
Di seguito sono riportati i passaggi per configurare il server:
Passaggio 1: scaricare e installare le dipendenze richieste per il progetto
Crea una cartella cache-server-app. Cambia la tua directory in cache-server-app dal terminale. Seguire i passaggi da 3 a 5 spiegati nel capitolo Configurazione dell'ambiente.
Passaggio 2: creare uno schema
Inserisci schema.graphql file nella cartella del progetto cache-server-app e aggiungi il seguente codice -
type Query {
students:[Student]
getTime:String
}
type Student {
id:ID!
firstName:String
lastName:String
fullName:String
}
Passaggio 3: aggiungere i resolver
Crea un file resolvers.js nella cartella del progetto e aggiungi il codice seguente:
const db = require('./db')
const Query = {
students:() => db.students.list(),
getTime:() => {
const today = new Date();
var h = today.getHours();
var m = today.getMinutes();
var s = today.getSeconds();
return `${h}:${m}:${s}`;
}
}
module.exports = {Query}
Passaggio 4: eseguire l'applicazione
Crea un file server.js. Fare riferimento al passaggio 8 nel capitolo Configurazione dell'ambiente. Esegui il comando npm start nel terminale. Il server sarà attivo e funzionante sulla porta 9000. Qui useremo GraphiQL come client per testare l'applicazione.
Apri il browser e inserisci l'URL http://localhost:9000/graphiql. Digita la seguente query nell'editor:
{
getTime
students {
id
firstName
}
}
La risposta di esempio mostra i nomi degli studenti e l'ora del server.
{
"data": {
"getTime": "22:18:42",
"students": [
{
"id": "S1001",
"firstName": "Mohtashim"
},
{
"id": "S1002",
"firstName": "Kannan"
},
{
"id": "S1003",
"firstName": "Kiran"
}
]
}
}
Configurazione del client ReactJS
Apri un nuovo terminale per il cliente. Il terminale del server deve essere mantenuto in esecuzione prima di eseguire l'applicazione client. L'applicazione React verrà eseguita sulla porta numero 3000 e l'applicazione server sulla porta numero 9000.
Passaggio 1: creare un'applicazione React
Nel terminale del client, digita il seguente comando:
npx create-react-app hello-world-client
Questo installerà tutto il necessario per una tipica applicazione React. Ilnpx utility e create-react-apptools crea un progetto con il nome hello-world-client. Una volta completata l'installazione, apri il progetto in VSCode.
Installa i moduli del router per reagire usando il seguente comando: npm install react-router-dom.
Passaggio 2: avvia hello-world-client
Cambia il percorso della cartella corrente nel terminale in hello-world-client. Digita npm start per avviare il progetto. Questo eseguirà un server di sviluppo sulla porta 3000 e aprirà automaticamente il browser e caricherà la pagina dell'indice.
Questo è mostrato nella schermata riportata di seguito:
Passaggio 3: installare le librerie client di Apollo
Per installare un client Apollo, aprire un nuovo terminale e trovarsi nel percorso della cartella del progetto corrente. Digita il seguente comando:
npm install apollo-boost graphql
Questo scaricherà le librerie graphql per il lato client e anche il pacchetto Apollo Boost. Possiamo effettuare una verifica incrociata digitando npm view apollo-boost dependencies. Questo avrà molte dipendenze come mostrato di seguito -
{
'apollo-cache': '^1.1.15',
'apollo-cache-inmemory': '^1.2.8',
'apollo-client': '^2.4.0',
'apollo-link': '^1.0.6',
'apollo-link-error': '^1.0.3',
'apollo-link-http': '^1.3.1',
'apollo-link-state': '^0.4.0',
'graphql-tag': '^2.4.2'
}
Possiamo vedere chiaramente che la libreria apollo-client è installata.
Passaggio 4: modificare il componente dell'app nel file index.js
Per una semplice applicazione React, devi solo mantenere il file index.js in src cartella e index.htmlnella cartella pubblica; tutti gli altri file generati automaticamente possono essere rimossi.
Di seguito viene fornita la struttura delle directory:
hello-world-client /
-->node_modules
-->public
index.html
-->src
index.js
students.js
-->package.json
Aggiungi un file aggiuntivo students.js che conterrà il Componente Studenti. I dettagli dello studente vengono recuperati tramite il componente Student. Nel componente dell'app, stiamo usando un HashRouter.
Di seguito è riportato il file index.js nell'applicazione React -
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {HashRouter, Route, Link} from 'react-router-dom'
//components
import Students from './students'
class App extends Component {
render() {
return(
<div><h1>Home !!</h1>
<h2>Welcome to React Application !! </h2>
</div>
)
}
}
function getTime() {
var d = new Date();
return d.getHours()+":"+d.getMinutes()+":"+d.getSeconds()
}
const routes = <HashRouter>
<div>
<h4>Time from react app:{getTime()}</h4>
<header>
<h1> <Link to="/">Home</Link>
<Link to = "/students">Students</Link> </h1>
</header>
<Route exact path = "/students" component = {Students}></Route>
<Route exact path = "/" component = {App}></Route>
</div>
</HashRouter>
ReactDOM.render(routes, document.querySelector("#root"))
Passaggio 5: modifica degli studenti del componente in Students.js
In Students Component, utilizzeremo i seguenti due approcci per caricare i dati:
Fetch API (loadStudents_noCache) - Questo attiverà una nuova richiesta ogni volta che fa clic sulla scheda Studente.
Apollo Client (loadWithApolloclient) - Questo recupererà i dati dalla cache.
Aggiungi una funzione loadWithApolloclientquali query per studenti e tempo dal server. Questa funzione abiliterà la memorizzazione nella cache. Qui usiamo una funzione gql per analizzare la query.
async loadWithApolloclient() {
const query = gql`{
getTime
students {
id
firstName
}
}`;
const {data} = await client.query({query})
return data;
}
Il Fetch APIè una semplice interfaccia per il recupero delle risorse. Fetch rende più facile effettuare richieste web e gestire le risposte rispetto al vecchio XMLHttpRequest. Il seguente metodo mostra il caricamento dei dati direttamente utilizzando fetch api -
async loadStudents_noCache() {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:`{
getTime
students {
id
firstName
}
}`})
})
const rsponseBody = await response.json();
return rsponseBody.data;
}
Nel costruttore di StudentsComponent, chiama il file loadWithApolloClientmetodo. Il completo Student.js il file è sotto -
import React, {Component} from 'react';
import { Link} from 'react-router-dom'
//Apollo Client
import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
import gql from 'graphql-tag'
const client = new ApolloClient({
link: new HttpLink({uri:`http://localhost:9000/graphql`}),
cache:new InMemoryCache()
})
class Students extends Component {
constructor(props) {
super(props);
this.state = {
students:[{id:1,firstName:'test'}],
serverTime:''
}
this.loadWithApolloclient().then(data => {
this.setState({
students:data.students,
serverTime:data.getTime
})
})
}
async loadStudents_noCache() {
const response = await fetch('http://localhost:9000/graphql', {
method:'POST',
headers:{'content-type':'application/json'},
body:JSON.stringify({query:`{
getTime
students {
id
firstName
}
}`})
})
const rsponseBody = await response.json();
return rsponseBody.data;
}
async loadWithApolloclient() {
console.log("inside apollo client function")
const query = gql`{
getTime
students {
id
firstName
}
}`;
const {data} = await client.query({query})
return data;
}
render() {
return(
<div>
<h3>Time from GraphQL server :{this.state.serverTime}</h3>
<p>Following Students Found </p>
<div>
<ul>
{
this.state.students.map(s => {
return(
<li key = {s.id}>
{s.firstName}
</li>
)
})
}
</ul>
</div>
</div>
)
}
}
export default Students
Passaggio 6: eseguire l'applicazione React con npm start
Puoi testare l'applicazione React passando dalla scheda Home alla scheda Studenti. Una volta caricata la scheda Studenti con i dati dal server. Memorizzerà i dati nella cache. Puoi testarlo passando più volte dalla scheda Home alla scheda Studenti. L'output sarà come mostrato di seguito -
Se hai caricato prima la pagina degli studenti digitando l'URL, http://localhost:3000/#/students, puoi vedere che il tempo di caricamento per l'app React e GraphQL sarebbe approssimativamente lo stesso. Dopodiché, se si passa alla visualizzazione iniziale e si torna al server GraphQL, l'ora non cambierà. Ciò mostra che i dati sono memorizzati nella cache.
Passaggio 7: modificare la chiamata loadWithApolloclient in loadStudents_noCache
Se modifichi il metodo di caricamento in loadStudents_noCachenel costruttore di StudentComponent, l'output non memorizzerà i dati nella cache. Questo mostra la differenza tra caching e non caching.
this.loadStudents_noCache().then(data => {
this.setState({
students:data.students,
serverTime:data.getTime
})
})
Dall'output di cui sopra, è chiaro che se si passa avanti e indietro tra le schede, l'ora dal server graphql sarà sempre l'ultima, il che significa che i dati non vengono memorizzati nella cache.