RESTful Design API cu NodeJS & Restify

Ce veți crea

API RESTful conține două concepte principale: Resursă, și Reprezentare. Resursa poate fi orice obiect asociat cu date sau identificat cu un URI (mai mult de un URI se poate referi la aceeași resursă) și poate fi operat utilizând metode HTTP. Reprezentarea este modul în care afișați resursa. În acest tutorial vom acoperi câteva informații teoretice despre designul API RESTful și vom implementa un exemplu API de aplicații blogging folosind NodeJS.

Resursă

Alegerea resurselor corecte pentru un API RESTful este o secțiune importantă de proiectare. În primul rând, trebuie să analizați domeniul dvs. de activitate și apoi să decideți câte resurse și ce resurse vor fi utilizate care sunt relevante pentru nevoile dvs. de afaceri. Dacă proiectați un blogging API, probabil că veți folosi Articol, Utilizator, și cometariu. Acestea sunt numele resurselor, iar datele asociate cu acestea sunt resursa în sine:

"title": "Cum de a proiecta API RESTful", "content": "Designul API-ului este un caz foarte important în lumea dezvoltării software-ului.", "author" , "nodejs", "node-restify"] "Categorie": "NodeJS"

Resurse verbe

Puteți continua cu o operațiune de resurse după ce ați decis cu privire la resursele necesare. Operația de aici se referă la metodele HTTP. De exemplu, pentru a crea un articol, puteți face următoarea solicitare:

POST / articole HTTP / 1.1 Gazda: localhost: 3000 Content-Type: application / json "title": " : "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.", "Autor": "huseyinbabal"

În același mod, puteți vizualiza un articol existent prin emiterea următoarei solicitări:

GET / articole / 123456789012 HTTP / 1.1 Gazdă: localhost: 3000 Content-Type: application / json

Dar despre actualizarea unui articol existent? Am auzit că spui:

Pot face o altă solicitare POST la / articles / update / 123456789012 cu sarcina utilă.

Poate fi preferabil, dar URI devine tot mai complex. Așa cum am spus mai devreme, operațiile se pot referi la metode HTTP. Aceasta înseamnă, a se spune Actualizați operație în metoda HTTP în loc de a pune în URI. De exemplu:

PUT / articles / 123456789012 HTTP / 1.1 Host: localhost: 3000 Tip de conținut: application / json "title": "Actualizat modul de proiectare API RESTful", "content" lumea dezvoltării de software "," autor ":" huseyinbabal "," tags ": [" technology "," nodejs "," restify "," încă o etichetă "]" category ":" NodeJS "

Apropo, în acest exemplu vedeți etichete și câmpuri de categorii. Acestea nu trebuie să fie câmpuri obligatorii. Le puteți lăsa goale și le puteți seta în viitor. 

Uneori, trebuie să ștergeți un articol când acesta este depășit. În acest caz, puteți utiliza a ȘTERGE Cererea HTTP către / articole / 123456789012.

Metodele HTTP sunt concepte standard. Dacă le folosiți ca o operațiune, veți avea URI simpli și acest tip de API simplu vă va ajuta să câștigați consumatori fericiți.

Ce se întâmplă dacă doriți să inserați un comentariu la un articol? Puteți selecta articolul și adăuga un comentariu nou la articolul selectat. Prin utilizarea acestei instrucțiuni, puteți utiliza următoarea solicitare:

POST / articole / 123456789012 / comments HTTP / 1.1 Gazda: localhost: 3000 Tipul de conținut: application / json "text": "un tutorial bun", "author": "john doe"

Forma de resursă de mai sus este numită a sub-resurse. cometariu este o sub-resursă a Articol.  cometariu taxa de încărcare de mai sus va fi introdusă în baza de date ca fiind copilul lui Articol. Uneori, un URI diferit se referă la aceeași resursă. De exemplu, pentru a vedea un anumit comentariu, puteți utiliza fie:

GET / articole / 123456789012 / comments / 123 HTTP / 1.1 Gazda: localhost: 3000 Content-Type: aplicație / json 

sau:

GET / comments / 123456789012 HTTP / 1.1 Gazdă: localhost: 3000 Content-Type: application / json

versionare

