JSON Toolkit

FAQ zur Teamzusammenarbeit: Verträge, Konfiguration und Fixtures

Fazit: Benennungsstil, Zeitformate, null-Semantik, Enum-Formen, Konfigurationsformate, Fixture-Organisation und Merge-Konflikte – zwölf Abwägungen, über die Teams tatsächlich streiten.

Fortgeschritten~12 Min. LesezeitVeröffentlicht 2026-10-30Aktualisiert 2026-10-30
Titelbild für die FAQ zur Teamzusammenarbeit

Kurz gesagt: Klären Sie diese Punkte einmal in einer Teamkonvention – eine {"data":…,"meta":…}-Hülle mit HTTP-Statuscodes, ein projektweiter Benennungsstil, RFC-3339-Zeitstempel mit Zeitzone und String-Enums – und entwickeln Sie dann jede neue API gegen denselben Vertrag, indem Sie nur Felder hinzufügen, sie nie ändern oder löschen.

Es gibt keine einzige richtige Antwort auf diese Fragen, aber ein Team muss eine einzige Antwort haben – sonst beginnt jede neue API dieselbe Diskussion neu.

1. API-Verträge

Welche Struktur sollte eine API zurückgeben?

Drei verbreitete Formen, jede mit Kosten:

Form Beispiel Vorteile Nachteile
Rohdaten [{...}, {...}] Einfach Kann keine Metadaten tragen
Feste Hülle {"code":0,"message":"ok","data":{...}} Einheitliche Fehlerbehandlung Geschäftscode dupliziert den HTTP-Status
Ressourcenhülle {"data":{...},"meta":{...},"links":{...}} Erweiterbar, klare Semantik Eine zusätzliche Verschachtelungsebene

Für interne Geschäfts-APIs bevorzugen Sie „Ressourcenhülle + HTTP-Statuscodes, die das Ergebnis ausdrücken“:

{
  "data": [{ "id": "1", "name": "示例" }],
  "meta": { "total": 128, "page": 2, "pageSize": 20 }
}

Verwenden Sie für Fehler einen HTTP-Statuscode plus einen strukturierten Fehler-Body, statt einen weiteren code zu verschachteln:

{
  "error": {
    "type": "validation_failed",
    "message": "请求参数校验失败",
    "details": [
      { "path": "/email", "reason": "格式不正确" }
    ]
  }
}

Kernpunkt: HTTP-Statuscodes drücken bereits Erfolg oder Fehlschlag aus, ein Geschäftscode ist also redundant. Koexistieren die beiden Systeme, sind Inkonsistenzen wie „201, aber code ist 500“ fast unvermeidlich.

Vermeiden Sie nackte Arrays. Mit einem Array auf oberster Ebene können Sie Paginierung, Summen oder Cursor nicht anhängen, und sie später hinzuzufügen heißt, jeden Aufrufer zu ändern.

Sollten Feldnamen snake_case oder camelCase verwenden?

Wählen Sie eines, wenden Sie es projektweit an und mischen Sie sie nie innerhalb eines JSON-Dokuments.

Stil Häufiges Ökosystem Beispiel
camelCase JavaScript / TypeScript / Java userName, createdAt
snake_case Python / Ruby / Go (teils) / Datenbankspalten user_name, created_at
kebab-case Selten; mit Bindestrichen versehene Schlüssel sind umständlich zuzugreifen user-name

Kriterien:

  1. Wer konsumiert dieses JSON: camelCase wählen, wenn das Frontend dominiert, snake_case, wenn Datenpipelines und Python-Dienste dominieren;
  2. Bildet es direkt auf Datenbankspalten ab: snake_case spart eine Konvertierungsschicht, wenn Tabellenstrukturen direkt durchgereicht werden;
  3. Kontinuität bestehender Systeme: Behalten Sie, was die bestehende API verwendet; Konsistenz schlägt Korrektheit.

