Erstellen einer REST-API mit Node.js und einer Oracle-Datenbank. Teil 5

Teil 5. Erstellen einer REST-API: Paginierung, manuelle Sortierung und Filterung

Im vorherigen Artikel haben Sie die Kernfunktionalität der CRUD-API erstellt.

Wenn jetzt eine HTTP-GET-Anforderung auf der Mitarbeiterroute ausgegeben wird, werden alle Zeilen der Tabelle zurückgegeben. Dies mag bei nur 107 Zeilen in der Tabelle HR.EMPLOYEES nicht viel ausmachen, aber stellen Sie sich vor, was passieren würde, wenn die Tabelle Tausende oder Millionen von Zeilen enthält. Clients wie Mobil- und Webanwendungen zeigen normalerweise nur einen Bruchteil der in der Datenbank verfügbaren Zeilen an und wählen dann bei Bedarf weitere Zeilen aus - möglicherweise, wenn der Benutzer bei einer Unterbrechungssteuerung nach unten scrollt oder auf die Schaltfläche „Weiter“ klickt zu Seiten in der Benutzeroberfläche.

Zu diesem Zweck müssen REST-APIs Paginierungswerkzeuge für zurückgegebene Ergebnisse unterstützen. Sobald die Paginierung unterstützt wird, sind Sortierfunktionen erforderlich, da Daten normalerweise sortiert werden sollten, bevor die Paginierung angewendet wird. Darüber hinaus ist das Datenfilter-Tool für die Leistung sehr wichtig. Warum Daten aus der Datenbank über die Zwischenschicht und vollständig an den Client senden, wenn dies nicht erforderlich ist?

Ich werde die URL-Abfragezeichenfolgenparameter verwenden, damit Clients angeben können, wie die Ergebnisse paginiert, sortiert und gefiltert werden sollen. Wie immer bei der Programmierung kann die Implementierung abhängig von Ihren Anforderungen, Leistungszielen usw. variieren. In diesem Beitrag werde ich Ihnen einen manuellen Ansatz zum Hinzufügen dieser Funktionen zur API erläutern.

Paginierung

Abfragezeichenfolgenparameter, die ich für die Paginierung verwenden werde: Überspringen und Begrenzen. Der Parameter skip wird verwendet, um die angegebene Anzahl von Zeilen zu überspringen, während limit die Anzahl der zurückgegebenen Zeilen begrenzt. Ich werde den Standardwert 30 für das Limit verwenden, wenn der Client den Wert nicht angibt.

Aktualisieren Sie zunächst die Controller-Logik, um Werte aus der Abfragezeichenfolge zu extrahieren und an die Datenbank-API zu übergeben. Öffnen Sie die Datei controller / employee.js und fügen Sie der Funktion get nach der Zeile, in der der Parameter req.params.id analysiert wird, die folgenden Codezeilen hinzu.

// *** line that parses req.params.id is here *** context.skip = parseInt(req.query.skip, 10); context.limit = parseInt(req.query.limit, 10); 

Jetzt müssen Sie die Datenbanklogik aktualisieren, um diese Werte zu berücksichtigen, und die SQL-Abfrage entsprechend aktualisieren. In SQL wird die Offset-Klausel zum Überspringen von Zeilen und die Abrufklausel zum Begrenzen der Anzahl der von der Abfrage zurückgegebenen Zeilen verwendet. Wie üblich werden Werte nicht direkt zur Abfrage hinzugefügt, sondern aus Leistungs- und Sicherheitsgründen als Bindevariablen hinzugefügt. Öffnen Sie db_apis / employee.js und fügen Sie nach dem if-Block in der Suchfunktion den folgenden Code hinzu, der der Anforderung die where-Klausel hinzufügt.

 // *** if block that appends where clause ends here *** if (context.skip) { binds.row_offset = context.skip; query += '\noffset :row_offset rows'; } const limit = (context.limit > 0) ? context.limit : 30; binds.row_limit = limit; query += '\nfetch next :row_limit rows only'; 

