Come creare un'API GraphQL Node.js sicura
Pubblicato: 2022-03-11In questo articolo, miriamo a presentare una guida rapida su come creare un'API GraphQL Node.js sicura.
Alcune domande che potrebbero venire in mente potrebbero essere:
- Qual è lo scopo dell'utilizzo di un'API GraphQL?
- Che cos'è un'API GraphQL?
- Che cos'è una query GraphQL?
- Qual è il vantaggio di GraphQL?
- GraphQL è migliore di REST?
- Perché utilizziamo Node.js?
Sono tutte domande valide, ma prima di rispondere, dovremmo tuffarci in una breve panoramica dello stato attuale dello sviluppo web:
- Quasi tutte le soluzioni che troverai oggi utilizzano una sorta di API (Application Programming Interface).
- Anche se utilizzi solo un social network, come Facebook o Instagram, sei comunque connesso a un front-end che utilizza un'API.
- Se sei curioso, scoprirai che quasi tutti i servizi di intrattenimento online utilizzano un diverso tipo di API, inclusi servizi come Netflix, Spotify e YouTube.
Praticamente in ogni scenario, troverai un'API che non è necessario conoscere in dettaglio, ad esempio, non è necessario sapere come sono state create e non è necessario utilizzare la stessa tecnologia di una volta in grado di integrarlo nel proprio sistema. L'API fornita consente di offrire un modo per comunicare tra i servizi in uno standard comune che sia il servizio che il client possono comunicare senza dover dipendere da uno stack tecnologico specifico.
Con un'API ben strutturata, è possibile avere un'API solida, manutenibile e scalabile in grado di servire più tipi di client e applicazioni front-end.
Detto questo, cos'è l'API GraphQL?
GraphQL è un linguaggio di query per API, sviluppato per uso interno in Facebook e pubblicato per uso pubblico nel 2015. Supporta lettura, scrittura e aggiornamenti in tempo reale. È anche open source ed è comunemente paragonato a REST e ad altre architetture. Si basa, in estrema sintesi, su:
- Query GraphQL : ciò consente al client di leggere e manipolare il modo in cui i dati devono essere ricevuti.
- Mutazioni GraphQL : ecco come scrivere i dati sul server. È la convenzione GraphQL su come scrivere i dati nel sistema.
Sebbene questo articolo dovrebbe dimostrare uno scenario semplice ma reale su come creare e utilizzare le API GraphQL, non forniremo un'introduzione dettagliata a GraphQL. Il motivo è semplice, poiché il team di GraphQL fornisce una documentazione completa ed elenca diverse best practice nella loro Introduzione a GraphQL.
Che cos'è una query GraphQL?
Come descritto in precedenza, una query è il modo in cui un client può leggere e manipolare i dati dall'API. Puoi passare il tipo di un oggetto e selezionare il tipo di campi che desideri ricevere. Una semplice query sarebbe la seguente:
query{ users{ firstName, lastName } }
In questa query, stiamo cercando di raggiungere tutti gli utenti dallo schema dei nostri utenti ma ricevendo solo firstName
e lastName
. Il risultato di questa query sarebbe, ad esempio:
{ "data": { "users": [ { "firstName": "Marcos", "lastName": "Silva" }, { "firstName": "Paulo", "lastName": "Silva" } ] } }
È abbastanza semplice per l'utilizzo da parte del client.
Qual è lo scopo dell'utilizzo di un'API GraphQL?
Lo scopo della creazione di un'API è la possibilità di avere un software come servizio che può essere integrato da altri servizi esterni. Anche se la tua applicazione viene utilizzata da un unico front-end, puoi considerare questo front-end come un servizio esterno e, per questo, sarai in grado di lavorare in progetti diversi quando la comunicazione tra i due viene fornita tramite l'API.
Se lavori in un team numeroso, puoi dividerlo per creare un team front-end e back-end, consentendo a entrambi di utilizzare la stessa tecnologia e semplificare il proprio lavoro. Quando si progetta un'API, è importante scegliere la soluzione migliore per il progetto e ciò che ti avvicina alla soluzione desiderata.
In questo articolo, ci concentreremo su uno scheletro per la creazione di un'API che utilizza GraphQL.
GraphQL è migliore di REST?
Potrebbe essere un po' una scappatoia, ma non posso farne a meno: dipende .
GraphQL è un approccio che si adatta molto bene a diversi scenari. REST è un approccio all'architettura dimostrato anche in diversi scenari. Al giorno d'oggi, ci sono tonnellate di articoli che spiegano perché uno è migliore dell'altro o perché dovresti usare solo REST invece di GraphQL. Inoltre, molti modi in cui puoi utilizzare GraphQL internamente e continuare a mantenere gli endpoint dell'API come un'architettura basata su REST.
La migliore guida sarebbe conoscere i vantaggi di ciascun approccio, analizzare la soluzione che stai creando, valutare quanto il tuo team sta lavorando con la soluzione e valutare se sarai in grado di guidare il tuo team ad imparare e ad arrivare a accelerare velocemente prima di scegliere tra gli approcci.
Questo articolo è più una guida pratica piuttosto che un confronto soggettivo di GraphQL e REST. Nel caso in cui desideri leggere un confronto dettagliato tra i due, ti suggerisco di consultare un altro dei nostri articoli, GraphQL vs. REST - A GraphQL Tutorial.
Nell'articolo di oggi, ci concentreremo sulla creazione di un'API GraphQL utilizzando Node.js.
Perché utilizziamo Node.js?
GraphQL ha diverse librerie che puoi usare. Ai fini di questo articolo, abbiamo deciso di adottare l'idea di utilizzare JavaScript con Node.js a causa del loro uso diffuso e del fatto che Node.js consente agli sviluppatori di utilizzare la familiare sintassi front-end per lo sviluppo lato server.
È anche utile confrontare il nostro approccio con un'API basata su REST, simile a quella illustrata in un altro articolo del blog di Toptal Engineering: Creazione di un'API REST sicura in Node.js. Questo articolo illustra anche l'uso di Node.js con Express per sviluppare un'API REST scheletrica che consentirà di confrontare alcune differenze tra questi due approcci. Node.js è stato inoltre progettato con applicazioni di rete scalabili, una comunità globale e diverse librerie open source che puoi trovare sul sito Web di npm.
Questa volta, mostreremo come creare un'API scheletro con GraphQL, Node.js ed Express!
Esercitazione pratica su GraphQL
Come accennato in precedenza, creeremo un'idea schematica per l'API GraphQL e prima di procedere dovrai conoscere le basi di Node.js ed Express. Il codice sorgente del progetto realizzato per questo esempio GraphQL è disponibile qui.
Gestiremo due tipi di risorse:
- Utenti, per i quali tratteremo un CRUD di base.
- Prodotti, per i quali avremo un po' di dettagli per mostrare di più la potenza di GraphQL.
Gli utenti conterranno la seguente struttura:
- ID
- nome di battesimo
- cognome
- parola d'ordine
- livello di autorizzazione
I prodotti conterranno la seguente struttura:
- ID
- nome
- descrizione
- prezzo
Per quanto riguarda lo standard di codifica, useremo TypeScript per questo progetto. Nel file sorgente, sarai in grado di configurare tutto per iniziare a scrivere codice con TypeScript.
Codiciamo!
Prima di tutto, assicurati di aver installato l'ultima versione di Node.js. Al momento della pubblicazione, la versione attuale è la 10.15.3, come da Nodejs.org.
Inizializzazione del progetto
Iniziamo in una nuova cartella che possiamo nominare node-graphql
. Lì, possiamo aprire un terminale o una console Git CLI e avviare la magia usando il seguente comando: npm init
.
Configurazione delle nostre dipendenze e TypeScript
Per accelerare il processo, la sostituzione di package.json
con quanto segue nel nostro repository Git dovrebbe contenere tutte le dipendenze necessarie:
{ "name": "node-graphql", "version": "1.0.0", "description": "", "main": "dist/index.js", "scripts": { "tsc": "tsc", "start": "npm run tsc && node ./build/app.js" }, "author": "", "license": "ISC", "dependencies": { "@types/express": "^4.16.1", "@types/express-graphql": "^0.6.2", "@types/graphql": "^14.0.7", "express": "^4.16.4", "express-graphql": "^0.7.1", "graphql": "^14.1.1", "graphql-tools": "^4.0.4" }, "devDependencies": { "tslint": "^5.14.0", "typescript": "^3.3.4000" } }
Con il package.json
aggiornato, premi di nuovo il terminale e usa: npm install
. Installerà tutte le dipendenze necessarie per eseguire questa API GraphQL all'interno di Node.js ed Express.
Il prossimo passo è configurare la nostra modalità TypeScript. Abbiamo bisogno di un file chiamato tsconfig.json
nella nostra cartella principale con quanto segue:
{ "compilerOptions": { "target": "ES2016", "module": "commonjs", "outDir": "./build", "strict": true, "esModuleInterop": true } }
La logica del codice per questa configurazione sarà presente nella cartella dell'app. Lì possiamo creare un file app.ts
e per i test di base aggiungere il seguente codice lì:
console.log('Hello Graphql Node API tutorial');
Con la nostra configurazione, ora possiamo eseguire npm start
e attendere una build ed essere in grado di testare che tutto funzioni correttamente. Nella console del tuo terminale, dovresti vedere il nostro "esercitazione sull'API del nodo GraphQL". Nella scena posteriore, la configurazione fondamentalmente compila il codice TypeScript in puro JavaScript e quindi esegue la nostra build nella cartella build
.

