API-Integrations-Skill-Beispiel

Ein Skill für die Gestaltung und Implementierung robuster API-Integrationen.

Anwendungsfall

Dieser Skill hilft bei:

  • RESTful API-Design
  • Fehlerbehandlungsmustern
  • Authentifizierungsimplementierungen
  • Rate-Limiting und Retry-Logik

Vollständige SKILL.md

markdown
---
name: API Integration Best Practices
description: Design and implement robust, maintainable API integrations
version: 1.0.0
author: API Design Community
platforms:
  - claude-code
  - codex
categories:
  - development
  - backend
tags:
  - api
  - rest
  - integration
---

# API Integration Best Practices

## Designprinzipien

1. **Konsistenz**: Verwenden Sie konsistente Benennungen und Muster
2. **Resilienz**: Behandeln Sie Fehler elegant
3. **Sicherheit**: Schützen Sie Daten bei der Übertragung und im Ruhezustand
4. **Beobachtbarkeit**: Loggen und überwachen Sie effektiv

## RESTful Design

### URL-Struktur

\`\`\`
GET    /api/v1/users          # Benutzer auflisten
GET    /api/v1/users/:id      # Benutzer abrufen
POST   /api/v1/users          # Benutzer erstellen
PATCH  /api/v1/users/:id      # Benutzer aktualisieren
DELETE /api/v1/users/:id      # Benutzer löschen
\`\`\`

### Namenskonventionen
- Verwenden Sie Pluralnomen für Sammlungen
- Verwenden Sie Kleinbuchstaben mit Bindestrichen
- Vermeiden Sie Verben in URLs (Aktionen sind HTTP-Methoden)
- Versionieren Sie Ihre API (v1, v2)

## Antwortformate

### Erfolgsantwort

\`\`\`json
{
  "data": {
    "id": "123",
    "type": "user",
    "attributes": {
      "name": "John Doe",
      "email": "[email protected]"
    }
  },
  "meta": {
    "requestId": "req_abc123"
  }
}
\`\`\`

### Fehlerantwort

\`\`\`json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Email is required",
    "details": [
      {
        "field": "email",
        "message": "This field is required"
      }
    ]
  },
  "meta": {
    "requestId": "req_abc123"
  }
}
\`\`\`

### Paginierung

\`\`\`json
{
  "data": [...],
  "pagination": {
    "page": 1,
    "perPage": 20,
    "total": 100,
    "totalPages": 5
  },
  "links": {
    "self": "/api/v1/users?page=1",
    "next": "/api/v1/users?page=2",
    "prev": null
  }
}
\`\`\`

## HTTP-Statuscodes

| Code | Bedeutung | Wann verwenden |
|------|---------|-------------|
| 200 | OK | Erfolgreiches GET, PUT, PATCH |
| 201 | Created | Erfolgreiches POST |
| 204 | No Content | Erfolgreiches DELETE |
| 400 | Bad Request | Ungültige Eingabe |
| 401 | Unauthorized | Fehlende/ungültige Authentifizierung |
| 403 | Forbidden | Gültige Authentifizierung, keine Berechtigung |
| 404 | Not Found | Ressource existiert nicht |
| 422 | Unprocessable | Validierungsfehler |
| 429 | Too Many Requests | Rate-limitiert |
| 500 | Server Error | Unerwarteter Fehler |

## Fehlerbehandlung

### Client-Implementierung

\`\`\`typescript
async function fetchWithRetry<T>(
  url: string,
  options: RequestInit,
  maxRetries = 3
): Promise<T> {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);

      if (response.status === 429) {
        const retryAfter = response.headers.get('Retry-After');
        await sleep(parseInt(retryAfter || '1') * 1000);
        continue;
      }

      if (!response.ok) {
        throw new ApiError(response.status, await response.json());
      }

      return response.json();
    } catch (error) {
      if (attempt === maxRetries) throw error;
      await sleep(Math.pow(2, attempt) * 1000); // Exponential backoff
    }
  }
}
\`\`\`

## Authentifizierung

### Bearer Token

\`\`\`typescript
const response = await fetch('/api/resource', {
  headers: {
    'Authorization': \`Bearer \${accessToken}\`,
    'Content-Type': 'application/json'
  }
});
\`\`\`

### Token-Aktualisierung

\`\`\`typescript
async function refreshAccessToken(refreshToken: string) {
  const response = await fetch('/api/auth/refresh', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ refreshToken })
  });

  if (!response.ok) {
    throw new AuthError('Token refresh failed');
  }

  return response.json();
}
\`\`\`

## Rate-Limiting

### Client-seitige Behandlung

\`\`\`typescript
class RateLimiter {
  private queue: Array<() => Promise<void>> = [];
  private processing = false;
  private requestsPerSecond: number;

  constructor(requestsPerSecond = 10) {
    this.requestsPerSecond = requestsPerSecond;
  }

  async throttle<T>(fn: () => Promise<T>): Promise<T> {
    return new Promise((resolve, reject) => {
      this.queue.push(async () => {
        try {
          resolve(await fn());
        } catch (error) {
          reject(error);
        }
      });
      this.processQueue();
    });
  }

  private async processQueue() {
    if (this.processing) return;
    this.processing = true;

    while (this.queue.length > 0) {
      const fn = this.queue.shift()!;
      await fn();
      await sleep(1000 / this.requestsPerSecond);
    }

    this.processing = false;
  }
}
\`\`\`

## Sicherheits-Checkliste

- [ ] HTTPS überall verwenden
- [ ] Alle Eingaben validieren
- [ ] Ausgabe bereinigen
- [ ] Rate-Limiting implementieren
- [ ] Sichere Token-Speicherung verwenden
- [ ] Sicherheitsereignisse protokollieren
- [ ] Anmeldedaten regelmäßig rotieren

Nächste Schritte