Das ist alles was Sie tun müssen, um zu paginieren! Starten Sie die API und führen Sie dann einige URL-Befehle in einem anderen Terminal aus, um sie zu testen. Hier sind einige Beispiele, die Sie verwenden können:

 # use default limit (30) curl "http://localhost:3000/api/employees" # set limit to 5 curl "http://localhost:3000/api/employees?limit=5" # use default limit and set skip to 5 curl "http://localhost:3000/api/employees?skip=5" # set both skip and limit to 5 curl "http://localhost:3000/api/employees?skip=5&limit=5" 

Sortieren

Kunden sollten mindestens in der Lage sein, eine Spalte zum Sortieren und Sortieren anzugeben (aufsteigend oder absteigend). Der einfachste Weg, dies zu tun, besteht darin, einen Abfrageparameter zu definieren (ich verwende sort), mit dem Sie eine Zeichenfolge wie 'Nachname: Aufstieg' oder 'Gehalt: Abstieg' übergeben können. Die einzige Möglichkeit, die Reihenfolge der von der SQL-Abfrage zurückgegebenen Ergebnismenge zu gewährleisten, besteht darin, die order by-Klausel einzuschließen. Aus diesem Grund wäre es schön, eine Standardauftragsdefinition zu definieren, um die Konsistenz sicherzustellen, wenn der Client sie nicht angibt.

Gehen Sie zurück zu controller / employee.js und fügen Sie der get-Funktion nach der Zeile, in der der Parameter req.query.limit analysiert wird, die folgende Codezeile hinzu.

 // *** line that parses req.query.limit is here *** context.sort = req.query.sort; 

Öffnen Sie dann db_apis / employee.js und fügen Sie die folgende Zeile unter den Zeilen hinzu, die baseQuery deklarieren und initialisieren.

 // *** lines that initalize baseQuery end here *** const sortableColumns = ['id', 'last_name', 'email', 'hire_date', 'salary']; 

sortableColumns ist eine Whitelist mit Spalten, mit denen Kunden sortieren können. Fügen Sie dann in der Suchfunktion den folgenden if-Block hinzu, der die order by-Klausel hinzufügt. Dies muss nach dem Hinzufügen der where-Klausel, jedoch vor den Offset- und Fetch-Klauseln erfolgen.

 // *** if block that appends where clause ends here *** if (context.sort === undefined) { query += '\norder by last_name asc'; } else { let [column, order] = context.sort.split(':'); if (!sortableColumns.includes(column)) { throw new Error('Invalid "sort" column'); } if (order === undefined) { order = 'asc'; } if (order !== 'asc' && order !== 'desc') { throw new Error('Invalid "sort" order'); } query += `\norder by "${column}" ${order}`; } 

Der erste Teil des if-Blocks prüft, ob der Client den Sortierwert übergeben hat. Wenn nicht, wird der SQL-Abfrage die Standardreihenfolge nach Klausel hinzugefügt, die in aufsteigender Reihenfolge nach Nachname sortiert wird. Wenn ein Sortierwert angegeben wird, wird dieser zuerst in Spalten- und Auftragswerte aufgeteilt, und jeder Wert wird überprüft, bevor der Abfrage eine Reihenfolge hinzugefügt wird.

Jetzt können Sie mehrere URL-Befehle ausführen, um sie zu überprüfen. Hier einige Beispiele zum Ausprobieren:

 # use default sort (last_name asc) curl "http://localhost:3000/api/employees" # sort by id and use default direction (asc) curl "http://localhost:3000/api/employees?sort=id" # sort by hire_date desc curl "http://localhost:3000/api/employees?sort=hire_date:desc" # use sort with limit and skip together curl "http://localhost:3000/api/employees?limit=5&skip=5&sort=salary:desc" # should throw an error because first_name is not whitelisted curl "http://localhost:3000/api/employees?sort=first_name:desc" # should throw an error because 'other' is not a valid order curl "http://localhost:3000/api/employees?sort=last_name:other" 

