Cum se creează un API Secure Node.js GraphQL
Publicat: 2022-03-11În acest articol, ne propunem să prezentăm un ghid rapid despre cum să creați un API Securizat Node.js GraphQL.
Câteva întrebări care pot veni în minte ar putea fi:
- Care este scopul utilizării unui API GraphQL?
- Ce este un API GraphQL?
- Ce este o interogare GraphQL?
- Care este beneficiul GraphQL?
- Este GraphQL mai bun decât REST?
- De ce folosim Node.js?
Toate acestea sunt întrebări valide, dar înainte de a le răspunde, ar trebui să ne aruncăm într-o scurtă prezentare a stării actuale a dezvoltării web:
- Aproape fiecare soluție pe care o veți găsi astăzi utilizează un fel de interfață de programare a aplicațiilor (API).
- Chiar dacă utilizați doar o rețea socială, cum ar fi Facebook sau Instagram, sunteți în continuare conectat la un front-end care consumă un API.
- Dacă ești curios, vei descoperi că aproape toate serviciile de divertisment online folosesc un alt tip de API, inclusiv servicii precum Netflix, Spotify și YouTube.
Practic, în fiecare scenariu, veți găsi un API pe care nu trebuie să îl cunoașteți în detaliu, de exemplu, nu trebuie să știți cum au fost construite și nu trebuie să utilizați aceeași tehnologie în care au fost înainte. capabil să-l integreze în propriul sistem. API-ul furnizat vă permite să oferiți o modalitate de a comunica între servicii într-un standard comun pe care atât serviciul, cât și clientul îl pot comunica fără a fi nevoit să depindeți de o anumită stivă de tehnologie.
Cu un API bine structurat, este posibil să existe un API solid, mentenabil și scalabil, care poate deservi mai multe tipuri de clienți și aplicații front-end.
Acestea fiind spuse, ce este API-ul GraphQL?
GraphQL este un limbaj de interogare pentru API, dezvoltat pentru uz intern în Facebook și publicat pentru uz public în 2015. Acceptă citirea, scrierea și actualizări în timp real. Este, de asemenea, open source și este de obicei comparat cu REST și alte arhitecturi. Pe scurt, se bazează pe:
- Interogări GraphQL - Acest lucru permite clientului să citească și să manipuleze modul în care ar trebui să fie primite datele.
- Mutații GraphQL - Iată cum se scrie datele pe server. Este convenția GraphQL despre cum să scrieți date în sistem.
Deși acest articol ar trebui să demonstreze un scenariu simplu, dar real, despre cum să construiți și să utilizați API-urile GraphQL, nu vom oferi o introducere detaliată în GraphQL. Motivul este simplu, deoarece echipa GraphQL oferă o documentație cuprinzătoare și enumeră mai multe bune practici în Introducerea în GraphQL.
Ce este o interogare GraphQL?
După cum s-a descris mai sus, o interogare este modul în care un client poate citi și manipula datele din API. Puteți trece tipul unui obiect și puteți selecta ce fel de câmpuri doriți să primiți înapoi. O interogare simplă ar fi următoarea:
query{ users{ firstName, lastName } }
În această interogare, încercăm să ajungem la toți utilizatorii din schema utilizatorilor noștri, dar primim doar firstName
și lastName
. Rezultatul acestei interogări ar fi ca, de exemplu:
{ "data": { "users": [ { "firstName": "Marcos", "lastName": "Silva" }, { "firstName": "Paulo", "lastName": "Silva" } ] } }
Este destul de simplu pentru utilizarea clientului.
Care este scopul utilizării unui API GraphQL?
Scopul creării unui API este abilitatea de a avea software ca serviciu care poate fi integrat de alte servicii externe. Chiar dacă aplicația dvs. este consumată de un singur front-end, puteți considera acest front-end ca un serviciu extern și, pentru asta, veți putea lucra în diferite proiecte atunci când comunicarea dintre cele două este asigurată prin intermediul API-ului.
Dacă lucrați într-o echipă mare, aceasta poate fi împărțită pentru a crea o echipă front-end și back-end, permițându-le ambilor să folosească aceeași tehnologie și să-și facă munca mai ușoară. Când proiectați un API, este important să alegeți cea mai potrivită pentru proiect și ceea ce vă aduce mai aproape de soluția dorită.
În acest articol, ne vom concentra pe un schelet pentru construirea unui API care utilizează GraphQL.
Este GraphQL mai bun decât REST?
Poate fi un pic o retragere, dar nu mă pot abține: asta depinde .
GraphQL este o abordare care se potrivește foarte bine mai multor scenarii. REST este o abordare arhitecturală care este dovedită și în mai multe scenarii. În zilele noastre, există o mulțime de articole care explică de ce unul este mai bun decât celălalt sau de ce ar trebui să utilizați doar REST în loc de GraphQL. Și, de asemenea, o mulțime de moduri prin care puteți utiliza GraphQL intern și să mențineți în continuare punctele finale ale API-ului ca arhitectură bazată pe REST.
Cea mai bună îndrumare ar fi să cunoașteți beneficiile fiecărei abordări, să analizați soluția pe care o creați, să evaluați cât de confortabil este echipa dvs. să lucreze cu soluția și să evaluați dacă veți putea sau nu să vă ghidați echipa să învețe și să ajungă la curent. viteză rapid înainte de a alege între abordări.
Acest articol este mai degrabă un ghid practic decât o comparație subiectivă a GraphQL și REST. În cazul în care doriți să citiți o comparație detaliată a celor două, vă sugerez să consultați încă unul dintre articolele noastre, GraphQL vs. REST - A GraphQL Tutorial.
În articolul de astăzi, ne vom concentra pe crearea unui API GraphQL folosind Node.js.
De ce folosim Node.js?
GraphQL are mai multe biblioteci diferite pe care le puteți utiliza. În scopul acestui articol, am decis să mergem cu ideea de a folosi JavaScript cu Node.js datorită utilizării lor pe scară largă și a faptului că Node.js permite dezvoltatorilor să folosească sintaxa familiară front-end pentru dezvoltarea pe server.
De asemenea, este util să comparăm cu abordarea noastră cu un API bazat pe REST, similar cu cel care a fost demonstrat într-un alt articol Toptal Engineering Blog: Crearea unui API REST securizat în Node.js. Acest articol prezintă, de asemenea, utilizarea Node.js cu Express pentru a dezvolta un schelet API REST care vă va permite să comparați unele diferențe între aceste două abordări. Node.js a fost, de asemenea, proiectat cu aplicații de rețea scalabile, o comunitate globală și mai multe biblioteci open-source pe care le puteți găsi pe site-ul web npm.
De data aceasta, vom arăta cum să construim un schelet API cu GraphQL, Node.js și Express!
Tutorial hands on GraphQL
După cum sa subliniat mai devreme, vom construi o idee schelet pentru API-ul GraphQL și va trebui să cunoașteți elementele de bază ale Node.js și Express înainte de a continua. Codul sursă al proiectului realizat pentru acest exemplu GraphQL este disponibil aici.
Vom gestiona două tipuri de resurse:
- Utilizatori, pentru care ne vom ocupa de un CRUD de bază.
- Produse, pentru care vom avea un pic de detalii pentru a arăta mai mult din puterea GraphQL.
Utilizatorii vor conține următoarea structură:
- id
- Nume
- numele de familie
- parola
- permissionLevel
Produsele vor conține următoarea structură:
- id
- Nume
- Descriere
- Preț
În ceea ce privește standardul de codare, vom folosi TypeScript pentru acest proiect. În fișierul sursă, veți putea configura totul pentru a începe codarea cu TypeScript.
Hai să codificăm!
În primul rând, asigurați-vă că aveți instalată cea mai recentă versiune Node.js. La momentul publicării, versiunea actuală este 10.15.3, conform Nodejs.org.
Inițializarea Proiectului
Să începem într-un folder nou pe care îl putem numi node-graphql
. Acolo, putem deschide un terminal sau o consolă Git CLI și începem magia folosind următoarea comandă: npm init
.
Configurarea dependențelor și TypeScript
Pentru a accelera procesul, înlocuirea package.json
cu următoarele în depozitul nostru Git ar trebui să conțină toate dependențele necesare:
{ "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" } }
Cu package.json
actualizat.json, doar apăsați din nou terminalul și utilizați: npm install
. Va instala toate dependențele necesare pentru a rula acest API GraphQL în Node.js și Express.
Următoarea piesă este să configurați modul nostru TypeScript. Avem nevoie de un fișier numit tsconfig.json
în folderul nostru rădăcină cu următoarele:
{ "compilerOptions": { "target": "ES2016", "module": "commonjs", "outDir": "./build", "strict": true, "esModuleInterop": true } }
Logica codului pentru această configurație va fi prezentă în folderul aplicației. Acolo putem crea un fișier app.ts
și pentru testarea de bază adăugați următorul cod acolo:
console.log('Hello Graphql Node API tutorial');
Prin configurația noastră, acum putem rula npm start
și așteptăm o versiune și putem testa dacă totul funcționează corect. În consola terminalului, ar trebui să vedeți „Tutorialul nostru API-ului GraphQL Node”. În scena din spate, configurația completează practic codul TypeScript în JavaScript pur și apoi execută build
noastră în folderul de compilare.