Ora configuriamo uno scheletro di base per la nostra API GraphQL. Per iniziare il nostro progetto, aggiungeremo tre importazioni di base:
- Esprimere
- Express-graphql
- Strumenti Graphql
Iniziamo a mettere insieme il tutto:
import express from 'express'; import graphqlHTTP from 'express-graphql'; import {makeExecutableSchema} from 'graphql-tools';
Ora dovremmo essere in grado di iniziare a programmare un po'. Il prossimo passo è gestire la nostra app in Express e la configurazione di base di GraphQL come:
import express from 'express'; import graphqlHTTP from 'express-graphql'; import {makeExecutableSchema} from 'graphql-tools'; const app: express.Application = express(); const port = 3000; let typeDefs: any = [` type Query { hello: String } type Mutation { hello(message: String) : String } `]; let helloMessage: String = 'World!'; let resolvers = { Query: { hello: () => helloMessage }, Mutation: { hello: (_: any, helloData: any) => { helloMessage = helloData.message; return helloMessage; } } }; app.use( '/graphql', graphqlHTTP({ schema: makeExecutableSchema({typeDefs, resolvers}), graphiql: true }) ); app.listen(port, () => console.log(`Node Graphql API listening on port ${port}!`));
Quello che stiamo facendo è:
- Abilitazione della porta 3000 per la nostra app server Express.
- Definire quali query e mutazioni vogliamo utilizzare come rapido esempio.
- Definire come funzioneranno le query e le mutazioni.
OK, ma cosa sta succedendo per typeDefs e resolver, così come in relazione a query e mutazioni?
- typeDefs - La definizione del nostro schema di ciò che possiamo aspettarci da query e mutazioni.
- Risolutori - Invece dell'aspettativa di campi o parametri richiesti, qui definiamo le funzioni e i comportamenti di come dovrebbero funzionare le query e le mutazioni.
- Query - I "get" che vogliamo leggere dal server.
- Mutazioni - Le nostre richieste che influenzeranno tutti i dati che abbiamo sul nostro server.
Ora, eseguiamo di nuovo npm start per vedere cosa abbiamo lì. Ci si aspetterebbe che l'app venga eseguita con il seguente messaggio: Node Graphql API in ascolto sulla porta 3000!
Ora possiamo provare a interrogare e testare l'API GraphQL sul nostro server tramite: http://localhost:3000/graphql
Ottimo, ora possiamo scrivere la nostra prima query personale che è stata definita "ciao".
Nota che il modo in cui l'abbiamo definito in typeDefs
, la pagina può aiutarci a costruire la query.
È fantastico, ma come possiamo cambiare il valore? Mutazioni!
Ora, vediamo cosa succede quando cambiamo il nostro valore in memoria con una mutazione:
Ora possiamo eseguire operazioni CRUD di base con la nostra API GraphQL Node.js. Andiamo avanti con il nostro codice ora.
Prodotti
Per i prodotti, utilizzeremo un modulo chiamato prodotti. Per semplificare questo articolo, utilizzeremo un database in memoria solo a scopo dimostrativo. Definiremo un modello e un servizio per la gestione dei prodotti.
Il nostro modello sarà basato come segue:
export class Product { private id: Number = 0; private name: String = ''; private description: String = ''; private price: Number = 0; constructor(productId: Number, productName: String, productDescription: String, price: Number) { this.id = productId; this.name = productName; this.description = productDescription; this.price = price; } }
Il servizio che comunicherà con GraphQL sarà definito come:
export class ProductsService { public products: any = []; configTypeDefs() { let typeDefs = ` type Product { name: String, description: String, id: Int, price: Int } `; typeDefs += ` extend type Query { products: [Product] } `; typeDefs += ` extend type Mutation { product(name:String, id:Int, description: String, price: Int): Product! }`; return typeDefs; } configResolvers(resolvers: any) { resolvers.Query.products = () => { return this.products; }; resolvers.Mutation.product = (_: any, product: any) => { this.products.push(product); return product; }; } }
Utenti
Per gli utenti, seguiremo la stessa struttura del modulo prodotti. Avremo un modello e un servizio per gli utenti. Il modello sarà definito come:
export class User { private id: Number = 0; private firstName: String = ''; private lastName: String = ''; private email: String = ''; private password: String = ''; private permissionLevel: Number = 1; constructor(id: Number, firstName: String, lastName: String, email: String, password: String, permissionLevel: Number) { this.id = id; this.firstName = firstName; this.lastName = lastName; this.email = email; this.password = password; this.permissionLevel = permissionLevel; } }
Nel frattempo, il nostro servizio sarà come:
const crypto = require('crypto'); export class UsersService { public users: any = []; configTypeDefs() { let typeDefs = ` type User { firstName: String, lastName: String, id: Int, password: String, permissionLevel: Int, email: String } `; typeDefs += ` extend type Query { users: [User] } `; typeDefs += ` extend type Mutation { user(firstName:String, lastName: String, password: String, permissionLevel: Int, email: String, id:Int): User! }`; return typeDefs; } configResolvers(resolvers: any) { resolvers.Query.users = () => { return this.users; }; resolvers.Mutation.user = (_: any, user: any) => { let salt = crypto.randomBytes(16).toString('base64'); let hash = crypto.createHmac('sha512', salt).update(user.password).digest("base64"); user.password = hash; this.users.push(user); return user; }; } }
Ricordiamo che il codice sorgente è disponibile per l'uso da questo link.
Ora possiamo giocare e testare il nostro codice. npm start
. Avremo il server in esecuzione sulla porta 3000. Ora possiamo accedere a GraphQL per il test su http://localhost:3000/graphql.
Proviamo una mutazione per aggiungere un articolo alla nostra lista di prodotti:
Per verificare se ha funzionato, useremo ora una query per i prodotti, ma riceveremo solo id
, name
e price
:
query{ products{ id, name, price } } The response will be: { "data": { "products": [ { "id": 100, "name": "My amazing product", "price": 400 } ] } }
E questo è tutto; il prodotto funziona come previsto. Ora possiamo giocare e cambiare campo se vogliamo. Puoi provare ad aggiungere una descrizione:
query{ products{ id, name, description, price } }
Ora possiamo avere le descrizioni dei nostri prodotti. Proviamo gli utenti ora.
mutation{ user(id:200, firstName:"Marcos", lastName:"Silva", password:"amaz1ingP4ss", permissionLevel:9, email:"[email protected]") { id } }
E una query sarà come:
query{ users{ id, firstName, lastName, password, email } }
Con una risposta del tipo:
{ "data": { "users": [ { "id": 200, "firstName": "Marcos", "lastName": "Silva", "password": "kpj6Mq0tGChGbZ+BT9Nw6RMCLReZEPPyBCaUS3X23lZwCCp1Ogb94/oqJlya0xOBdgEbUwqRSuZRjZGhCzLdeQ==", "email": "[email protected]" } ] } }
E ora il nostro scheletro GraphQL è pronto! Ci sono un sacco di passaggi da qui verso un'API utile e completamente funzionale, ma ora il nucleo di base è impostato.
Riassunto e Considerazioni Finali
Anche taglienti per accorciare, l'articolo è abbastanza grande con molte informazioni di base sullo sviluppo di un'API GraphQL Node.js.
Esaminiamo ciò che abbiamo trattato finora:
- Utilizzo di Node.js con Express e GraphQL per creare un'API GraphQL;
- Utilizzo di base di GraphQL;
- Utilizzo di base di query e mutazioni;
- Approccio di base alla creazione di moduli per il tuo progetto;
- Testare la nostra API GraphQL;
Per concentrarci maggiormente sul lato dello sviluppo delle cose, abbiamo evitato diversi elementi importanti che possono essere brevemente riassunti come segue:
- Convalide per nuovi articoli;
- Gestire correttamente gli errori con un servizio di errore generico;
- Convalidare i campi che un utente può utilizzare ad ogni richiesta con un servizio generico;
- Aggiungi un intercettore JWT per proteggere l'API;
- Gestisci l'hash delle password con un approccio più efficace;
- Aggiungere unit e test di integrazione;
Ricorda che abbiamo il codice sorgente completo a questo link Git. Sentiti libero di usare, fork, aprire problemi, fare richieste pull e giocarci! Si prega di notare che tutti gli standard e i suggerimenti forniti in questo articolo non sono scolpiti nella pietra.
Questo è solo uno dei tanti approcci che possono essere utilizzati per iniziare a progettare la tua API GraphQL. Inoltre, assicurati di leggere ed esplorare GraphQL in modo più dettagliato, imparando cosa ha da offrire e come può migliorare le tue API.