TS
Thomas Schmitz

Freiberuflicher IT-Berater, Softwareentwickler & DevOps. Praxisnahe Artikel zu API-Design, Architektur und Cloud-Workflows.

Serie: API-Design · Teil 18 von 22

API-Design Teil 18: Dokumentation & DX

OpenAPI, Beispiele, SDKs und wie du deine API für Entwickler zugänglich machst.

Praxisnah Checkliste

Die beste API nützt nichts, wenn niemand versteht, wie man sie benutzt. Gute Dokumentation ist der Unterschied zwischen: Ich habe das in 5 Minuten integriert – und – Ich habe 2 Tage damit verschwendet.

Developer Experience (DX) geht über Dokumentation hinaus: Beispiele, die funktionieren. Fehlermeldungen, die helfen. SDKs, die Arbeit abnehmen. Dieser Artikel zeigt, wie du deine API für Entwickler zugänglich machst.

Zielbild

Nach diesem Artikel kannst du:

  • OpenAPI-Spezifikationen schreiben und validieren
  • Beispiele erstellen, die wirklich funktionieren
  • Authentication-Guides für verschiedene Flows schreiben
  • Entscheiden, ob SDKs sinnvoll sind
  • API Explorer und Sandboxes einsetzen
  • Onboarding für neue Entwickler optimieren

Kernfragen

Bevor du weiterliest, versuche diese Fragen für dein Projekt zu beantworten:

  1. Welches Format? OpenAPI 3.x? AsyncAPI? Etwas anderes?
  2. Welche Beispiele braucht ihr? Jeden Endpoint? Nur die wichtigsten?
  3. Braucht ihr SDKs? Für welche Sprachen?
  4. Wie testen Entwickler? Sandbox? Postman? curl?
  5. Wie erreichen euch Entwickler bei Problemen? Support? Community?

OpenAPI Specification

OpenAPI (früher Swagger) ist der Standard für API-Dokumentation.

Warum OpenAPI?

Vorteil Beschreibung
Maschinenlesbar Tools können Docs, SDKs, Tests generieren
Standardisiert Entwickler kennen das Format
Validierbar CI kann Spec gegen Code prüfen
Interaktiv Swagger UI, Redoc, etc.

Grundstruktur

openapi: 3.1.0
info:
  title: Example API
  version: 2.3.1
  description: |
    Die Example API ermöglicht...

    ## Authentifizierung
    Alle Requests benötigen einen Bearer Token...

servers:
  - url: https://api.example.com/v2
    description: Production
  - url: https://api.staging.example.com/v2
    description: Staging

security:
  - bearerAuth: [ ]

paths:
  /orders:
    get:
      summary: List orders
      operationId: listOrders
      # ...

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

Endpoint-Dokumentation

paths:
  /orders:
    get:
      summary: List orders
      description: |
        Gibt eine paginierte Liste aller Orders zurück.

        Unterstützt Filtering nach Status und Datum.
      operationId: listOrders
      tags:
        - Orders
      parameters:
        - name: status
          in: query
          description: Filter by order status
          schema:
            type: string
            enum: [ pending, confirmed, shipped, delivered ]
          example: pending
        - name: limit
          in: query
          description: Maximum number of results
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
          example: 50
        - name: cursor
          in: query
          description: Pagination cursor from previous response
          schema:
            type: string
          example: eyJpZCI6MTIzfQ
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderList'
              example:
                data:
                  - id: order_abc123
                    status: pending
                    total: 9999
                    created_at: '2026-01-19T10:30:00Z'
                pagination:
                  next_cursor: eyJpZCI6NDU2fQ
                  has_more: true
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

Schema-Definitionen