Müssen Sie wirklich konvertieren, tun Sie es an der Grenze (Gateway oder Frontend-Request-Schicht), statt toCamelCase-Aufrufe durch den Geschäftscode zu verstreuen.

Welches Format sollten Zeitfelder verwenden?

Verwenden Sie RFC-3339-/ISO-8601-Strings mit einem Zeitzonen-Offset:

{
  "createdAt": "2026-10-30T11:37:57+08:00",
  "updatedAt": "2026-10-30T03:37:57Z"
}

Kernpunkte:

  • Die Zeitzone einschließen: 2026-10-30 11:37:57 ohne Zone bricht in zeitzonenübergreifenden Szenarien unweigerlich;
  • Z oder einen Offset konsistent verwenden: Beides ist korrekt, aber mischen Sie sie nicht innerhalb einer API;
  • Numerische Zeitstempel vermeiden: Ob Sekunden oder Millisekunden, und ob Schaltsekunden enthalten sind, muss jedes Team neu interpretieren. Ist Kompaktheit nötig, verwenden Sie eine Millisekunden-Ganzzahl, aber nageln Sie die Einheit in der Dokumentation fest.

Bevorzugen Sie Feldnamen mit At-Suffix wie createdAt / updatedAt / deletedAt, damit auf einen Blick klar ist, dass der Wert ein Zeitpunkt statt einer Dauer ist. Für Dauern verwenden Sie timeoutMs, ttlSeconds – legen Sie die Einheit in den Namen.

Sollten Nullen null sein oder ein weggelassenes Feld?

Das hängt davon ab, ob „dieses Feld bedeutsam ist“:

Semantik Form Hinweise
Das Feld existiert, hat aber noch keinen Wert "name": null Sagt ausdrücklich „es wurde geprüft und ist leer“
Das Feld ist für diese Ressource irrelevant Weglassen Ein regulärer Nutzer sollte etwa kein vipExpireAt haben
Partielles Update (PATCH) Weglassen = nicht ändern Nur null bedeutet hier „leeren“

Der dritte Fall wird am häufigsten übersehen. In einer PATCH-Anfrage:

{ "nickname": null }

bedeutet das „den Nickname leeren“, während nickname aus dem Request-Body wegzulassen „den Nickname nicht anfassen“ bedeutet. Behandeln Sie beides als „leeren“, löscht ein Nutzer, der seine E-Mail ändert, seinen Nickname.

Noch einmal: Verwenden Sie nicht undefined. Es ist kein gültiger JSON-Wert, und JSON.stringify verwirft den Schlüssel vollständig, das Verhalten entspricht also „weglassen“, während der Code aussieht wie „ein leerer Wert wurde ausdrücklich übergeben“.

Wie sollten Boolean-Felder benannt werden?

Verwenden Sie die Präfixe is / has / can / should und vermeiden Sie Verneinungen.

{
  "isActive": true,
  "hasPassword": false,
  "canEdit": true
}

Drei Lehren:

  1. Keine Verneinungen: isDisabled: false zwingt den Leser, es einmal zu invertieren; isEnabled: true ist direkter. Doppelte Verneinung (isNotDisabled) ist ein Desaster;
  2. Keine Zahlen für Booleans: "enabled": 1 lässt jeden Konsumenten einmal === 1 schreiben;
  3. Keine Strings: "enable": "true" ist in JavaScript wahrheitswertig, und if (data.enable) ist auch bei "false" wahr; solche Bugs sind extrem schwer zu verfolgen.

Sollten Enum-Felder Zahlen oder Strings verwenden?

Verwenden Sie Strings, sofern es keine klare Speicher- oder Bandbreitenbeschränkung gibt.

{ "status": "active" }

