# API-Denken vor Framework-Denken

URL: https://www.mikebild.dev/de/blog/api-denken-vor-framework-denken/

„Angular oder React?" gilt in diesem Jahr als die Architekturfrage für neue Web-Projekte. Sie ist keine. Sie ist eine Werkzeugfrage – und sie wird regelmäßig gestellt, bevor jemand die Frage beantwortet hat, die tatsächlich Architektur ist: Was sind eigentlich unsere Operationen und unsere Daten? Diese Reihenfolge ist verkehrt herum, und sie ist gerade besonders verführerisch. 2016 ist das Jahr der Framework-Debatten: Angular 2 ist seit September final, Vue 2 erschien Ende September, React steht bei Version 15, und die Vergleichsartikel dazu füllen Konferenzprogramme, Blogs und Team-Meetings.

Der Streit ist unterhaltsam, aber er verdeckt etwas Einfaches: Das Framework rendert nur, was eine API hergibt. Wer die API zuerst entwirft – Ressourcen oder Schema, Namen aus der Fachsprache, Fehlerfälle, Berechtigungen –, kann das Frontend danach fast frei wählen und später sogar wechseln. Wer das Framework zuerst wählt, bekommt mit hoher Wahrscheinlichkeit eine API, die den Datenfluss genau dieses Frameworks nachbildet. Und diese API bleibt, wenn das Framework längst abgelöst ist.

## Was eine API festlegt – und was ein Framework

Ein Frontend-Framework entscheidet, wie Komponenten gerendert werden, wie Zustand im Client verwaltet wird und wie sich das Team organisiert, das die Oberfläche baut. Das ist nicht wenig, aber es ist austauschbar. Migrationsgeschichten von Backbone nach Angular oder von Angular 1 nach React gibt es genug – in diesem Jahr, mit dem harten Schnitt zwischen Angular 1 und Angular 2, mehr denn je. Ein Framework-Wechsel ist teuer, aber er ist ein lokales Ereignis: Er betrifft den Client und sonst niemanden.

Eine API legt etwas anderes fest, und zwar für alle Beteiligten gleichzeitig:

- welche Operationen es gibt und wie sie heißen,
- welche Daten zusammengehören und welche bewusst getrennt bleiben,
- welche Fehlerfälle fachlich erwartbar sind und wie sie aussehen,
- wer welche Operation auslösen darf.

Diese vier Punkte überleben jede Framework-Mode. Sie bilden den Vertrag zwischen Fachseite, Backend und sämtlichen Clients – dem Web-Frontend von heute, der Mobile-App vom nächsten Jahr, dem Partner-System von übermorgen. Ein Vertrag, der sich ändert, zieht Änderungen bei allen Vertragspartnern nach sich. Genau deshalb gehört er an den Anfang, nicht ans Ende.

Der vierte Punkt verdient dabei einen zweiten Blick, weil er beim Framework-zuerst-Vorgehen am zuverlässigsten unter die Räder kommt. Berechtigungen wirken aus Sicht der Oberfläche wie eine Anzeige-Angelegenheit: Der Button wird ausgeblendet, das Menü gekürzt, fertig. Aus Sicht der API sind sie eine Zusicherung – die Aussage, dass eine Operation von einem bestimmten Aufrufer schlicht nicht ausgelöst werden kann, egal welcher Client anklopft. Diese Zusicherung lässt sich nur im Vertrag geben, nicht in der Komponente. Wer sie beim Entwurf ausspart, holt sie später unter Zeitdruck nach, meist nachdem der erste Aufruf aufgetaucht ist, den kein Button je ausgelöst hat.

## Die falsche Reihenfolge im Projektalltag

Wie sich die verkehrte Reihenfolge anfühlt, habe ich in diesem Frühjahr in einem Projekt erlebt: Bestellverwaltung für einen Handelskunden, Web-Oberfläche zuerst, Mobile „irgendwann später". Die ersten drei Wochen gingen in die Framework-Evaluation – Angular 2 war noch Release Candidate, React mit Redux die Alternative, dazu die üblichen Nebenkriegsschauplätze um TypeScript und JSX. Die API stand auf keiner Agenda. „Machen wir, wenn das Frontend steht", hieß es, und das war ehrlich gemeint.

