Softwareentwicklung

Data Mocking: Möglichkeiten eines Fake-Backends

Wie ein simuliertes Backend die Frontendentwicklung erleichtert

Data-Mocking – Möglichkeiten eines Fake-Backends

Wir möchten in diesem Post zeigen, welche Vorteile ein simuliertes Backend bietet und die Frage beantworten, welchen Möglichkeiten es zur einfachen Erstellung eines Fake-Backends gibt.

In heutigen Web-Anwendungen arbeiten wir zumeist mit einer losen Kopplung von Frontend und Backend. Das macht es möglich, dass die einzelnen Teile als separate Projekte gehandhabt werden können. So kann das Backend etwa eine RESTful API bereitstellen, die völlig losgelöst von der Frontend-Technologie ist und eine andere, idealerweise semantische, Versionierung als das Frontend hat. Die Trennung bietet ferner die Flexibilität, bei Änderungen im Frontend nur dieses neu auszurollen, oder auch das Backend für ein anderes Frontend mit einem ganz anderen technologischen Stack zu nutzen – zum Beispiel native Anwendungen als Ergänzung zur einer Webanwendung.

Während der Entwicklung arbeiten in der Regel verschiedene Personen jeweils am Frontend und am Backend. Das Backend-Team muss sicherstellen, dass der Inhalt, der über die API bereitgestellt wird, korrekt ist. Währenddessen spielt die Validität des Inhalts für die Implementierung des Frontends eine untergeordnete Rolle. Das Frontend-Team kümmert sich vorrangig darum, dass Daten im korrekten Format und in der richtigen Struktur zur Verfügung stehen, um diese ggf. aufbereitet in den Views einer Applikation darzustellen.

Bei der Arbeit mit gemockten Daten sollten sich die Teams zu Beginn der Realisierung eines Features über das Datenformat (JSON) einigen. Dann kann im Frontend mit den Dummy-Daten sofort produktiv gearbeitet werden, während das Backend in Ruhe daran arbeiteten kann, die echten Daten bereitzustellen.

Für das Frontend-Team ist die Unabhängigkeit vom real existierenden Backend ein echter Vorteil. So kann es beispielsweise auch dann produktiv bleiben, wenn sich die Entwicklung des Backends aus irgendeinem Grund verzögert. Das führt uns zu der Frage:

Wie können wir das Backend auf einfache Art und Weise faken?

Unterschiedliche Wege um ein Backend zu faken

Es gibt, je nach Bedarf, verwendeten Technologien und Anforderungen eines Projekts verschiedene Möglichkeiten, Dummy-Daten für das Frontend bereitzustellen:

  1. Statische JSON-Dateien via Ajax
  2. Online Mocking Services
  3. JSON-Server
  4. Ein eigener Server

Im Folgenden werden wir die Details der Möglichkeiten sowie deren Vor- und Nachteile erkunden.

 

1. JSON-Dateien über Ajax bereitstellen

Dies ist der einfachste Ansatz und ohne jegliches Tooling zu bewerkstelligen. Erstellen Sie einfach Ihre Dummy-Daten und speichern Sie diese im Dateisystem Ihres Frontend-Projektes.

Pro:

  • Unkompliziertheit
  • Dummy-Daten in der Versionskontrolle (z. B. Git)

Die Ablage der Dateien im Dateisystem hat den großen Vorteil, dass die Dummy-Daten nur aus einer einzige Quelle stammen. Dies ist vor allem bei der Arbeit im Team wichtig, insbesondere für die Koordination zwischen Frontend- und Backend-Team.

Contra:

  • Sehr begrenzte Funktionalität
  • Ggf. keine Unterstützung durch das genutzte JavaScript-Framework™
  • Keine Verwendung von HTTP-Methoden neben GET möglich
  • Nur eingeschränkter Test von Fehlerbehandlungen möglich (außer 404-Error)
  • Unterschiede zwischen dem gefakten und dem echten Backend

Diese Art des Fakings mag für eine Webapplikation oder Webseite, die nur wenig Daten über Ajax laden muss, ein gangbarer Weg sein. Andernfalls überwiegen vermutlich die Nachteile. Der größte Nachteil ist vor allem der Unterschied zwischen dem vorgetäuschten Backend und dem realen Backend in der Produktion. Dies umfasst sowohl verschiedene URLs (einschließlich einer ganz anderen Struktur) als auch andere HTTP-Header, die so nur mangelhaft simuliert und getestet werden können.