components:
  schemas:
    Order:
      type: object
      required:
        - id
        - status
        - total
        - created_at
      properties:
        id:
          type: string
          description: Unique order identifier
          example: order_abc123
          pattern: '^order_[a-z0-9]+$'
        status:
          type: string
          enum: [ pending, confirmed, shipped, delivered, cancelled ]
          description: Current order status
          example: pending
        total:
          type: integer
          format: int64
          description: Total amount in cents
          example: 9999
          minimum: 0
        currency:
          type: string
          description: ISO 4217 currency code
          example: EUR
          default: EUR
        items:
          type: array
          items:
            $ref: '#/components/schemas/OrderItem'
        created_at:
          type: string
          format: date-time
          description: Creation timestamp (ISO 8601)
          example: '2026-01-19T10:30:00Z'
        metadata:
          type: object
          additionalProperties: true
          description: Custom key-value pairs
          example:
            customer_note: "Please gift wrap"

Error Responses

components:
  responses:
    BadRequest:
      description: Invalid request
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            type: https://api.example.com/errors/validation-failed
            title: Validation Failed
            status: 400
            error_code: VALIDATION_FAILED
            detail: The request body contains invalid fields.
            request_id: req_abc123
            errors:
              - field: email
                code: INVALID_FORMAT
                message: Must be a valid email address.

  schemas:
    Error:
      type: object
      required:
        - type
        - title
        - status
        - error_code
      properties:
        type:
          type: string
          format: uri
        title:
          type: string
        status:
          type: integer
        error_code:
          type: string
        detail:
          type: string
        request_id:
          type: string
        errors:
          type: array
          items:
            $ref: '#/components/schemas/FieldError'

OpenAPI Validierung in CI

# .github/workflows/api.yml
name: API Validation

on: [ push, pull_request ]

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Validate OpenAPI
        uses: char0n/swagger-editor-validate@v1
        with:
          definition-file: openapi.yaml

      - name: Check for breaking changes
        run: |
          git show origin/main:openapi.yaml > /tmp/openapi-main.yaml
          npx oasdiff breaking /tmp/openapi-main.yaml openapi.yaml

Beispiele, die funktionieren

Beispiele sind das Wichtigste in der Dokumentation. Sie müssen funktionieren.

Anforderungen an Beispiele

Anforderung Warum?
Vollständig Copy-Paste muss funktionieren
Realistisch Keine foo, bar, test123
Konsistent Gleiche IDs/Daten überall
Aktuell Bei API-Änderungen updaten

Request-Beispiele

Beispiel: Order anlegen.

Request:

curl -X POST https://api.example.com/v2/orders \
  -H "Authorization: Bearer sk_live_abc123" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: ord_req_xyz789" \
  -d '{
    "customer_id": "cus_def456",
    "items": [
      {
        "product_id": "prod_ghi789",
        "quantity": 2
      }
    ],
    "shipping_address": {
      "line1": "123 Main St",
      "city": "Berlin",
      "postal_code": "10115",
      "country": "DE"
    }
  }'

Response:

{
  "id": "order_abc123",
  "status": "pending",
  "customer_id": "cus_def456",
  "items": [
    {
      "product_id": "prod_ghi789",
      "name": "Widget Pro",
      "quantity": 2,
      "unit_price": 4999,
      "total": 9998
    }
  ],
  "subtotal": 9998,
  "shipping": 499,
  "total": 10497,
  "currency": "EUR",
  "created_at": "2026-01-19T10:30:00Z"
}

Error-Beispiele

Zeige auch, was schiefgehen kann. Beispiel:

Validation Error (400)

curl -X POST https://api.example.com/v2/orders \
  -H "Authorization: Bearer sk_live_abc123" \
  -H "Content-Type: application/json" \
  -d '{"customer_id": ""}'
{
  "type": "https://api.example.com/errors/validation-failed",
  "title": "Validation Failed",
  "status": 400,
  "error_code": "VALIDATION_FAILED",
  "request_id": "req_xyz789",
  "errors": [
    {
      "field": "customer_id",
      "code": "REQUIRED",
      "message": "Customer ID is required."
    },
    {
      "field": "items",
      "code": "REQUIRED",
      "message": "At least one item is required."
    }
  ]
}

Rate Limit (429)

{
  "type": "https://api.example.com/errors/rate-limit-exceeded",
  "title": "Too Many Requests",
  "status": 429,
  "error_code": "RATE_LIMIT_EXCEEDED",
  "detail": "Rate limit exceeded. Please wait 30 seconds.",
  "request_id": "req_abc123"
}