Als das Frontend stand, gab es dann auch eine API. Sie hatte einen Endpunkt `/api/app-state`, der beim Laden den kompletten Redux-Store befüllte. Sie hatte Feldnamen, die aus den Reducern stammten, nicht aus der Fachsprache. Fehler kamen als HTTP 500 mit einem Text, weil der Client ohnehin nur eine rote Meldung anzeigte. Berechtigungen wurden im Frontend geprüft, weil das dort gerade bequemer war. Nichts davon war böser Wille – jede einzelne Entscheidung war aus Sicht des Frontends vernünftig. In Summe war die API ein Abdruck des Redux-Datenflusses.

Ein halbes Jahr später kam das Mobile-Team. Es konnte mit `/api/app-state` nichts anfangen, brauchte kleinere Zuschnitte, andere Fehlerbehandlung, echte Autorisierung auf dem Server. Das Backend bekam eine zweite API neben der ersten, und ab da wurden beide gepflegt. Die Framework-Frage war damals übrigens zugunsten von React entschieden worden – es hätte für das Ergebnis keinen Unterschied gemacht, wenn es Angular geworden wäre. Die teure Entscheidung war nicht das Framework. Es war die Reihenfolge.

## Ressourcen zuerst: ein Beispiel

Wie sieht die andere Reihenfolge aus? Sie beginnt mit einem Gespräch, in dem kein Framework vorkommt. Mit der Fachseite am Tisch werden die Begriffe eingesammelt, die dort ohnehin täglich fallen: Bestellung, Kunde, Kreditlimit, Stornierung. Aus diesen Begriffen entsteht ein erster Ressourcen-Entwurf – hier als REST-Routen notiert:

```http
GET    /customers/{id}
GET    /customers/{id}/orders
POST   /orders
GET    /orders/{id}
POST   /orders/{id}/cancellation
```

Zwei Dinge an diesem Entwurf sind wichtiger, als sie aussehen. Erstens: `POST /orders/{id}/cancellation` statt `DELETE /orders/{id}`. Eine Stornierung ist im Handel keine Löschung, sondern ein fachlicher Vorgang mit eigenen Regeln – sie kann abgelehnt werden, sie kann Gebühren auslösen, sie taucht in der Historie auf. Der Endpunkt trägt den Namen aus der Fachsprache, nicht den aus dem HTTP-Lehrbuch. Zweitens: Der Fehlerfall ist Teil des Vertrags. Wenn eine Bestellung das Kreditlimit überschreitet, ist das kein Serverfehler, sondern eine erwartbare fachliche Antwort:

```json
{
  "order": null,
  "failure": {
    "code": "CREDIT_LIMIT_EXCEEDED",
    "message": "Customer credit limit exceeded",
    "creditLimit": 5000,
    "openAmount": 5240
  }
}
```

Dieses JSON kann man ausdrucken und mit der Fachseite besprechen. „Stimmt der Fehlercode? Fehlt ein Feld? Darf der Außendienst das überhaupt sehen?" – solche Fragen lassen sich an einem Vertragsdokument klären, lange bevor eine Zeile Frontend existiert. An einem Redux-Reducer oder einem Angular-Service lassen sie sich nicht klären, weil die Fachseite ihn nie zu Gesicht bekommt.

## Dasselbe als Schema gedacht

Seit anderthalb Jahren gibt es für diese Vertragsarbeit ein zweites Vokabular: GraphQL, im Sommer 2015 von Facebook als Spezifikation samt Referenzimplementierung veröffentlicht. Mit Relay gab es von Anfang an einen Client, seit Mitte dieses Jahres arbeitet das Meteor-Team mit Apollo an einer zweiten, bewusst framework-neutralen Client-Familie. Was mich an GraphQL für den Entwurfsschritt interessiert, ist weniger der Query-Mechanismus als die Schema-Kurznotation. Sie zwingt dazu, genau die Dinge aufzuschreiben, um die es beim API-Entwurf geht:

```graphql
type Order {
  id: ID!
  customer: Customer!
  items: [OrderItem!]!
  status: OrderStatus!
}

enum OrderStatus {
  PLACED
  APPROVED
  REJECTED
  CANCELLED
}

type OrderFailure {
  code: String!
  message: String!
}

type PlaceOrderResult {
  order: Order
  failure: OrderFailure
}

type Mutation {
  placeOrder(input: PlaceOrderInput!): PlaceOrderResult
  cancelOrder(id: ID!): CancelOrderResult
}
```

`placeOrder` und `cancelOrder` heißen wie die Vorgänge, über die die Fachseite spricht. `PlaceOrderResult` macht sichtbar, dass eine Bestellung fachlich scheitern kann, ohne dass technisch etwas kaputt ist – dieselbe Unterscheidung wie im JSON-Beispiel oben, nur diesmal im Typsystem verankert. Ob am Ende REST-Ressourcen oder ein GraphQL-Schema den Vertrag bilden, ist für die Reihenfolge zweitrangig. Beides sind Notationen für dieselbe Denkarbeit: Operationen, Daten, Fehlerfälle, Berechtigungen – vor dem Framework.

```mermaid
flowchart TD
  subgraph FF["Framework zuerst"]
    F1[Framework-Wahl] --> F2[Datenfluss des<br/>Frameworks] --> F3[API bildet den<br/>Datenfluss nach] --> F4[Jeder neue Client<br/>braucht eine neue API]
  end
  subgraph AF["API zuerst"]
    A1[Fachsprache:<br/>Operationen und Daten] --> A2[API-Vertrag:<br/>Ressourcen oder Schema] --> A3[Frontend frei wählbar:<br/>Angular, React, Vue]
  end
```

## Woran man eine framework-geformte API erkennt

Die verkehrte Reihenfolge hinterlässt Spuren, die sich in Code-Reviews zuverlässig wiederfinden. Ein paar Signale, auf die ich inzwischen achte:

- Endpunkte, die exakt einer Bildschirmseite entsprechen (`/api/dashboard`, `/api/app-state`)
- Feldnamen aus dem Client-Store statt aus der Fachsprache
- Fehler ausschließlich als HTTP 500 mit Freitext, weil der Client ohnehin nur eine Meldung einblendet
- Berechtigungsprüfungen, die nur im Frontend existieren
- Datenformate, die die interne Struktur einer bestimmten Client-Bibliothek voraussetzen

Jedes dieser Signale ist für sich genommen harmlos und im Moment seiner Entstehung sogar effizient. Zusammen bedeuten sie: Diese API hat genau einen legitimen Konsumenten, und der ist zufällig das Framework, das gerade im Projekt steckt. Der zweite Konsument – Mobile-App, Partner-Anbindung, Batch-Import – zahlt dann den vollen Preis.

## Backend-for-Frontend als ehrlicher Kompromiss

Nun wäre es unehrlich, so zu tun, als hätten alle Clients dieselben Bedürfnisse. Ein Web-Frontend will oft breite, verschachtelte Antworten; eine Mobile-App über Mobilfunk will kleine, vorverdichtete Zuschnitte. Wer beiden dasselbe generische Format aufzwingt, macht beide langsam. Für dieses Spannungsfeld hat sich seit dem letzten Jahr ein Muster mit eigenem Namen etabliert: Backend for Frontend, kurz BFF. Sam Newman hat es beschrieben, SoundCloud hat es in der eigenen Architektur vorgemacht – pro Client-Typ eine dünne, dem jeweiligen Frontend gewidmete Schicht, dahinter die eine fachliche API.

```mermaid
flowchart LR
  Web[Web-Client<br/>React oder Angular] --> BW[BFF Web]
  Mob[Mobile-Client<br/>iOS und Android] --> BM[BFF Mobile]
  BW --> API[Fachliche API:<br/>Orders, Customers]
  BM --> API
```