În general, caracteristicile API se schimbă frecvent pentru a oferi noi caracteristici consumatorilor. În acest caz, pot exista două versiuni ale aceluiași API în același timp. Pentru a separa aceste două caracteristici, puteți utiliza versiunea. Există două forme de versiuni

  1. Versiunea în URI: Puteți furniza numărul versiunii în URI. De exemplu, /v1.1/articles/123456789012.
  2. Versiunea în antet: Furnizați numărul versiunii în antet și niciodată nu modificați URI-ul.De exemplu:
GET / articole / 123456789012 HTTP / 1.1 Gazda: localhost: 3000 Accept-Version: 1.0

De fapt, versiunea schimbă doar reprezentarea resursei, nu conceptul resursei. Deci, nu trebuie să schimbați structura URI. În v1.1, poate a fost adăugat un articol nou la articol. Cu toate acestea, acesta returnează încă un articol. În a doua opțiune, URI este încă simplu și consumatorii nu trebuie să-și schimbe URI-ul în implementările de la client. 

Este important să se elaboreze o strategie pentru situațiile în care consumatorul nu furnizează un număr de versiune. Puteți ridica o eroare atunci când versiunea nu este furnizată sau puteți returna un răspuns folosind prima versiune. Dacă utilizați cea mai recentă versiune stabilă ca valoare implicită, consumatorii pot obține multe erori pentru implementările de pe partea clientului.

Reprezentare

Reprezentarea este modul în care un API afișează resursa. Când apelați un punct final al API, veți primi o resursă. Această resursă poate fi în orice format, cum ar fi XML, JSON, etc. JSON este preferabil dacă proiectați un nou API. Cu toate acestea, dacă actualizați un API existent care a fost utilizat pentru a returna un răspuns XML, puteți oferi o altă versiune pentru un răspuns JSON. 

Asta e suficienta informatie teoretica despre designul API RESTful. Să aruncăm o privire la utilizarea în viața reală prin conceperea și implementarea unui API pentru Blogging folosind Restify.

Blogging REST API

Proiecta

Pentru a proiecta un API RESTful, trebuie să analizăm domeniul de afaceri. Atunci ne putem defini resursele. Într-un API pentru blogging, avem nevoie de:

  • Creați, actualizați, ștergeți, vizualizați Articol
  • Creați un comentariu pentru un anumit domeniu Articol, Actualizați, Ștergeți, Vizualizați, cometariu
  • Creați, actualizați, ștergeți, vizualizați Utilizator

În acest API, nu mă voi referi la modul de autentificare a unui utilizator pentru a crea un articol sau un comentariu. Pentru partea de autentificare, vă puteți referi la autentificarea bazată pe token cu AngularJS & NodeJS tutorial. 

Numele noastre de resurse sunt gata. Operațiunile de resurse sunt pur și simplu CRUD. Puteți consulta tabelul următor pentru o prezentare generală a API.

Numele resursei Verbele HTTP Metode HTTP
Articol crea articolul
actualizați articolul
șterge articolul
vezi articolul
POST / articole cu încărcătură utilă
PUT / articole / 123 cu încărcătură utilă
DELETE / articole / 123
GET / articolul / 123
cometariu creați un comentariu
actualizare comentariu
ștergeți Comentariu
vezi comentariul
POST / articole / 123 / comments with Payload
PUT / comments / 123 cu sarcină utilă
DELETE / comments / 123
GET / comments / 123
Utilizator creaza utilizator
actualizați Utilizatorul
ștergeți Utilizatorul
vizualizați Utilizatorul
POST / utilizatori cu sarcină utilă
PUT / utilizatori / 123 cu sarcină utilă
DELETE / users / 123
GET / utilizatori / 123

Setarea proiectului

În acest proiect vom folosi NodeJS cu Restify. Resursele vor fi salvate în MongoDB Bază de date. Mai întâi, putem defini resursele ca modele în Restify.

Articol

var mongoose = necesită ("mongoose"); var Schema = mongoose.Schema; var ArticolulSchema = schema nouă (title: String, slug: String, conținut: String, autor: type: String, ref: "User"); mongoose.model ("articolul", articolulSchema);

cometariu

var mongoose = necesită ("mongoose"); var Schema = mongoose.Schema; var CommentSchema = schema nouă (text: String, articol: type: String, ref: "Article", autor: type: String, ref: "User"); mongoose.model ("Comentariu", CommentSchema);