Response Headers:

Retry-After: 30
RateLimit-Policy: "user";q=100;w=60
RateLimit: "user";r=0;t=30

Beispiele testen

Beispiele automatisch testen:

# tests/test_docs_examples.py
import subprocess
import json

def test_create_order_example():
    """Test that the documented curl example works."""
    result = subprocess.run([
        "curl", "-s", "-X", "POST",
        "https://api.staging.example.com/v2/orders",
        "-H", f"Authorization: Bearer {TEST_API_KEY}",
        "-H", "Content-Type: application/json",
        "-d", json.dumps({
            "customer_id": "cus_test",
            "items": [{"product_id": "prod_test", "quantity": 1}]
        })
    ], capture_output=True, text=True)

    response = json.loads(result.stdout)
    assert "id" in response
    assert response["status"] == "pending"

Authentication Guide

Auth ist oft der schwierigste Teil. Dokumentiere ihn gut.

Übersicht

Die Example API unterstützt zwei Authentifizierungsmethoden:

Methode Use Case Empfohlen für
API Keys Server-to-Server Backend-Integration
OAuth 2.0 User-Kontext Mobile/Web Apps

API Keys

API Key erstellen

  1. Gehe zu dashboard.example.com/api-keys
  2. Klicke Create API Key
  3. Wähle die benötigten Scopes
  4. Kopiere den Key (wird nur einmal angezeigt)

API Key verwenden

curl https://api.example.com/v2/orders \
  -H "Authorization: Bearer sk_live_abc123"

Environments

Environment Key-Präfix URL
Production sk_live_ api.example.com
Test sk_test_ api.staging.example.com

Wichtig: Test-Keys funktionieren nur gegen die Staging-API. Production-Keys niemals in Client-Code oder Repos committen.

OAuth 2.0

Flows

Flow Use Case
Authorization Code + PKCE Web/Mobile mit User-Login
Client Credentials Server-to-Server

Authorization Code Flow

  1. User zu Authorization URL leiten:
https://auth.example.com/oauth/authorize?
  client_id=YOUR_CLIENT_ID&
  redirect_uri=https://yourapp.com/callback&
  response_type=code&
  scope=orders:read orders:write&
  state=random_state_string&
  code_challenge=BASE64_CHALLENGE&
  code_challenge_method=S256
  1. Authorization Code gegen Token tauschen:
curl -X POST https://auth.example.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=AUTHORIZATION_CODE" \
  -d "redirect_uri=https://yourapp.com/callback" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "code_verifier=ORIGINAL_VERIFIER"
  1. Access Token verwenden:
curl https://api.example.com/v2/orders \
  -H "Authorization: Bearer ACCESS_TOKEN"

Token Refresh

curl -X POST https://auth.example.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=REFRESH_TOKEN" \
  -d "client_id=YOUR_CLIENT_ID"

SDKs und Client Libraries

SDKs können Integration drastisch vereinfachen.

Wann SDKs?

Pro SDK Contra SDK
Komplexe Auth (OAuth) Einfache REST-API
Viele Sprachen im Einsatz Wenige Integratoren
Komplexe Datentypen Maintenance-Aufwand
Retry-Logic eingebaut SDK-Bugs = Support-Tickets

SDK-Generierung

Aus OpenAPI automatisch generieren:

# OpenAPI Generator
openapi-generator generate \
  -i openapi.yaml \
  -g typescript-fetch \
  -o ./sdk/typescript

# Speakeasy (kommerzielle Alternative)
speakeasy generate sdk \
  --schema openapi.yaml \
  --lang typescript \
  --out ./sdk/typescript

SDK-Beispiel

TypeScript SDK

Installation:

npm install @example/api-sdk

Quickstart:

import {ExampleAPI} from '@example/api-sdk';

const api = new ExampleAPI({
    apiKey: 'sk_live_abc123'
});

