Die RESTful-API besteht aus zwei Hauptkonzepten: Ressource, und Darstellung. Ressource kann ein beliebiges Objekt sein, das mit Daten verknüpft ist oder mit einem URI identifiziert wird (mehrere URIs können sich auf dieselbe Ressource beziehen) und kann mit HTTP-Methoden betrieben werden. Darstellung ist die Art, wie Sie die Ressource anzeigen. In diesem Tutorial werden einige theoretische Informationen zum RESTful-API-Design behandelt und ein Beispiel für eine Blogging-Anwendungs-API mithilfe von NodeJS implementiert.
Die Auswahl der richtigen Ressourcen für eine RESTful-API ist ein wichtiger Abschnitt beim Entwerfen. Zunächst müssen Sie Ihre Geschäftsdomäne analysieren und dann entscheiden, wie viele und welche Ressourcen verwendet werden, die für Ihre geschäftlichen Anforderungen relevant sind. Wenn Sie eine Blogging-API entwerfen, werden Sie sie wahrscheinlich verwenden Artikel, Nutzer, und Kommentar. Dies sind die Ressourcennamen und die damit verbundenen Daten sind die Ressourcen selbst:
"title": "How to RESTful API entwerfen", "content": "RESTful API-Design ist ein sehr wichtiger Fall in der Welt der Softwareentwicklung.", "author": "huseyinbabal", "tags": ["technology" , "nodejs", "node-restify"] "category": "NodeJS"
Sie können mit einer Ressourcenoperation fortfahren, nachdem Sie sich für die erforderlichen Ressourcen entschieden haben. Der Vorgang bezieht sich hier auf HTTP-Methoden. Um beispielsweise einen Artikel zu erstellen, können Sie die folgende Anfrage stellen:
POST / Artikel HTTP / 1.1 Host: localhost: 3000 Inhaltstyp: application / json "title": "RESTful API-Design mit restify", "slug": "restful-api-design-with-restify", "content" : "Pellentesque habitant morbi tristique senectus et netus et malesuada macht Turpis egestas bekannt.", "Author": "huseyinbabal"
Auf dieselbe Weise können Sie einen vorhandenen Artikel anzeigen, indem Sie die folgende Anforderung ausgeben:
GET / articles / 123456789012 HTTP / 1.1 Host: localhost: 3000 Inhaltstyp: application / json
Was ist mit dem Aktualisieren eines vorhandenen Artikels? Ich kann hören, dass Sie sagen:
Ich kann eine weitere POST-Anforderung an / articles / update / 123456789012 mit der Nutzlast stellen.
Vielleicht vorzuziehen, aber der URI wird komplexer. Wie bereits erwähnt, können Operationen auf HTTP-Methoden verweisen. Dies bedeutet, das angeben aktualisieren Operation in der HTTP-Methode, anstatt diese in den URI zu setzen. Zum Beispiel:
PUT / articles / 123456789012 HTTP / 1.1 Host: localhost: 3000 Inhaltstyp: application / json "title": "Aktualisiertes Design für die RESTful-API", "content": "Das aktualisierte RESTful-API-Design ist ein sehr wichtiger Fall in der Software-Entwicklungswelt. "," Autor ":" huseyinbabal "," tags ": [" Technologie "," nodejs "," restify "," ein weiteres Tag "]" category ":" NodeJS "
In diesem Beispiel werden übrigens Tags und Kategorienfelder angezeigt. Das müssen keine Pflichtfelder sein. Sie können sie leer lassen und in Zukunft einstellen.
Manchmal müssen Sie einen Artikel löschen, wenn er veraltet ist. In diesem Fall können Sie eine LÖSCHEN HTTP-Anfrage an / artikel / 123456789012.
HTTP-Methoden sind Standardkonzepte. Wenn Sie sie als Vorgang verwenden, verfügen Sie über einfache URIs, und diese einfache API hilft Ihnen, glückliche Konsumenten zu gewinnen.
Was ist, wenn Sie einen Kommentar zu einem Artikel einfügen möchten? Sie können den Artikel auswählen und dem ausgewählten Artikel einen neuen Kommentar hinzufügen. Mit dieser Anweisung können Sie die folgende Anfrage verwenden:
POST / articles / 123456789012 / comments HTTP / 1.1 Host: localhost: 3000 Inhaltstyp: application / json "text": "Wow! Dies ist ein gutes Tutorial", "Autor": "john doe"
Die obige Form der Ressource wird als a bezeichnet Subressource. Kommentar ist eine unterressource von Artikel. Das Kommentar Die obige Nutzlast wird als untergeordnetes Element von in die Datenbank eingefügt Artikel. Manchmal bezieht sich ein anderer URI auf dieselbe Ressource. Um beispielsweise einen bestimmten Kommentar anzuzeigen, können Sie entweder Folgendes verwenden:
GET / articles / 123456789012 / comments / 123 HTTP / 1.1 Host: localhost: 3000 Inhaltstyp: Anwendung / json
oder:
GET / comments / 123456789012 HTTP / 1.1 Host: localhost: 3000 Inhaltstyp: Anwendung / json
Im Allgemeinen werden API-Funktionen häufig geändert, um Verbrauchern neue Funktionen zur Verfügung zu stellen. In diesem Fall können zwei Versionen derselben API gleichzeitig vorhanden sein. Um diese beiden Funktionen voneinander zu trennen, können Sie die Versionierung verwenden. Es gibt zwei Formen der Versionierung
/v1.1/artikel/123456789012
. GET / articles / 123456789012 HTTP / 1.1 Host: localhost: 3000 Accept-Version: 1.0
Tatsächlich ändert die Version nur die Darstellung der Ressource, nicht das Konzept der Ressource. Sie müssen die URI-Struktur also nicht ändern. In Version 1.1 wurde dem Artikel möglicherweise ein neues Feld hinzugefügt. Es wird jedoch immer noch ein Artikel zurückgegeben. Bei der zweiten Option ist der URI immer noch einfach, und die Benutzer müssen ihren URI in clientseitigen Implementierungen nicht ändern.
Es ist wichtig, eine Strategie für Situationen zu entwickeln, in denen der Verbraucher keine Versionsnummer angibt. Sie können einen Fehler auslösen, wenn keine Version bereitgestellt wird, oder Sie können eine Antwort zurückgeben, indem Sie die erste Version verwenden. Wenn Sie die neueste stabile Version als Standard verwenden, können Konsumenten viele Fehler für ihre clientseitigen Implementierungen erhalten.
Darstellung ist die Art und Weise, wie eine API die Ressource anzeigt. Wenn Sie einen API-Endpunkt aufrufen, wird eine Ressource zurückgegeben. Diese Ressource kann in einem beliebigen Format wie XML, JSON usw. vorliegen. JSON ist vorzuziehen, wenn Sie eine neue API entwerfen. Wenn Sie jedoch eine vorhandene API aktualisieren, mit der eine XML-Antwort zurückgegeben wurde, können Sie eine andere Version für eine JSON-Antwort angeben.
Das sind genug theoretische Informationen über das API-Design von RESTful. Werfen wir einen Blick auf die reale Nutzung, indem wir eine Blogging-API mit Restify entwerfen und implementieren.
Um eine RESTful-API zu entwerfen, müssen wir die Geschäftsdomäne analysieren. Dann können wir unsere Ressourcen definieren. In einer Blogging-API benötigen wir:
In dieser API werde ich nicht beschreiben, wie ein Benutzer authentifiziert wird, um einen Artikel oder Kommentar zu erstellen. Für den Authentifizierungsteil können Sie sich auf das Tutorial Token-Based Authentication with AngularJS & NodeJS beziehen.
Unsere Ressourcennamen sind fertig. Ressourcenoperationen sind einfach CRUD. In der folgenden Tabelle finden Sie einen allgemeinen Überblick über die API.
Ressourcenname | HTTP-Verben | HTTP-Methoden |
---|---|---|
Artikel | Artikel erstellen Artikel aktualisieren Artikel löschen Artikel ansehen | POST / Artikel mit Payload PUT / Artikel / 123 mit Nutzlast LÖSCHEN / Artikel / 123 GET / Artikel / 123 |
Kommentar | Kommentar erstellen coment aktualisieren Kommentar löschen Kommentar anzeigen | POST / Artikel / 123 / Kommentare mit Payload PUT / Kommentare / 123 mit Payload LÖSCHEN / Kommentare / 123 ERHALTEN / kommentieren / 123 |
Nutzer | Benutzer erstellen Benutzer aktualisieren Benutzer löschen Benutzer anzeigen | POST / Benutzer mit Payload PUT / Benutzer / 123 mit Payload LÖSCHEN / Benutzer / 123 GET / Benutzer / 123 |
In diesem Projekt werden wir verwenden NodeJS mit Wieder herstellen. Die Ressourcen werden im gespeichert MongoDB Datenbank. Zunächst können wir Ressourcen in Restify als Modelle definieren.
var Mungo = Anfordern ("Mungo"); var Schema = mongoose.Schema; var ArticleSchema = neues Schema (title: String, Slug: String, Inhalt: String, Autor: Typ: String, ref: "User"); mongoose.model ('Article', ArticleSchema);
var Mungo = Anfordern ("Mungo"); var Schema = mongoose.Schema; var CommentSchema = neues Schema (Text: String, Artikel: Typ: String, Ref: "Artikel", Autor: Typ: String, Ref: "Benutzer"); mongoose.model ('Comment', CommentSchema);
Es gibt keine Operation für die Benutzerressource. Wir gehen davon aus, dass wir bereits den aktuellen Benutzer kennen, der Artikel oder Kommentare bearbeiten kann.
Sie können fragen, woher dieses Mungo-Modul kommt. Es ist das beliebteste ORM-Framework für MongoDB, das als NodeJS-Modul geschrieben wurde. Dieses Modul ist im Projekt in einer anderen Konfigurationsdatei enthalten.
Jetzt können wir unsere HTTP-Verben für die oben genannten Ressourcen definieren. Sie können Folgendes sehen:
var restify = required ('restify'), fs = required ('fs') var controller = , controller_path = process.cwd () + '/ app / controller' fs.readdirSync (controller_path) .forEach (function ) if (file.indexOf ('. js')! = -1) controller [file.split ('.') [0]] = required (controller_path + '/' + file) var Server = restify.createServer (); server .use (restify.fullResponse ()) .use (restify.bodyParser ()) // Article Start server.post ("/ articles", controller.article.createArticle) server.put ("/ articles /: id", controller.article.updateArticle) server.del ("/ articles /: id", controller.article.deleteArticle) server.get (Pfad: "/ articles /: id", Version: "1.0.0", Controller. article.viewArticle) server.get (Pfad: "/ articles /: id", Version: "2.0.0", controller.article.viewArticle_v2) // Artikelende // Kommentar Start server.post ("/ comments") , controller.comment.createComment) server.put ("/ comments /: id", controller.comment.viewComment) server.del ("/ comments /: id", controller.comment.deleteComment) server.get ("/ comments) /: id ", controller.comment.viewComment) // Kommentar Ende var port = process.env.PORT || 3000; server.listen (port, function (err) if (err) console.error (err) else console.log ('App ist fertig unter:' + port)) if (process.env.environment == 'production' ) process.on ('uncaughtException', Funktion (err) console.error (JSON.parse (JSON.stringify (err, ['stack', 'message', 'inner']), 2))))
In diesem Code-Snippet werden zunächst die Controller-Dateien mit Controller-Methoden iteriert und alle Controller initialisiert, um eine bestimmte Anforderung an den URI auszuführen. Danach werden URIs für bestimmte Operationen für grundlegende CRUD-Operationen definiert. Es gibt auch eine Versionierung für eine der Vorgänge bei Article.
Zum Beispiel, wenn Sie Version als angeben 2
im Accept-Version-Header, viewArticle_v2
wird durchgeführt. viewArticle
und viewArticle_v2
Beide führen dieselbe Aufgabe aus und zeigen die Ressource an, aber sie zeigen die Artikelressource in einem anderen Format an, wie Sie im sehen können Titel
Feld unten. Schließlich wird der Server an einem bestimmten Port gestartet und einige Fehlerberichtsüberprüfungen werden angewendet. Wir können mit Controller-Methoden für HTTP-Vorgänge auf Ressourcen fortfahren.
var mongoose = required ('mongoose'), Article = mongoose.model ("Article"), ObjectId = mongoose.Types.ObjectId exports.createArticle = Funktion (req, res, next) var articleModel = neuer Artikel (req.body) ); articleModel.save (Funktion (err, article) if (err) res.status (500); res.json (Typ: false, Daten: "Fehler aufgetreten:" + err) else res.json ( Typ: true, data: article)) exports.viewArticle = function (req, res, next) Article.findById (neue ObjectId (req.params.id), function (err, article) if ( err) res.status (500); res.json (type: false, data: "Fehler ist aufgetreten:" + err) else if (article) res.json (type: true, data: article.) ) else res.json (Typ: false, Daten: "Artikel:" + req.params.id + "nicht gefunden") exports.viewArticle_v2 = function (req, res, next) Article.findById (neue ObjectId (req.params.id), Funktion (err, article) if (err) res.status (500); res.json (type: false, Daten: "Fehler aufgetreten:" + err) else if (article) article.title = article.title + "v2" res.json (type: true, data: article) else res.json (type: false, data.) : "Artikel:" + req.params.id + "nicht gefunden")) exports.updateArticle = function (req, res, next) var updatedArticleModel = neuer Artikel (erforderlicher Körper); Article.findByIdAndUpdate (neue ObjectId (req.params.id), aktualisierteArticleModel, Funktion (err, article) if (err) res.status (500); res.json (type: false, data: "Fehler: "+ err) else if (article) res.json (type: wahr, Daten: article) else res.json (type: false, data:" Artikel: "+ req.params). id + "nicht gefunden")) exports.deleteArticle = function (req, res, next) Article.findByIdAndRemove (neues Objekt (req.params.id), function (err, article) if (err ) res.status (500); res.json (Typ: false, Daten: "Fehler aufgetreten:" + err) else res.json (Typ: true, Daten: "Artikel:" + req.) params.id + "erfolgreich gelöscht"))
Nachfolgend finden Sie eine Erläuterung der grundlegenden CRUD-Operationen auf der Mongoose-Seite:
articleModel
vom Anforderungshauptteil gesendet. Ein neues Modell kann erstellt werden, indem der Anforderungshauptteil als Konstruktor an ein Modell wie übergeben wird var articleModel = neuer Artikel (Anz. Körper)
. einen finden
mit einem ID-Parameter reicht aus, um Artikeldetails zurückzugeben.sparen
Befehl.findByIdAndRemove
ist der beste Weg, um einen Artikel zu löschen, indem Sie die Artikel-ID angeben.Die oben erwähnten Mongoose-Befehle sind einfach statisch wie die Methode "Article", die auch eine Referenz des Mongoose-Schemas ist.
var mongoose = erfordern ('mongoose'), Kommentar = mongoose.model ("Kommentar"), Article = mongoose.model ("Article"), ObjectId = mongoose.Types.ObjectId exports.viewComment = function (req, res) Article.findOne ("comments._id"): neue ObjectId (req.params.id), "comments. $": 1, Funktion (err, comment) if (err) res.status (500) ; res.json (type: false, data: "Fehler aufgetreten:" + err) else if (comment) res.json (type: true, data: neuer Kommentar (comment.comments [0]) ) else res.json (Typ: false, Daten: "Kommentar:" + req.params.id + "nicht gefunden") exports.updateComment = function (req, res, next) var updatedCommentModel = neuer Kommentar (req.body); console.log (updatedCommentModel) Article.update ("comments._id": neue ObjectId (req.params.id), "$ set": "comments. $. text": updatedCommentModel.text, "Kommentare. $ .author ": updatedCommentModel.author, function (err) if (err) res.status (500); res.json (type: false, data:" Fehler aufgetreten: "+ err) else res.json (Typ: wahr, Daten: "Kommentar:" + req.params.id + "aktualisiert")) exports.deleteComment = function (req, res, next) Article.findOneAndUpdate ( "comments._id": neue ObjectId (req.params.id), "$ pull": "comments": "_id": neue ObjectId (req.params.id), Funktion (err, article) if (err) res.status (500); res.json (Typ: falsch, Daten: "Fehler aufgetreten:" + err) else if (article) res.json (Typ: true, data: article) else res.json (type: false, data: "Kommentar:" + req.params.id + "nicht gefunden")
Wenn Sie eine Anforderung an einen der Ressourcen-URIs stellen, wird die im Controller angegebene zugehörige Funktion ausgeführt. Jede Funktion in den Controller-Dateien kann das verwenden req und res Objekte. Das Kommentar Ressource hier ist eine Subressource von Artikel. Alle Abfragevorgänge werden über das Artikelmodell ausgeführt, um ein Unterdokument zu finden und die erforderlichen Aktualisierungen vorzunehmen. Wenn Sie jedoch versuchen, eine Comment-Ressource anzuzeigen, wird eine angezeigt, selbst wenn in MongoDB keine Sammlung vorhanden ist.
/ artikel / 123
(Gut), / articles? id = 123
(Schlecht).Wenn Sie eine RESTful-API mit diesen grundlegenden Regeln entwerfen, haben Sie immer ein flexibles, wartbares und leicht verständliches System.