Acum să configuram un schelet de bază pentru API-ul nostru GraphQL. Pentru a începe proiectul nostru, vom adăuga trei importuri de bază:
- Expres
- Express-graphql
- Instrumente Graphql
Să începem să punem totul cap la cap:
import express from 'express'; import graphqlHTTP from 'express-graphql'; import {makeExecutableSchema} from 'graphql-tools';
Acum ar trebui să putem începe să codificăm puțin. Următorul pas este să ne ocupăm de aplicația noastră în Express și de configurația de bază GraphQL, cum ar fi:
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}!`));
Ceea ce facem este:
- Activarea portului 3000 pentru aplicația noastră de server Express.
- Definirea interogărilor și mutațiilor pe care dorim să le folosim ca exemplu rapid.
- Definirea modului în care vor funcționa interogările și mutațiile.
Bine, dar ce se întâmplă cu typeDef-uri și soluții, precum și cu relația cu interogările și mutațiile?
- typeDefs - Definiția schemei noastre a ceea ce ne putem aștepta de la interogări și mutații.
- Rezolvatori - În loc de așteptarea câmpurilor sau a parametrilor necesari, aici definim funcțiile și comportamentele cum ar trebui să funcționeze interogările și mutațiile.
- Interogări - „obținerile” pe care vrem să le citim de pe server.
- Mutații - Solicitările noastre care vor afecta orice date pe care le avem pe propriul nostru server.
Acum, să rulăm npm start din nou pentru a vedea ce avem acolo. Ne-am aștepta ca aplicația să ruleze cu următorul mesaj: Node Graphql API ascultând pe portul 3000!
Acum putem încerca să interogăm și să testăm API-ul GraphQL pe propriul nostru server prin: http://localhost:3000/graphql
Grozav, acum putem scrie prima noastră interogare care a fost definită ca „bună ziua”.
Rețineți că, așa cum am definit-o la typeDefs
, pagina ne poate ajuta să construim interogarea.
Este grozav, dar cum putem schimba valoarea? Mutații!
Acum, să vedem ce se întâmplă când ne schimbăm valoarea în memorie cu o mutație:
Acum putem face operațiuni CRUD de bază cu API-ul nostru GraphQL Node.js. Să avansăm cu codul nostru acum.
Produse
Pentru produse, vom folosi un modul numit produse. Ca un efort de a simplifica acest articol, vom folosi o bază de date în memorie doar pentru demonstrație. Vom defini un model și un serviciu pentru gestionarea produselor.
Modelul nostru se va baza după cum urmează:
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; } }
Serviciul care va comunica cu GraphQL va fi definit ca:
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; }; } }
Utilizatori
Pentru utilizatori, vom urma aceeași structură ca și modulul de produse. Vom avea un model și un serviciu pentru utilizatori. Modelul va fi definit astfel:
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; } }
Între timp, serviciul nostru va fi astfel:
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; }; } }
Pentru a vă reaminti, codul sursă este disponibil pentru utilizare de la acest link.
Acum putem juca și testa codul nostru. Să rulăm npm start
. Vom avea serverul care rulează la portul 3000. Acum putem accesa GraphQL pentru testare la http://localhost:3000/graphql.
Să încercăm o mutație pentru a adăuga un articol la lista noastră de produse:
Pentru a testa dacă a funcționat, vom folosi acum o interogare pentru produse, dar primim doar id
, name
și price
:
query{ products{ id, name, price } } The response will be: { "data": { "products": [ { "id": 100, "name": "My amazing product", "price": 400 } ] } }
Si asta e; produsul funcționează conform așteptărilor. Acum putem să ne jucăm și să schimbăm câmpurile dacă vrem. Puteți încerca să adăugați o descriere:
query{ products{ id, name, description, price } }
Acum putem avea descrierile produselor noastre. Să încercăm utilizatorii acum.
mutation{ user(id:200, firstName:"Marcos", lastName:"Silva", password:"amaz1ingP4ss", permissionLevel:9, email:"[email protected]") { id } }
Și o interogare va fi ca:
query{ users{ id, firstName, lastName, password, email } }
Cu un răspuns de genul:
{ "data": { "users": [ { "id": 200, "firstName": "Marcos", "lastName": "Silva", "password": "kpj6Mq0tGChGbZ+BT9Nw6RMCLReZEPPyBCaUS3X23lZwCCp1Ogb94/oqJlya0xOBdgEbUwqRSuZRjZGhCzLdeQ==", "email": "[email protected]" } ] } }
Și acum scheletul nostru GraphQL este gata! Există o mulțime de pași de aici către un API util, complet funcțional, dar nucleul de bază este acum setat.
Rezumat și gânduri finale
Chiar și margini de tăiere pentru a scurta, articolul este destul de mare, cu o mulțime de informații de bază privind dezvoltarea unui API GraphQL Node.js.
Să revizuim ceea ce am acoperit până acum:
- Utilizarea Node.js cu Express și GraphQL pentru a construi un API GraphQL;
- Utilizarea de bază a GraphQL;
- Utilizarea de bază a interogărilor și mutațiilor;
- Abordare de bază pentru crearea de module pentru proiectul dvs.;
- Testarea API-ului nostru GraphQL;
Pentru a ne concentra mai mult pe partea de dezvoltare a lucrurilor, am evitat câteva elemente importante care pot fi rezumate pe scurt după cum urmează:
- Validari pentru articole noi;
- Gestionarea corectă a erorilor cu un serviciu de erori generic;
- Validarea câmpurilor pe care un utilizator le poate folosi la fiecare solicitare cu un serviciu generic;
- Adăugați un interceptor JWT pentru a securiza API-ul;
- Gestionați hash-ul parolei cu o abordare mai eficientă;
- Adăugați teste de unitate și de integrare;
Amintiți-vă că avem codul sursă complet la acest link Git. Simțiți-vă liber să utilizați, să bifurcați, să deschideți probleme, să faceți solicitări de tragere și să jucați cu el! Vă rugăm să rețineți că toate standardele și sugestiile făcute în acest articol nu sunt sculptate în piatră.
Aceasta este doar una dintre multele abordări care pot fi folosite pentru a începe să vă proiectați propriul API GraphQL. De asemenea, asigurați-vă că citiți și explorați GraphQL mai detaliat, aflați ce are de oferit și cum vă poate îmbunătăți API-urile.