2. Online Mocking Services

Neben der ersten Möglichkeit gibt es für das Mocking von APIs spezialisierte Online-Dienste wie mockapi.io, mocky.io und jsonstub.com. Diese bieten eine gute und einfache Alternative, die HTTP-Responses des Backends zu simulieren.

Pro:

  • Einfach zu verwenden
  • Gute und je nach Anbieter leistungsstarke Konfigurationsmöglichkeiten
  • Die Handhabung ist fast so einfach, wie statische JSON-Dateien zu speichern. Dazu bietet diese Option weitere Möglichkeiten, Dinge wie HTTP-Statuscodes und HTTP-Methoden zu konfigurieren.

Contra:

  • CORS-Einschränkungen (falls zutreffend)
  • Ihre Daten liegen auf öffentlichen Servern
  • Abhängigkeit vom Anbieter
  • Die Daten liegen nicht in Ihrer Versionskontrolle

Der Abhängigkeitsfaktor ist vermutlich das größte Gegenargument. Es gibt ein ganzes Spektrum von Unsicherheiten, vor allem was die Verfügbarkeit des Services angeht. Sie sollten sich zumindest die folgenden Fragen stellen: Kann ich weiter arbeiten, wenn der Service ausfällt? Was passiert, wenn der Anbieter seinen Dienst einstellt? Werde ich meine Daten exportieren können?

Dass die Dummy-Daten nicht unter Ihrer Versionskontrolle liegen, ist ebenfalls ein großer Nachteil, vor allem wenn Sie nicht allein arbeiten. Natürlich können Sie die Dummy-Daten redundant in Ihrem Dateisystem speichern. Dies kann jedoch zu einem erhöhten Maintenance-Aufwand führen und Verwirrung stiften, weil niemand sicher ist, ob die Dateien in der Versionskontrolle aktuell sind bzw. genau denen entsprechen, die durch die Online-Service bereitgestellt werden.

3. JSON-Server

JSON-Server ist ein cleveres Kommandozeilen-Tool und sehr einfach zu bedienen. Selbst für Leute, die nicht den ganzen Tag im Terminal verbringen. Zitat vom Anbieter:

Get a full fake REST API with zero coding in less than 30 seconds (seriously)

Es wird ermöglicht, dass JSON-Dateien aus dem Dateisystem über einen lokalen Server bereitgestellt werden.

Pro:

  • Die Dummy-Daten sind in Ihrer Versionskontrolle
  • Einfach zu konfigurieren
  • Es unterstützt die gängigsten HTTP-Methoden
  • Es speichert Änderungen in Ihren JSON-Quelle für POST, PUT, PATCH oder DELETE-Requests.

Das hört sich zunächst nach einer perfekten Lösung an. Sie können Ihre Dummy-Daten als JSON-Dateien in Ihrem Projekt speichern und diese über ein externes Tool via HTTP zur Verfügung stellen. Es gibt jedoch auch ein paar Nachteile, von denen das eine oder andere je nach Projektanforderung ein Showstopper sein könnte.

Contra:

  • Der Payload für HTTP-Requests muss zwingend im JSON-Format übermittelt werden
  • Keine Routen mit selbst definierten dynamischen Teilen möglich
    • api/articles/{offset}/{count}
  • Wartbarkeit nur einer einzigen JSON-Datei für alle Endpunkte bei größeren Projekten

Es ist einfach zu bedienen, aber das bedeutet leider auch, dass einige der Konventionen Ihnen in die Quere kommen können.

Die Payload-Einschränkung sollte kein Problem sein, vorausgesetzt, Sie verfügen auch über die volle Kontrolle im echten Backend. Problematisch wird es allerdings, wenn z. B. Ihr reales Backend nur eine Integer-Zahl akzeptiert, um etwa einen Datensatz zu löschen.

Der JSON-Server bietet URL-Parameter für Paginierung. Aber diese sind an ein festes URL-Konzept gebunden, welches Sie besser akzeptieren sollten. Andernfalls werden Sie dazu gezwungen sein, in einer Datei Namens routes.json

4. Ein eigener Server