Verglichen mit { "status": 1 } gewinnen Strings, weil:

  • Logs, Packet Captures und Datenbanken direkt lesbar sind, ohne eine Abbildungstabelle nachzuschlagen;
  • Ein hinzugefügter Enum-Wert die Bedeutung bestehender Werte nicht ändert (einen Wert mitten in ein numerisches Enum einzufügen verschiebt alles);
  • Das Frontend keine 1 → 'active'-Abbildung synchron halten muss.

Die Kosten sind ein paar zusätzliche Bytes, die nach Kompression nahezu vernachlässigbar sind.

Begleitende Praxis: Verwenden Sie für String-Enum-Werte Kleinbuchstaben + Unterstriche (pending_review) und beschränken Sie sie mit enum im Schema, damit ungültige Werte in der Validierungsphase abgelehnt werden.

2. Konfiguration und Fixtures

Sollte Konfiguration JSON, YAML oder TOML sein?

Wählen Sie nach Zweck, nicht nach Vorliebe:

Format Gut für Schlecht für
JSON Programmatisches Lesen und Schreiben, strikt strukturierte Daten, Schema-Validierung Häufiges manuelles Bearbeiten (Kommentare nicht erlaubt)
YAML Tief verschachtelte Deployment-Konfiguration (K8s) Von Hand geschriebene Einrückung ist fehleranfällig; yes/no werden zu Booleans
TOML Flache Abhängigkeits- und Werkzeugkonfiguration (Cargo.toml, pyproject.toml) Schlechte Lesbarkeit bei tiefer Verschachtelung
JSONC Editor-Konfiguration, die Kommentare braucht (tsconfig.json) Systemgrenzen überschreiten

Ein häufiger Teamfehler ist, Geschäftskonfiguration in YAML zu speichern – YAMLs implizite Typkonvertierung (1.0 wird eine Zahl, NO wird ein Boolean, 2026-10-30 wird ein Datum) erzeugt über Parser hinweg unterschiedliche Ergebnisse.

Muss die Konfiguration strikt von einem Programm validiert werden, wählen Sie JSON + Schema und dokumentieren Sie Kommentare über ein _comment-Feld oder separate Dokumentation.

Wie sollten Test-Fixtures organisiert sein?

Organisieren Sie nach „eine Basis + minimale Diffs“, nicht nach dem Kopieren eines riesigen JSON für jeden Testfall.

fixtures/
├─ users/
│  ├─ base.json              # Baseline user object
│  ├─ no-email.json          # Only email is missing
│  └─ invalid-age.json       # Only age is out of range
└─ fixtures.ts               # Utility functions for loading and shallow merging
import baseUser from './users/base.json';

export function makeUser(overrides: Partial<User> = {}): User {
  return { ...baseUser, ...overrides };
}

So muss ein neuer Testfall nur die abweichenden Felder schreiben, und eine Änderung an einem Basisfeld aktualisiert jeden Fall automatisch.

Drei Regeln:

  1. Fixtures müssen die Schema-Validierung bestehen: das Basis-Fixture selbst sollte gültige Daten sein;
  2. Keine echten Produktionsdaten exportieren: Telefonnummern, Ausweisnummern und Adressen sind alle personenbezogene Informationen;
  3. Fixtures gehören in die Versionskontrolle, müssen aber klein bleiben: eine einzelne Datei über ein paar Dutzend KB verdient Beschneidung oder Generierung.

Wie reduzierte ich Merge-Konflikte in JSON-Dateien?

JSON konfligiert leicht: Ein Formatter fließt die ganze Datei auf einmal um, zwei Personen, die je eine Zeile ändern, konfligieren also über die ganze Datei.

Vier Taktiken:

  1. Formatierung vereinheitlichen und in .editorconfig eintragen: konsistente Einrückung, Zeilenenden und abschließender Zeilenumbruch vermeiden unbezogene Diffs;
  2. Schlüssel sortieren: einigen Sie sich auf alphabetische Reihenfolge, damit ein neues Feld nicht mit dem Einfügepunkt eines anderen kollidiert;
  3. Dateien aufteilen: eine riesige config.json nach Domäne in mehrere Dateien aufteilen, und die Konfliktoberfläche schrumpft natürlich;
  4. „Alles neu formatieren“-Commits vermeiden: Trennen Sie Formatierung und Geschäftsänderungen in zwei Commits, damit das Review lesbar bleibt.