// List orders
const orders = await api.orders.list({
    status: 'pending',
    limit: 50
});

// Create order
const order = await api.orders.create({
    customer_id: 'cus_def456',
    items: [
        {product_id: 'prod_ghi789', quantity: 2}
    ]
});

console.log(order.id); // order_abc123

Error Handling:

import {ExampleAPI, ValidationError, RateLimitError} from '@example/api-sdk';

try {
    await api.orders.create({ /* ... */});
} catch (error) {
    if (error instanceof ValidationError) {
        console.log(error.errors); // Field-level errors
    } else if (error instanceof RateLimitError) {
        console.log(`Retry after ${error.retryAfter} seconds`);
    }
}

API Explorer und Sandbox

Interaktives Testen macht das Lernen einfacher.

Swagger UI / Redoc

# Einbetten in Docs
x-logo:
  url: https://example.com/logo.png
  altText: Example API

x-tagGroups:
  - name: Orders
    tags:
      - Orders
      - Order Items
  - name: Customers
    tags:
      - Customers

Sandbox-Umgebung

Feature Production Sandbox
URL api.example.com sandbox.api.example.com
API Key sk_live_* sk_test_*
Daten Echte Daten Test-Daten
Limits Voll Reduziert
Webhooks Echte Events Simulierte Events

Test-Daten

Dokumentiere vordefinierte Test-Daten, damit Integrationen reproduzierbar sind.

Test Customers:

ID Name Beschreibung
cus_test_success Test Success Alle Operationen erfolgreich
cus_test_decline Test Decline Zahlungen werden abgelehnt
cus_test_error Test Error Simuliert Server-Fehler

Test Products:

ID Name Preis
prod_test_widget Test Widget €49.99
prod_test_gadget Test Gadget €99.99

Fehler simulieren:

Um einen 429 Rate Limit Error zu simulieren:

curl https://sandbox.api.example.com/v2/orders \
  -H "Authorization: Bearer sk_test_abc123" \
  -H "X-Simulate-Error: rate_limit"

Onboarding

Der erste Eindruck zählt. Mach den Einstieg einfach.

Quickstart Guide

Ein Quickstart sollte in unter 5 Minuten zur ersten erfolgreichen Response führen.

1. API Key erstellen

Registriere dich und erstelle einen Test-API-Key (dashboard.example.com).

2. Ersten Request machen

curl https://api.example.com/v2/orders \
  -H "Authorization: Bearer YOUR_API_KEY"

3. Order erstellen

curl -X POST https://api.example.com/v2/orders \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "cus_test_success",
    "items": [{"product_id": "prod_test_widget", "quantity": 1}]
  }'

Nächste Schritte

Glossar

Erkläre Domain-spezifische Begriffe, damit neue Teams schneller onboarden.

Begriff Definition
Order Eine Bestellung eines Kunden
Line Item Ein einzelner Posten in einer Order
Fulfillment Der Prozess der Auftragsabwicklung
Idempotency Key Eindeutiger Schlüssel zur Vermeidung doppelter Requests
Webhook HTTP-Callback bei Events
Cursor Opaker String für Pagination

Support und Feedback

Entwickler brauchen Hilfe. Mach es ihnen einfach.

Support-Kanäle

Kanal Use Case Response Time
Docs Self-Service Sofort
FAQ Häufige Fragen Sofort
GitHub Issues Bugs, Feature Requests 1-3 Tage
Discord/Slack Community-Support Variabel
E-Mail Kritische Issues 24h
Enterprise Support SLA-gebunden 1-4h

Feedback sammeln

Ein kurzes Feedback-Widget reicht:

  • Frage: War diese Seite hilfreich?
  • Schnellfeedback: 👍 Ja / 👎 Nein
  • Optionales Freitextfeld + Absenden

Status Page

Verlinke eine Status Page sichtbar und beschreibe, was dort zu finden ist:

  • Aktuelle Verfügbarkeit und Incidents
  • status.example.com
  • Abo-Optionen: RSS, E-Mail, Slack

Regeln & Anti-Patterns