Der Punkt, der das Muster für mich ehrlich macht: Die Kopplung an den Client wird nicht geleugnet, sondern benannt und eingezäunt. Das BFF darf client-spezifisch sein, darf Antworten zuschneiden, darf sogar dem Datenfluss eines Frameworks schmeicheln – es ist die einzige Stelle im System, an der das erlaubt ist. Die fachliche API dahinter bleibt sauber und framework-frei. Verwechselt man beide Ebenen, landet man wieder beim `/api/app-state`-Endpunkt, nur diesmal mit gutem Gewissen.

Wichtig ist außerdem, wem so eine Schicht gehört. Bei SoundCloud pflegt das jeweilige Client-Team sein BFF selbst – das Web-Team seins, das Mobile-Team seins. Das passt zur Logik des Musters: Wer den Zuschnitt braucht, verantwortet ihn auch, und die fachliche API dahinter muss nicht jede Client-Laune mitverhandeln. Übernimmt stattdessen das Backend-Team alle BFFs, wird aus dem Kompromiss schnell wieder ein Flaschenhals, und der Druck wächst, die Zuschnitte doch in die fachliche API zu drücken.

## Vertragsarbeit ist Arbeit mit der Fachseite

Ob Ressourcen oder Schema: Der Entwurf taugt nur so viel wie das Gespräch, aus dem er stammt. Für REST-APIs hat sich Swagger als Beschreibungsformat durchgesetzt – offiziell heißt die Spezifikation seit der Gründung der OpenAPI Initiative Ende letzten Jahres OpenAPI, im Alltag sagt weiterhin jeder Swagger. Der eigentliche Wert liegt nicht im Tooling, sondern darin, dass es ein Dokument gibt, das in einem Review neben den Fachkonzepten liegen kann. Ein GraphQL-Schema leistet dasselbe, in kompakterer Form.

Ich habe dieses Jahr selbst in diese Richtung experimentiert: graphql-pouch, ein kleines Open-Source-Projekt, das aus einer GraphQL-Schema-Notation eine lauffähige API über PouchDB erzeugt, inklusive CouchDB-Synchronisation. Der Ansatz dort ist bewusst „Frontend-First" – ohne Backend-Migrationen schnell zu einem typisierten Datenmodell kommen. Interessanterweise bestätigt gerade dieses Experiment die These: Auch wenn die Laufzeitumgebung dem Frontend entgegenkommt, ist das erste Artefakt die Schema-Notation. Man schreibt Typen und Operationen auf, bevor irgendetwas rendert. Das Schema ist der Vertrag; alles andere ist Erzeugnis.

Die Vertragsarbeit selbst bleibt dabei unbequem, und das ist gut so. Wenn die Fachseite beim Namen `cancelOrder` die Stirn runzelt, weil im Haus niemand von „Stornierung", sondern alle von „Rückabwicklung" sprechen, dann ist das genau die Diskussion, die man im Dezember führen will – nicht im Juni, wenn drei Clients den Namen bereits fest verdrahtet haben.

## Unterm Strich

Die Framework-Frage darf Spaß machen, und die Antworten dieses Jahres – Angular 2, React 15, Vue 2 – sind allesamt vertretbar. Aber sie ist die zweite Frage. Die erste lautet: Welche Operationen gibt es, wie heißen sie in der Fachsprache, welche Fehlerfälle sind erwartbar, wer darf was? Wer diese Frage in einem Vertragsdokument beantwortet – als Ressourcen-Entwurf oder als Schema –, macht die Framework-Wahl beinahe risikofrei und den späteren Wechsel bezahlbar. Wer sie überspringt, wählt das Framework trotzdem – nur dass es dann heimlich die API mitentwirft, und dieser Teil der Entscheidung lässt sich später nicht mehr per npm install korrigieren.

## Weiterführende Quellen

- [graphql-pouch auf GitHub](https://github.com/MikeBild/graphql-pouch)
- [GraphQL – Introduction und Schema-Dokumentation](https://graphql.org/learn/)
- [Sam Newman: Pattern – Backends For Frontends](https://samnewman.io/patterns/architectural/bff/)
- [Phil Calçado: The Back-end for Front-end Pattern (BFF) bei SoundCloud](https://philcalcado.com/2015/09/18/the_back_end_for_front_end_pattern_bff.html)
- [OpenAPI Initiative](https://www.openapis.org/)