Einen eigenen Server schreiben, nur um im Frontend gemockte Daten zur Verfügung zu haben? Klingt zunächst mal nach einem perfekten Beispiel für Over-Engineering. Die Frage ist: Wollen Sie – als Frontend-Entwickler – ein »zweites« Backend pflegen? Der Hauptgrund, warum Sie Ihre Daten mocken möchten, ist es ja schließlich, vom Backend unabhängig zu sein.

Die Antwort ist ja. Zumindest unter der Voraussetzung, einen vernünftigen Kompromiss zwischen Flexibilität und Komplexität erzielen zu können.

Das HTTP-Fake-Backend bietet diesen Kompromiss. Es kommt als Node.js-Server, der Dummy-Daten über HTTP bereitstellt, und ist fast so einfach einzurichten wie der oben beschriebene JSON-Server. Es versetzt Sie in die Lage, schnell und einfach eine API bauen – schlichtweg durch die Bereitstellung von JSON-Dateien oder JavaScript-Objekten über einfach zu konfigurierende Routen.

Jeder Endpunkt benötigt eine Konfigurationsdatei in den Routen, damit HTTP-Methoden und Response definiert werden können.

 

Einfaches Beispiel

Sagen wir mal, Sie benötigen einen Endpunkt wie http://localhost:8081/api/simpleExample, der folgendes JSON zurückgeben soll:

"status": "ok"

Alles was Sie machen müssen, ist die folgende Konfiguration in einer JavaScript-Datei bereitzustellen:

module.exports = SetupEndpoint({
	    name: 'simpleExample',
	    urls: [{
	        requests: [{
	          response: {status: 'ok'}
	        }]
	    }]
});

 

Weiterführendes Beispiel

Das Fake-Backend kann wesentlich mehr als ein durch JavaScript-Objekte definiertes JSON via HTTP GET zurückzugeben. Lassen Sie uns eine komplexere Beispielskonfiguration betrachten, die wie folgt aussieht

module.exports = SetupEndpoint({
    name: 'anotherExample',
    urls: [{
        params: '/read',
        requests: [{
            method: 'GET',
            response: '/json-templates/anotherExample.json'
        }]
    }, {
        params: '/update/{id}',
        requests: [{
            method: ['PUT', 'PATCH'],
            response: {
                success: true
            }
        }, {
            method: 'DELETE',
            response: {
                deleted: true
            }
        }]
    }]
});

Sie können also für einen Endpunkt mehrere URLs mit unterschiedlichen HTTP-Methoden festlegen und neben JavaScript-Objekten auch die Inhalte von JSON-Dateien aus dem File-System als Response definieren.

Auch HTTP-Fehler und Statuscodes lassen sich sowohl für einen gesamten Endpunkt als auch auf Request-Level wie folgt simulieren:

module.exports = SetupEndpoint({
    name: 'statusCodes',
    urls: [
        {
            params: '/boomError',
            requests: [{
                // Returns a 402 status code + error message provided by boom:
                // {
                // "error" : "Payment Required",
                // "statusCode" : 402
                // }
                statusCode: 402
            }]
        },
        {
            params: '/customError',
            requests: [{
                // Returns a HTTP status code 406 and a self defined response:
                response: { error: true },
                statusCode: 406
            }]
        },
        {
            params: '/regularResponse',
            requests: [{
                // Returns a 401 error provided by boom
                // as defined on endpoint level
                response: '/json-templates/anotherExample.json'
            }]
        }
    ],
    statusCode: 401
});

Nachfolgend finden Sie eine genaue Beschreibung des Konfigurationsobjektes:

  • name (String)
      • Wird genutzt, um den Endpunkt zu setzen
  • urls (Array)
      • Sie müssen mindestens ein URL-Objekt hinzufügen
  • urls.params (String)
      • Optional
      • URL Path Parameters mit festen oder variablen Pfad-Bestandteilen
      • Siehe hapi-Dokumentation. Zum Beispiel bezüglich optionalen Path Parameters
  • urls.requests (Array)
      • Sie müssen mindestens ein Request-Objekt hinzufügen
      • Mehrere Request-Objekte sind nur nötig, wenn Sie bei verschiedenen HTTP-Methoden unter einer identischen URL verschiedenen Responses zurück liefern möchten
  • urls.requests.method (String|Array)
      • Optional. Benutzt GET, sofern nicht definiert
      • Wird benutzt, um die HTTP-Methode(n) zu definieren, auf die der Endpoint reagieren soll
  • urls.requests.response (String|Array)
      • Kann ein String sein, der auf ein JSON-Template zeigt:
        response: '/json-templates/articles.json'
      • Oder einfach ein JavaScript Object:
        response: { success: true }
  • urls.requests.statusCode (Number)
      • Optional
      • Statuscode
      • Sorgt für folgende Response:
        • Einen Statuscode mit einer selbst definierten Antwort, wenn Sie zusätzlich eine Response-Property definiert haben
        • Einen Statuscode mit einem vordefinierten Error-Objekt, bereitgestellt durch boom, wenn Sie für diesen Request keine Response-Property definiert haben.
  • statusCode (Number)
      • Optional
      • Jede Route dieses Endpoints wird einen HTTP-Error mit dem hier definierten Status-Code zurückgeben (via boom).