Do

  • OpenAPI als Single Source of Truth
  • Beispiele, die Copy-Paste funktionieren
  • Error-Beispiele für jeden Fehlertyp
  • Auth-Guide mit Schritt-für-Schritt-Anleitung
  • Sandbox für risikofreies Testen
  • Quickstart-Guide für schnellen Einstieg
  • Glossar für Domain-Begriffe
  • Changelog und Versionshinweise
  • Feedback-Möglichkeit auf jeder Seite

Don't

  • Veraltete Beispiele
  • foo, bar, test als Beispielwerte
  • Auth ohne Code-Beispiele
  • Nur generierte Docs ohne Kontext
  • Broken Links
  • Docs ohne Suche
  • Keine Error-Dokumentation
  • SDK ohne Beispiele

Artefakt: Dokumentations-Checkliste

# API-Dokumentations-Checkliste

## OpenAPI Spec

- [ ] OpenAPI 3.x Format
- [ ] Alle Endpoints dokumentiert
- [ ] Request/Response Schemas definiert
- [ ] Beispiele für jeden Endpoint
- [ ] Error Responses dokumentiert
- [ ] Authentication dokumentiert
- [ ] CI-Validierung eingerichtet

## Beispiele

### Für jeden Endpoint

- [ ] curl-Beispiel (Request)
- [ ] Response-Beispiel (Success)
- [ ] Error-Beispiel (mindestens 400, 401)

### Qualität

- [ ] Realistische Daten (keine `foo`, `bar`)
- [ ] Konsistente IDs über Beispiele hinweg
- [ ] Vollständig (Copy-Paste funktioniert)
- [ ] Automatisch getestet

## Authentication

- [ ] Übersicht der Auth-Methoden
- [ ] API Key: Erstellen, Verwenden, Scopes
- [ ] OAuth: Flows, Endpoints, Beispiele
- [ ] Token Refresh dokumentiert
- [ ] Fehler bei Auth dokumentiert

## Getting Started

- [ ] Quickstart-Guide (< 5 Minuten)
- [ ] Schritt-für-Schritt mit Code
- [ ] Link zu API Key erstellen
- [ ] Erster Request zum Testen

## Reference

- [ ] Alle Endpoints
- [ ] Alle Parameter
- [ ] Alle Schemas
- [ ] Alle Error Codes
- [ ] Rate Limits
- [ ] Pagination erklärt

## SDKs (falls vorhanden)

- [ ] Installation
- [ ] Quickstart
- [ ] Error Handling
- [ ] Alle Sprachen dokumentiert

## Sandbox / Testing

- [ ] Sandbox-URL dokumentiert
- [ ] Test-API-Keys erklärt
- [ ] Test-Daten dokumentiert
- [ ] Error-Simulation erklärt

## Support

- [ ] Support-Kanäle dokumentiert
- [ ] FAQ vorhanden
- [ ] Status Page verlinkt
- [ ] Feedback-Möglichkeit

## Meta

- [ ] Glossar / Begriffserklärungen
- [ ] Changelog
- [ ] Versionierung erklärt
- [ ] Suchfunktion
- [ ] Mobile-freundlich

Checkliste

Bevor du zum nächsten Artikel gehst, prüfe:

  • [ ] OpenAPI-Spec ist vollständig und validiert
  • [ ] Beispiele funktionieren (getestet!)
  • [ ] Auth-Guide mit Code-Beispielen
  • [ ] Quickstart-Guide existiert
  • [ ] Error Responses sind dokumentiert
  • [ ] Sandbox/Test-Umgebung ist dokumentiert
  • [ ] Support-Kanäle sind klar
  • [ ] Glossar für Domain-Begriffe
  • [ ] Dokumentations-Checkliste ist abgearbeitet

Wie es weitergeht

Im nächsten Teil geht es um Testing und Quality Gates: Wie du sicherstellst, dass deine API funktioniert, bevor sie live geht – von Unit Tests über Contract Tests bis zu Security Scans.

Alle Teile der Serie: Serie: API-Design

Mehr Beiträge aus dem Blog.