Utilizator

Nu va exista nicio operație pentru resursa Utilizator. Vom presupune că știm deja utilizatorul actual care va putea să opereze pe articole sau comentarii.

Puteți întreba de unde provine acest modul de mongoasă. Acesta este cel mai popular cadru ORM pentru MongoDB scris ca modul NodeJS. Acest modul este inclus în proiect într-un alt fișier de configurare. 

Acum putem defini verbul nostru HTTP pentru resursele de mai sus. Puteți vedea următoarele:

var restify = necesită ('restify'), fs = necesită ('fs') var controllers = , controllers_path = process.cwd () +// app / controllers fs.readdirSync (controllers_path) .forEach ) if (file.indexOf ('. js')! = -1) controlerele [file.split ('.' restify.createServer (); server.use (restify.fullResponse ()) .use (restify.bodyParser ()) // Articol Start server.post ("/ articles", controllers.article.createArticle) server.put ("/ articles /: id" (path: "/ articles /: id", versiunea: "1.0.0", controlere. articol.viewArticle) server.get (path: "/ articles /: id", versiunea: "2.0.0", controllers.article.viewArticle_v2) // Sfârșit articol // Comentariu Start server.post (" , controllers.comment.createComment) server.put ("/ comments /: id", controllers.comment.viewComment) server.del ("/ comments /: id", controllers.comment.deleteComment) /: id ", controllers.comment.viewComment) // Comentariu Sfârșitul var port = process.env.PORT || 3000; server.listen (port, functie (err) if (err) console.error (err) altceva console.log (' ) process.on ('uncaughtException', funcția (err) console.error (JSON.parse (JSON.stringify (err, ['stack', 'message'

În acest fragment de cod, în primul rând fișierele controlerului care conțin metode de controler sunt iterate și toate controloanele sunt inițializate pentru a executa o cerere specifică către URI. Ulterior, URI-urile pentru operațiuni specifice sunt definite pentru operațiile CRUD de bază. Există, de asemenea, versiuni pentru una dintre operațiunile pe articolul. 

De exemplu, dacă precizați versiunea ca fiind 2 în antetul Accept-Version, viewArticle_v2 va fi executat. viewArticle și viewArticle_v2 ambele fac același loc de muncă, arătând resursa, dar arată articolul Resurse într-un alt format, după cum puteți vedea în titlu câmpul de mai jos. În cele din urmă, serverul este pornit pe un anumit port și se aplică anumite verificări de raportare a erorilor. Putem continua cu metode de controler pentru operațiile HTTP pe resurse.

article.js