Falls Sie diese Konfigurationsarbeit abschreckt, können Sie sich Ihre Konfiguration einfach und interaktiv mit Hilfe dieses Yeoman Generator erstellen lassen. Er führt Sie mit wenigen Fragen durch die Konfiguration:

 

Es geht noch flexibler

Das ergibt natürlich nur Sinn, wenn Sie es wirklich benötigen: Sie können auch an den vorgelieferten Konfigurationsmöglichkeiten vorbei eigene Endpunkte mit benutzerdefinierten Konfigurationen bauen. Denn der zugrundeliegende Server ist ein gewöhnlicher Node.js-HTTP-Server auf Basis von hapi. Damit lässt sich zum Beispiel leicht ein Endpunkt realisieren, der HTML statt JSON liefert.

Pro:

  • Die Dummy-Daten sind in Ihrer Versionskontrolle
  • Höchste Flexibilität
  • Einfache Einrichtung
    • Endpoints
    • URLs einschließlich dynamischer Teile
    • Erlaubte HTTP-Methoden
    • Errors (mit Unterstützung für alle HTTP-Statuscodes)
  • Yeoman Generator
    • Mit Subgenerator, um Sie beim Aufbau der API zu unterstützen

Der Server startet sich selbständig und blitzschnell neu, wenn JSON oder Konfigurationsdateien geändert werden. Genau wie der JSON-Server.

Contra:

  • Etwas komplexeres Setup im Vergleich zum JSON-Server
  • Weniger intelligent als der JSON-Server
    • Kein Speichern von Payload-Daten in den Datenquellen für POST, PUT und PATCH-Anfragen
    • Keine automatische und reale Beziehung zwischen Daten von verschiedenen Endpunkten
      • Beispiel: Sie müssen eigene und unabhängige Daten für eine Route definieren, die eine Liste /api/products und eine Route, die ein einzelnes Element /api/products/{id} enthält, zurück gibt.

 

Workflow-Integration

Der Server lässt sich während der Entwicklung mit npm run start:dev starten. Bei Änderungen an Endpunkten startet er automatisch neu. Dagegen ist ein Starten des Servers via npm start etwa in einer Continous-Integration-Umgebung sinnvoll.

Somit sollte sich der Server in Ihren vorhandenen Workflow gut integrieren lassen. Unabhängig davon, ob Sie npm-run-Skripte oder einen Taskrunner benutzen, um Ihr Frontend zu bauen.

Los geht’s

Besuchen Sie einfach die Projektseite auf Github und Ihr Fake-Backend läuft in wenigen Minuten. Komfortabler geht es, wenn Sie den Yeoman-Generator verwenden.


Fazit

Wir Entwickler sind nicht faul, wenn wir versuchen, stupide und sich wiederholende Arbeit zu vermeiden. Vielmehr sind wir auf Effizienz und die Sinnhaftigkeit unseres Tuns aus. Deshalb können wir bei der Erzeugung der Dummy-Daten für unser Fake-Backend Hilfe gebrauchen. Dabei können die folgenden Tools nützlich sein:

JSON-Generatoren

Die folgenden Tools helfen Ihnen, JSON für das Fake-Backend zu generieren:

 

Dummydaten-Generatoren

Ich empfehle, eines der folgenden ausgezeichneten Node-Module zu verwenden, wenn Sie es vorziehen, Ihre Fake-Daten programmatisch zu erstellen:

Michael Kühnel

Michael Kühnel

Frontend-Entwickler. Folge Michael bei twitter.