Viele Webanwendungen werden heutzutage als Single-Page-Webanwendung (SPA) mit Angular, React oder Vue.js umgesetzt. Man kann sie als eigenständige Anwendungen betrachten, die innerhalb des Browsers ausgeführt werden. Lediglich die fachlichen Daten müssen noch vom Server abgefragt werden, was zumeist durch REST-Aufrufe erfolgt. Bei einem Entwicklerteam aus Frontend- und Backend-Entwicklern sind die Frontendler von der REST-Schnittstelle der Backendler abhängig, was zu Verzögerungen bei der Umsetzung führen kann.
Minimale REST-Server mit kompatiblen API-Schnittstellen können bei der Frontend-Entwicklung helfen. Der auf Node basierende JSON-Server bietet passende REST-Funktionalitäten mit minimalem Konfigurationsaufwand. Das ist nicht nur für die lokale Entwicklung nützlich sondern auch unerlässlich für automatisierte Akzeptanztests (z.B. mit Selenium, Geb, Protractor).
Schnelleinstieg: Out of the box
Nach der Installation per npm
erstellen wir eine JSON-Datei mit Daten und starten den JSON-Server:
npm install json-server --save-dev echo '{"books": [ {"id":1, "title":"Angular-Buch", "pages": 320 } ] }' > db.json json-server --watch db.json
Anschließend können wir mit curl
die Bücher abfragen oder suchen, ein Buch erstellen, aktualisieren oder löschen. Beim Anlegen von Objekten ist JSON-Server so schlau, eine angegebene ID auszuwerten oder selber zu vergeben:
curl -v localhost:3000/books curl -v localhost:3000/books/1 curl -v localhost:3000/books?title=Angular-Buch curl -v -X POST localhost:3000/books -H 'content-type: application/json' -d '{ "title":"Kubernetes-Buch", "pages": 460 }' curl -v -X PUT localhost:3000/books/2 -H 'content-type: application/json' -d '{"title":"Docker-Buch", "pages": 350 }' curl -v -X DELETE localhost:3000/books/1
Ein Blick in die JSON-Datei zeigt, dass die Daten entsprechend aktualisiert wurden:
cat db.json { "books": [ { "title": "Docker-Buch", "pages": 350, "id": 2 } ]
Eigener API-Server dank JSON-Server
Falls wir etwas mehr Flexibilität benötigen, lohnt sich ein eigener Server auf Basis von JSON-Server, der seinerseits auf Express beruht. Dazu legen wir lediglich eine JavaScript-Datei api-server.js
an und starten sie mit: node api-server.js
const jsonServer = require('json-server'); const server = jsonServer.create(); const router = jsonServer.router('db.json'); const middlewares = jsonServer.defaults(); server.use(middlewares); // rewrite '/api/books' to '/books' server.use(jsonServer.rewriter({ '/api/books*': '/books' })); // return HTTP status specified in title parameter server.get('/books', (req, res, next) => { var specifiedStatus = null; if (req.query.title) { const numberMatchesInTitle = req.query.title.match(/\d+/); if (numberMatchesInTitle) { specifiedStatus = parseInt(numberMatchesInTitle[0], 10); } } if (specifiedStatus) { res.sendStatus(specifiedStatus); } else { next(); } }) // transform POST request to GET request server.use(jsonServer.bodyParser) server.post('/legacy/books', (req, res, next) => { const id = req.body.id; req.url = '/books/' + id; req.method='GET'; next(); }) server.use(router); server.listen(3000, () => { console.log('JSON Server is running') });
node api-server.js # rewrite '/api/books' to '/books' curl -v localhost:3000/api/books # return HTTP status specified in title parameter curl -v localhost:3000/books?title=Docker-412 # transform POST request to GET request curl -v -X POST localhost:3000/legacy/books -H 'content-type: application/x-www-form-urlencoded' -d 'id=2'
In der Datei haben wir ein Rewrite definiert, sodass alle „/api/books
“ -Anfragen an „/books
“ weitergeleitet werden.
Ein großer Vorteil eines eigenen API-Servers für die Entwicklung bietet die Erzeugung von unterschiedlichen HTTP-Status. So kann man auf einfache Weise in der Anfrage einen Status „verstecken“, mit dem der Server antworten soll und den die Webanwendung dann hoffentlich korrekt verarbeitet (z.B. „/books?title=docker414
“ => HTTP-Status 414).
Außerdem wandeln wir POST-Anfragen an „/legacy/books/
“ um, indem wir die ID aus dem Request-Body extrahieren und die Anfrage als GET-Anfrage mit der ID weiterverarbeiten. Das kann beispielsweise sinnvoll sein, wenn GET-Parameter zu groß sind und wir daher POST nutzen müssen. Dabei muss beim POST-Aufruf übrigens der korrekte Content-Type „application/x-www-form-urlencoded
“ angegeben werden.
Was kann JSON-Server noch?
Wenn man den JSON-Server direkt im Browser aufruft (http://localhost:3000), erhält man einen Überblick zu den unterstützten Routen.
Die kleinen Beispiele zeigen, wie unkompliziert ein kleiner REST-Server umsetzbar ist. Einige weitere Anwendungsfälle werden direkt vom JSON-Server unterstützt:
- Sortierung, Filterung, Paginierung und Volltextsuche
- statische Dateien aus
public
-Verzeichnis ausliefern - JSON-Antwort programmatisch berechnen
Insbesondere bei der Umsetzung von automatisierten Akzeptanztests, bei denen die Webanwendung vollautomatisch aufgerufen und geprüft wird, komme ich ohne den JSON-Server nicht mehr aus.