var mongoose = necesită ('mongoose'), articolul = mongoose.model ("Articol"), ObjectId = mongoose.Types.ObjectId exports.createArticle = funcția (req, res, next) var articleModel = ); (err) res.status (500); res.json (tip: false, date: eroare, type: true, data: article)) exports.viewArticle = funcția (req, res, next) article.findById (new ObjectId (req.params.id) err) res.status (500); res.json (tip: false, date: "Eroare a apărut:" + err altceva if (article) res.json ) altceva res.json (type: false, data: "Article:" + req.params.id + "not found" exports.viewArticle_v2 = Articolul.findById (nou ObjectId (req.params.id), funcția (err, articolul) if (err) res.status (500); + err) altceva if (articolul) article.title = article.title + "v2" res.json (type: true, data: article) else res.json : "Articol:" + req.params.id + "nu a fost găsit") exports.updateArticle = funcția (req, res, next) var updatedArticleModel = articol nou (req.body); Article.findByIdAndUpdate (new ObjectId (req.params.id), updatedArticleModel, funcția (err, article) if (err) res.status (500); res.json "else if (article) res.json (type: true, data: article altceva res.json (type: false, data: Article + req.params. id = "nu a fost găsit") exports.deleteArticle = funcția (req, res, urm) article.findByIdAndRemove (new Object (req.params.id) ) res.status (500); res.json (tip: false, date: "Eroare a apărut:" + err altceva res.json (type: true; params.id + "șters cu succes" 

Puteți găsi o explicație a operațiilor CRUD de bază pe partea Mongoose de mai jos:

  • createarticle: Acest lucru este simplu Salvați funcționare pe articleModel trimise de la organismul de solicitare. Un nou model poate fi creat prin trecerea corpului solicitării ca constructor unui model asemănător var articolModel = articol nou (req.body)
  • viewArticle: Pentru a vedea detalii despre articol, este necesar un ID de articol în parametrul URL. găsește una cu un parametru ID este suficient pentru a returna detaliile articolului.
  • updateArticle: Actualizarea articolului este o interogare de căutare simplă și unele manipulări de date pe articolul returnat. În cele din urmă, modelul actualizat trebuie salvat în baza de date prin emiterea unui Salvați comanda.
  • deleteArticle: findByIdAndRemove este cel mai bun mod de a șterge un articol prin furnizarea codului de articol.

Comenzile Mongoose menționate mai sus sunt pur și simplu metode statice cum ar fi obiectul Articol care este, de asemenea, o referință a schemei Mongoose.

comment.js

var mongoose = necesită ('mongoose'), Comentariu = mongoose.model ("Comentariu"), articolul = mongoose.model ("Articol"), ObjectId = mongoose.Types.ObjectId exports.viewComment = Article.findOne ("comments._id": new ObjectId (req.params.id), "comments. $": 1, funcția (err, comment) if (err) res.status ; res.json (type: false, data: "Eroare a apărut:" + err) altceva if (comment) res.json (type: true; ) altfel res.json (type: false, date: "Comment:" + req.params.id + "nu a fost găsit" exports.updateComment = var updatedCommentModel = nou comentariu (req.body); console.log (updatedCommentModel) Articol.update ("comments._id": new ObjectId (req.params.id), "$ set": comment.text.text: updatedCommentModel.text ". $ .author ": updatedCommentModel.author, funcția (err) if (err) res.status (500); res.json (type: false, data: res.json (type: true, data: "Comentariu:" + req.params.id + "actualizat" exports.deleteComment = "comments._id": new ObjectId (req.params.id), "pull": "comments": "_id": new ObjectId (req.params.id) articolul if (article) res.jus (type: error: if (err) res.status (500); res.json (type: false, data: "Comentariu:" + req.params.id + "nu a fost gasit"))

Când faceți o solicitare la unul dintre resursele URI de resurse, va fi executată funcția asociată menționată în controler. Fiecare funcție din interiorul fișierelor controlerului poate folosi req și res obiecte. cometariu resursa aici este o sub-resursă a Articol. Toate operațiile de interogare sunt realizate prin intermediul modelului Articol pentru a găsi un sub-document și a efectua actualizarea necesară. Cu toate acestea, ori de câte ori încercați să vizualizați o resursă Comentariu, veți vedea una chiar dacă nu există nici o colecție în MongoDB.  

Alte sugestii de design

  • Selectați resurse ușor de înțeles pentru a le oferi consumatorilor o utilizare ușoară.
  • Lăsați logica de afaceri să fie pusă în aplicare de către consumatori. De exemplu, resursa articolului are un câmp numit melc. Consumatorii nu trebuie să trimită acest detaliu la API-ul REST. Această strategie de blocaj ar trebui să gestioneze pe partea REST API pentru a reduce legătura dintre API și consumatori. Consumatorii trebuie doar să trimită detaliile titlurilor și să poți genera un tonaj în funcție de nevoile afacerii tale pe partea REST API.
  • Implementați un nivel de autorizare pentru punctele finale API. Consumatorii neautorizați pot accesa date restricționate care aparțin altui utilizator. În acest tutorial, nu am acoperit resursa Utilizator, dar vă puteți referi la Autentificarea bazată pe autentificare cu AngularJS & NodeJS pentru mai multe informații despre autentificările API.
  • User URI în loc de șir de interogări. / articole / 123  (Bun), / Articole? Id = 123 (Rău).
  • Nu păstrați statul; utilizați întotdeauna intrare / ieșire instantanee.
  • Folosește substantiv pentru resursele tale. Puteți utiliza metode HTTP pentru a opera cu resurse.

În cele din urmă, dacă proiectați un API RESTful respectând aceste reguli fundamentale, veți avea întotdeauna un sistem flexibil, ușor de întreținut și ușor de înțeles.

Cod