Die letzten beiden Beispiele sollten Ausnahmen auslösen, da sie Werte enthalten, die nicht für die Whitelist erstellt wurden. Es verwendet den Standard-Express-Fehlerhandler, sodass der Fehler als HTML-Webseite zurückgegeben wird.

Filtern

Die Fähigkeit, Daten zu filtern, ist eine wichtige Funktion, die alle REST-APIs bereitstellen müssen. Wie beim Sortieren kann die Implementierung einfach oder komplex sein, je nachdem, was Sie unterstützen möchten. Am einfachsten ist es, Unterstützung für Filter mit vollständiger Übereinstimmung hinzuzufügen (z. B. Nachname = Doe). Komplexere Implementierungen können Unterstützung für grundlegende Operatoren (z. B. <,>, Instr usw. usw.) und komplexe logische Operatoren (z. B. und / oder) hinzufügen, die mehrere Filter zusammenfassen können.

In diesem Beitrag werde ich versuchen, die Situation zu vereinfachen und Filterunterstützung für nur zwei Spalten hinzuzufügen: department_id und manager_id. Für jede Spalte werde ich den entsprechenden Parameter in der Abfragezeichenfolge aktivieren. Die Datenbanklogik, die die where-Klausel hinzufügt, wenn GET-Anforderungen mit einem einzelnen Mitarbeiter an den Endpunkt gesendet werden, muss aktualisiert werden, um diese neuen Filter zu berücksichtigen.

Öffnen Sie controller / employee.js und fügen Sie die folgenden Zeilen unter der Zeile hinzu, in der der Wert req.query.sort in der Funktion get analysiert wird.

 // *** line that parses req.query.sort is here *** context.department_id = parseInt(req.query.department_id, 10); context.manager_id = parseInt(req.query.manager_id, 10); 

Bearbeiten Sie dann db_apis / employee.js , um der Basisabfrage den Satz 1 = 1 hinzuzufügen, wie unten gezeigt.

 const baseQuery = `select employee_id "id", first_name "first_name", last_name "last_name", email "email", phone_number "phone_number", hire_date "hire_date", job_id "job_id", salary "salary", commission_pct "commission_pct", manager_id "manager_id", department_id "department_id" from employees where 1 = 1`; 

Natürlich ist 1 = 1 immer wahr, daher ignoriert der Optimierer es einfach. Diese Methode wird jedoch in Zukunft das Hinzufügen zusätzlicher Prädikate vereinfachen.

Ersetzen Sie in der Suchfunktion den if-Block, der beim Übergeben von context.id die where-Klausel hinzufügt, durch die folgenden Zeilen.

 // *** line that declares 'binds' is here *** if (context.id) { binds.employee_id = context.id; query += '\nand employee_id = :employee_id'; } if (context.department_id) { binds.department_id = context.department_id; query += '\nand department_id = :department_id'; } if (context.manager_id) { binds.manager_id = context.manager_id; query += '\nand manager_id = :manager_id'; } 

Wie Sie sehen können, fügt jeder if-Block einfach den an das binds-Objekt übergebenen Wert hinzu und fügt dann das entsprechende Prädikat zur where-Klausel hinzu. Speichern Sie die Änderungen und starten Sie die API neu. Verwenden Sie dann diese URL-Befehle, um dies zu überprüfen:

 # filter where department_id = 90 (returns 3 employees) curl "http://localhost:3000/api/employees?department_id=90" # filter where manager_id = 100 (returns 14 employees) curl "http://localhost:3000/api/employees?manager_id=100" # filter where department_id = 90 and manager_id = 100 (returns 2 employees) curl "http://localhost:3000/api/employees?department_id=90&manager_id=100" 

Das war's - die API unterstützt jetzt Paginierung, Sortierung und Filterung! Ein manueller Ansatz bietet viel Kontrolle, erfordert jedoch viel Code. Die Suchfunktion hat jetzt 58 Zeilen und unterstützt nur eingeschränkte Sortier- und Filterfunktionen. Sie können ein Modul wie den Knex.js- Abfrage- Generator verwenden , um diese Vorgänge zu vereinfachen.

Source: https://habr.com/ru/post/de473652/


All Articles