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.
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"
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
Î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
/v1.1/articles/123456789012
. 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.
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.
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:
Î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 |
Î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.
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);
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);
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.
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:
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)
. găsește una
cu un parametru ID este suficient pentru a returna detaliile articolului.Salvați
comanda.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.
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.
/ articole / 123
(Bun), / Articole? Id = 123
(Rău).Î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.