Verwendet das Team Lockdateien (pnpm-lock.yaml, package-lock.json), mergen Sie sie nicht von Hand, sondern generieren Sie sie neu:

git checkout --theirs pnpm-lock.yaml
pnpm install

Wie pflege ich Versionskompatibilität?

Das Prinzip lautet „hinzufügen, nicht ändern, nicht entfernen“.

Änderung Kompatibilität Ansatz
Ein optionales Feld ergänzen Kompatibel Hinzufügen; Konsumenten ignorieren unbekannte Felder
Ein Pflichtfeld ergänzen Inkompatibel Die Version erhöhen oder einen Standardwert liefern
Ein Feld entfernen Inkompatibel Zuerst als veraltet markieren, Aufrufer beobachten, dann entfernen
Den Typ eines Feldes ändern Inkompatibel Einen neuen Feldnamen ergänzen und während der Übergangszeit doppelt schreiben
Die Enum-Wertemenge ändern Kommt darauf an Werte hinzuzufügen ist kompatibel; sie zu entfernen nicht

Unterstützende Mechanismen:

  • Konsumenten verwenden „nachsichtiges Parsen“: unbekannte Felder ignorieren und fehlenden Standardwerte liefern;
  • Der Server behält alte Felder eine Weile und liefert einen Deprecation-Header in der Antwort als Hinweis;
  • Im Schema neue Felder nicht als required markieren und veraltete Felder mit deprecated: true taggen.

Wie validiere ich Verträge in CI?

Behandeln Sie das Schema als Teil des Codes und validieren Sie es bei jedem Commit.

# Validate sample data against the Schema (using ajv-cli)
npx ajv-cli validate -s schemas/user.json -d "fixtures/users/*.json" --strict=false

Führen Sie drei Dinge in CI aus:

  1. Gültigkeit des Schemas selbst: ob die $schema-Deklaration gültig ist und ob $ref auflöst;
  2. Ob die Fixtures zum Schema passen: stellt sicher, dass Testdaten nicht driften;
  3. Ob der Vertrag rückwärtskompatibel ist: gegen die vorherige Version vergleichen und auf entfernte Felder oder geänderte Typen prüfen.

Der dritte Punkt braucht Werkzeugunterstützung (etwa openapi-diff oder json-schema-diff); ohne sie vergleichen Sie zumindest Änderungen in den required-Arrays und den properties-Schlüsselmengen mit einem Skript.

3. Kurzreferenz

Frage Empfehlung
Response-Struktur {"data":..., "meta":...}, mit HTTP-Statuscodes für Fehler
Benennungsstil camelCase (frontend-orientiert) oder snake_case (datenorientiert), projektweit konsistent
Zeitformat RFC-3339-Strings mit Zeitzone, Feldnamen auf At endend
Nullen null für keinen Wert, irrelevante Felder weglassen, Weglassen in PATCH bedeutet „nicht ändern“
Boolean-Benennung is/has/can-Präfixe, keine Verneinungen, kein 0/1
Enums Strings, Kleinbuchstaben mit Unterstrichen, enum im Schema ergänzen
Konfigurationsformat JSON für programmatische Validierung, TOML oder JSONC für manuelles Bearbeiten
Fixtures Eine Basis + Minimal-Diff-Overrides, gültig gegen das Schema
Merge-Konflikte Formatierung vereinheitlichen, Schlüssel sortieren, Dateien aufteilen
Versionskompatibilität Hinzufügen, nicht ändern, nicht löschen; vor dem Entfernen als veraltet markieren