Gängige Designmuster

Leere Antworten

Die Standardmethode Delete sollte google.protobuf.Empty zurückgeben, es sei denn, sie führt einen vorläufigen Löschvorgang durch. In diesem Fall sollte die Methode die Ressource mit ihrem aktualisierten Status zurückgeben, der anzeigt, dass das Löschen in Arbeit ist.

Benutzerdefinierte Methoden sollten eigene XxxResponse-Nachrichten haben, auch wenn diese leer sind, da davon auszugehen ist, dass ihre Funktionalität mit der Zeit zunimmt und sie in diesem Fall zusätzliche Daten zurückgeben müssen.

Bereiche darstellen

Felder, die Bereiche darstellen, sollten halboffene Intervalle mit der Namenskonvention [start_xxx, end_xxx) verwenden, z. B. [start_key, end_key) oder [start_time, end_time). Die halboffene Intervallsemantik ist in der C++-Bibliothek STL und der Java-Standardbibliothek gängig. Bereich sollten in APIs nicht auf andere Weise, wie etwa in (index, count) oder [first, last] dargestelllt werden.

Ressourcenlabels

In einer ressourcenorientierten API wird das Ressourcenschema durch die API definiert. Damit der Client kleine Mengen einfacher Metadaten an die Ressourcen anhängen kann (z. B. zum Kennzeichnen einer VM-Ressource als Datenbankserver), sollte in APIs das Feld map<string, string> labels zur Ressourcendefinition hinzugefügt werden:

message Book {
  string name = 1;
  map<string, string> labels = 2;
}

Lang andauernde Vorgänge

Bei langwierigen API-Methoden kann eine "lang andauernde Vorgangsressource" an den Client zurückgegeben werden, mit der der Client den Fortschritt verfolgen und das Ergebnis abrufen kann. Der lang andauernde Vorgang definiert eine Standardschnittstelle für lang andauernde Vorgänge. Um Inkonsistenzen zu vermeiden, dürfen in den einzelnen APIs keine eigenen Schnittstellen für lang andauernde Vorgänge definiert werden.

Die Vorgangsressource muss direkt als Antwortnachricht zurückgegeben werden, und jede unmittelbare Konsequenz des Vorgangs sollte in der API wiedergegeben werden. Wenn Sie beispielsweise eine Ressource erstellen, sollte diese Ressource in den Methoden LIST und GET angezeigt werden, obwohl die Ressource anzeigen sollte, dass sie nicht zur Verwendung bereit ist. Nach Abschluss des Vorgangs sollte das Feld Operation.response die Nachricht enthalten, die bei einer kurzen Methode direkt zurückgegeben worden wäre.

Zu einem Voprgang können im Feld Operation.metadata Informationen über dessen Fortschritt angegeben werden. In einer API sollte für diese Metadaten auch dann eine Nachricht definiert werden, wenn das Feld metadata bei der anfänglichen Implementierung nicht ausgefüllt wird.

Listenpaginierung

Auflistbare Sammlungen sollten die Paginierung auch dann unterstützen, wenn der Umfang der Ergebnisse in der Regel klein ist.

Begründung: Wenn eine API die Paginierung nicht von Anfang an unterstützt, ist die spätere Unterstützung problematisch, da das Hinzufügen von Paginierungsfunktionen das Verhalten der API beeinträchtigt. Clients, die nicht wissen, dass die API jetzt die Paginierung verwendet, könnten fälschlicherweise davon ausgehen, dass sie ein vollständiges Ergebnis erhalten haben, obwohl ihnen tatsächlich nur die erste Seite gesendet wurde.

Um die Paginierung (Rückgabe von Listenergebnissen in Seiten) in einer List-Methode zu unterstützen, muss die API:

  • Definieren Sie das string-Feld page_token in der Anfragenachricht der List-Methode. Der Client fordert mit diesem Feld eine bestimmte Seite der Ergebnisliste an.
  • definieren Sie ein int32 Feld page_size in der List Anfragenachricht. Clients geben mit diesem Feld an, wie viele Ergebnisse maximal vom Server zurückgegeben werden sollen. Die Anzahl der maximal auf einer Seite zurückgegebenen Ergebnisse kann auf dem Server weiter begrenzt werden. Wenn page_size 0 ist, entscheidet der Server, wie viele Ergebnisse zurückgegeben werden.
  • Definieren Sie das string-Feld next_page_token in der Antwortnachricht der List-Methode. Dieses Feld enthält das Paginierungstoken zum Abrufen der nächsten Ergebnisseite. Wenn der Wert "" ist, bedeutet dies, dass keine weiteren Ergebnisse für die Anfrage vorliegen.

Um die nächste Ergebnisseite abzurufen, muss der Client den Wert von next_page_token der Antwort im nachfolgenden List-Methodenaufruf (im Feld page_token der Anfragenachricht) übergeben:

rpc ListBooks(ListBooksRequest) returns (ListBooksResponse);

message ListBooksRequest {
  string parent = 1;
  int32 page_size = 2;
  string page_token = 3;
}

message ListBooksResponse {
  repeated Book books = 1;
  string next_page_token = 2;
}

Wenn Clients zusätzlich zu einem Seitentoken Suchparameter übergeben, muss die Anfrage fehlschlagen, wenn die Suchparameter nicht mit dem Seitentoken übereinstimmen.

Der Inhalt des Seitentokens sollte ein URL-sicherer Base64-codierter Protocol Buffer sein. Auf diese Weise kann der Inhalt erweitert werden, ohne dass es zu Kompatibilitätsproblemen kommt. Wenn das Seitentoken möglicherweise vertrauliche Informationen enthält, sollten diese Informationen verschlüsselt werden. Dienste müssen die Manipulation von Seitentoken und damit eine unbeabsichtigte Offenlegung von Daten mit einer der folgenden Methoden verhindern:

  • Durch erneute Spezifizierung der Suchparameter bei Folgeanfragen.
  • Durch ausschließliche Referenzierung des serverseitigen Sitzungsstatus im Seitentoken
  • Durch Verschlüsselung und Signatur der Suchparameter im Seitentoken und erneute Validierung und Autorisierung der Parameter bei jedem Aufruf

Bei der Implementierung der Paginierung kann auch die Gesamtzahl der Elemente in einem int32-Feld namens total_size angegeben werden.

Untersammlungen auflisten

Gelegentlich muss ein Client in einer API List/Search über Untersammlungen hinweg zulassen. Die Library API verfügt beispielsweise über eine Sammlung von Ordnern, von denen jeder eine Büchersammlung enthält. Ein Client kann beispielsweise alle Ordner nach einem Buch durchsuchen. In solchen Fällen wird empfohlen, einen Standardwert List für die Untersammlung zu verwenden und die Platzhalter-Sammlungs-ID "-" für die übergeordnete Sammlung(en) anzugeben. Sie können für das Beispiel der Library API die folgende REST API-Anfrage verwenden:

GET https://library.googleapis.com/v1/shelves/-/books?filter=xxx

Eindeutige Ressource aus Untersammlung abrufen

Mitunter besitzt eine Ressource innerhalb einer Untersammlung eine in den übergeordneten Sammlungen eindeutige Kennzeichnung. In diesem Fall kann es sinnvoll sein, einem Get zu erlauben, diese Ressource abzurufen, ohne zu wissen, welche übergeordnete Sammlung sie enthält. In solchen Fällen wird empfohlen, einen Standard- Get für die Ressource zu verwenden und die Platzhalter-Sammlungs-ID "-" für alle übergeordneten Sammlungen anzugeben, in denen die Ressource eindeutig ist. Sie können in der Library API beispielsweise die folgende REST API-Anfrage verwenden, wenn das Buch unter allen Büchern in allen Ordnern eindeutig ist:

GET https://library.googleapis.com/v1/shelves/-/books/{id}

Der Ressourcenname in der Antwort auf diesen Aufruf muss den kanonischen Namen der Ressource verwenden, wobei die tatsächlichen übergeordneten Sammlungskennungen anstelle von "-" für jede übergeordnete Sammlung verwendet werden. Die obige Anfrage sollte beispielsweise eine Ressource mit dem Namen shelves/shelf713/books/book8141 und nicht shelves/-/books/book8141 zurückgeben.

Sortierreihenfolge

Wenn der Client mithilfe einer API-Methode die Sortierreihenfolge für Ergebnislisten festlegen kann, sollte die Anfragenachricht folgendes Feld enthalten:

string order_by = ...;

Der Stringwert sollte in der SQL-Syntax als eine durch Komma getrennte Liste von Feldern angegeben sein. Beispiel: "foo,bar" Standardmäßig werden die Einträge aufsteigend sortiert. Wenn Sie ein Feld absteigend sortieren möchten, sollte das Suffix " desc" an den Feldnamen angehängt werden. Beispiel: "foo desc,bar".

Überflüssige Leerzeichen in der Syntax werden nicht berücksichtigt. "foo,bar desc" und "  foo ,  bar  desc  " sind gleichwertig.

Anfragevalidierung

Wenn bei einer API-Methode Nebenwirkungen auftreten und eine Validierung der Anfrage ohne diese Nebenwirkungen erforderlich ist, sollte die Anfragenachricht folgendes Feld enthalten:

bool validate_only = ...;

Wenn dieses Feld auf true gesetzt ist, dürfen keine Nebeneffekte vom Server erzeugt werden. Außerdem ist nur eine implementierungsspezifische Validierung in Übereinstimmuung mit der vollständigen Anfrage zulässig.

Wenn die Validierung erfolgreich ist, muss google.rpc.Code.OK zurückgegeben werden, und eine vollständige Anfrage, die dieselbe Anfragenachricht verwendet, sollte nicht google.rpc.Code.INVALID_ARGUMENT zurückgeben. Beachten Sie, dass die Anfrage aufgrund anderer Fehler wie google.rpc.Code.ALREADY_EXISTS oder aufgrund von Race-Bedingungen möglicherweise immer noch fehlschlägt.

Anfrageduplikate

Für Netzwerk-APIs werden idempotente API-Methoden bevorzugt, da sie sich nach einem Netzwerkausfall sicher wiederholen lassen. Bei manchen API-Methoden, wie etwa dem Erstellen einer Ressource, lässt sich diese Idempotenz jedoch nicht so einfach herstellen. Außerdem sollten Duplikate vermieden werden. Die Anfragenachricht sollte für derartige Anwendungsfälle eine eindeutige ID wie etwa eine UUID enthalten. Der Server kann daran Duplikate erkennen und sicherstellen, dass die Anfrage nur einmal verarbeitet wird.

// A unique request ID for server to detect duplicated requests.
// This field **should** be named as `request_id`.
string request_id = ...;

Bei Erkennen einer doppelten Anfrage sollte vom Server die Antwort auf die bereits erfolgreiche Anfrage zurückgegeben werden, da der Client die vorherige Antwort vermutlich nicht empfangen hat.

ENUM-Standardwert

Jede Enum-Definition muss mit dem Wert 0 beginnen. Dieser Wert wird verwendet, wenn kein expliziter Enum-Wert angegeben ist. In APIs muss dokumentiert werden, wie der Wert 0 verarbeitet wird.

Der Enum-Wert 0 sollte als ENUM_TYPE_UNSPECIFIED bezeichnet werden. Wenn es ein allgemeines Standardverhalten gibt, wird es verwendet, wenn kein expliziter ENUM-Wert festgelegt ist. Falls es kein allgemeines Standardverhalten gibt, sollte der Wert 0 bei Verwendung mit dem Fehler INVALID_ARGUMENT abgelehnt werden.

enum Isolation {
  // Not specified.
  ISOLATION_UNSPECIFIED = 0;
  // Reads from a snapshot. Collisions occur if all reads and writes cannot be
  // logically serialized with concurrent transactions.
  SERIALIZABLE = 1;
  // Reads from a snapshot. Collisions occur if concurrent transactions write
  // to the same rows.
  SNAPSHOT = 2;
  ...
}

// When unspecified, the server will use an isolation level of SNAPSHOT or
// better.
Isolation level = 1;

Sie können für den Wert 0 einen idiomatischen Namen verwenden. Beispielsweise ist google.rpc.Code.OK die idiomatische Methode, um das Fehlen eines Fehlercodes anzugeben. Im Kontext des ENUM-Typs entspricht dabei OK semantisch UNSPECIFIED.

Wenn ein inhärent zweckmäßiger und sicherer Standardwert vorhanden ist, kann dieser Wert für den Wert "0" verwendet werden. Zum Beispiel ist BASIC der Wert "0" in der Enum-Ressourcenansicht.

Grammatiksyntax

In API-Designs müssen für bestimmte Datenformate oft einfache Grammatiken definiert werden, etwa in Form von akzeptablen Texteingaben. Um eine konsistente Entwicklungsumgebung auf verschiedenen APIs zu schaffen und die Lernkurve zu reduzieren, müssen API-Designer derartige Grammatiken mit der folgenden Variante der EBNF-Syntax (Extended Backus-Naur Form) definieren:

Production  = name "=" [ Expression ] ";" ;
Expression  = Alternative { "|" Alternative } ;
Alternative = Term { Term } ;
Term        = name | TOKEN | Group | Option | Repetition ;
Group       = "(" Expression ")" ;
Option      = "[" Expression "]" ;
Repetition  = "{" Expression "}" ;

Ganzzahlentypen

In API-Designs sollten unsignierte Ganzzahltypen wie uint32 und fixed32 nicht verwendet werden, da sie von einigen wichtigen Programmiersprachen und Systemen wie Java, JavaScript und OpenAPI nicht gut unterstützt werden. Und es ist wahrscheinlicher, dass sie Überlauffehler verursachen. Ein weiteres Problem besteht darin, dass in unterschiedlichen APIs für dieselbe Sache häufig unterschiedliche vorzeichenbehaftete und vorzeichenlose Typen verwendet werden.

In Fällen, in denen Ganzzahltypen mit Vorzeichen etwa für Größenangaben oder Zeitüberschreitungen verwendet werden, bei denen negative Werte keinen Sinn ergeben, kann mit dem Wert -1 (und nur mit-1) eine spezielle Bedeutung wie etwa das Dateiende (End of File, EOF), eine unendliche Zeitüberschreitung, ein unbegrenztes Kontingent oder ein unbekanntes Alter angegeben werden. Um Verwirrungen zu vermeiden, müssen derartige Nutzungen klar dokumentiert werden. API-Ersteller sollten auch das Verhalten des impliziten Standardwerts 0 dokumentieren, wenn dies nicht offensichtlich ist.

Teilantwort

Mitunter benötigt ein API-Client nur eine bestimmte Teilmenge der Daten in der Antwortnachricht. Manche API-Plattformen bieten daher eine native Unterstützung für Teilantworten. Die Google API Platform bietet zu diesem Zweck eine Antwortfeldmaske.

Für jeden REST API-Aufruf gibt es den impliziten Systemabfrageparameter $fields, der die JSON-Darstellung eines google.protobuf.FieldMask-Werts darstellt. Die Antwortnachricht wird vor der Rücksendung an den Client nach $fields gefiltert. Diese Logik wird auf der API Platform automatisch für alle API-Methoden angewendet.

GET https://library.googleapis.com/v1/shelves?$fields=shelves.name
GET https://library.googleapis.com/v1/shelves/123?$fields=name

Ressourcenansicht

Um den Netzwerkverkehr zu reduzieren, kann es nützlich sein, den Client bestimmen zu lassen, welche Teile der Ressource in Serverantworten zurückgegeben werden sollen. Auf diese Weise wird anstelle der vollständigen Ressourcendarstellung nur eine Ansicht der Ressource zurückgegeben. Um Ressourcenansichten in einer API zu unterstützen, wird der Methodenanfrage ein Parameter hinzugefügt, der es dem Client erlaubt, festzulegen, welche Ansicht der Ressource in der Antwort zurückgegeben werden soll.

Der Parameter:

  • sollte vom Typ enum sein
  • muss den Namen view haben.

Jeder Wert der Enumeration definiert, welche Teile der Ressource bzw. welche Felder in der Antwort des Servers zurückgegeben werden. Genau das, was für jeden view-Wert zurückgegeben wird, ist implementierungsdefiniert und sollte in der API-Dokumentation angegeben werden.

package google.example.library.v1;

service Library {
  rpc ListBooks(ListBooksRequest) returns (ListBooksResponse) {
    option (google.api.http) = {
      get: "/v1/{name=shelves/*}/books"
    }
  };
}

enum BookView {
  // Not specified, equivalent to BASIC.
  BOOK_VIEW_UNSPECIFIED = 0;

  // Server responses only include author, title, ISBN and unique book ID.
  // The default value.
  BASIC = 1;

  // Full representation of the book is returned in server responses,
  // including contents of the book.
  FULL = 2;
}

message ListBooksRequest {
  string name = 1;

  // Specifies which parts of the book resource should be returned
  // in the response.
  BookView view = 2;
}

Dieses Konstrukt wird URLs wie folgt zugeordnet:

GET https://library.googleapis.com/v1/shelves/shelf1/books?view=BASIC

Weitere Informationen zum Definieren von Methoden, Anfragen, und Antworten finden Sie im Abschnitt "Standardmethoden" in dieser Designanleitung.

ETags

Ein ETag ist eine opake Kennzeichnung, mit der ein Client bedingte Anfragen stellen kann. Zur Unterstützung von ETags sollte eine API das Stringfeld etag in die Ressourcendefinition aufnehmen und ihre Semantik muss der allgemeinen Verwendung von ETag entsprechen. Normalerweise enthält etag den vom Server berechneten Fingerabdruck der Ressource. Weitere Informationen finden Sie auf Wikipedia und unter RFC 7232.

ETags können stark oder schwach validiert werden. Schwach validierten ETags ist das Präfix W/ vorangestellt. Eine starke Validierung bedeutet in diesem Zusammenhang, dass zwei Ressourcen mit demselben ETag Byte für Byte identische Inhalte und identische Zusatzfelder (d. h. "Content-Type") enthalten. Stark validierte ETags ermöglichen somit das Zwischenspeichern von Teilantworten, die später zusammengesetzt werden können.

Umgekehrt werden Ressourcen mit demselben schwach validierten ETag-Wert semantisch gleichwertig dargestellt, sind aber nicht zwingend Byte für Byte identisch. Sie eignen sich daher nicht zum Zwischenspeichern von Antworten auf Anfragen zu Bytebereichen.

Beispiel:

// This is a strong ETag, including the quotes.
"1a2f3e4d5b6c7c"
// This is a weak ETag, including the prefix and quotes.
W/"1a2b3c4d5ef"

Es ist wichtig zu wissen, dass die Anführungszeichen tatsächlich Teil des ETag-Werts sind und gemäß RFC 7232 vorhanden sein müssen. Bei JSON-Darstellungen von ETags werden daher vor Anführungszeichen Escapezeichen eingefügt. In JSON-Ressourcentexten würden ETags beispielsweise wie folgt dargestellt:

// Strong
{ "etag": "\"1a2f3e4d5b6c7c\"", "name": "...", ... }
// Weak
{ "etag": "W/\"1a2b3c4d5ef\"", "name": "...", ... }

Zusammenfassung der in ETags zulässigen Zeichen:

  • Nur druckbare ASCII-Zeichen
    • Gemäß RFC 7232 zulässige Nicht-ASCII-Zeichen, diese sind jedoch weniger entwicklerfreundlich
  • Keine Leerzeichen
  • Doppelte Anführungszeichen ausschließlich an den oben gezeigten Positionen
  • Umgekehrte Schrägstriche sind gemäß RFC 7232 zu vermeiden, um Verwechslungen mit Escapezeichen zu verhindern

Ausgabefelder

In APIs wird mitunter zwischen den vom Client als Eingaben bereitgestellten Feldern und den vom Server als Ausgabe für eine bestimmte Ressource zurückgegebenen Feldern unterschieden. Bei reinen Ausgabefeldern wird das Feldattribut annotiert.

Wenn nur Ausgabefelder in der Anfrage festgelegt oder in google.protobuf.FieldMask enthalten sind, muss der Server die Anfrage ohne Fehler akzeptieren. Der Server muss das Vorhandensein von reinen Ausgabefeldern und jeglichen Hinweis darauf ignorieren. Der Grund für diese Empfehlung liegt darin, dass Clients vom Server zurückgegebene Ressourcen häufig als weitere Anfrageeingabe wiederverwenden, z. B. wird ein abgerufenes Book später in einer UPDATE-Methode wiederverwendet. Die Validierung reiner Ausgabefelder bedeutet für den Client zusätzlichen Aufwand beim Löschen dieser Felder.

import "google/api/field_behavior.proto";

message Book {
  string name = 1;
  Timestamp create_time = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
}

Singleton-Ressourcen

Eine Singleton-Ressource kann verwendet werden, wenn die übergeordnete Ressource (oder die API, falls keine übergeordnete Ressource vorhanden ist) nur eine einzige Instanz einer Ressource enthält.

Die Standardmethoden Create und Delete müssen für Singleton-Ressourcen weggelassen werden. Das Singleton wird implizit erstellt oder gelöscht, wenn sein übergeordnetes Element erstellt oder gelöscht wird, und ist implizit vorhanden, wenn es kein übergeordnetes Element hat. Auf die Ressource muss mit den Standardmethoden Get und Update sowie mit allen benutzerdefinierten Methoden zugegriffen werden, die für Ihren Anwendungsfall geeignet sind.

Beispielsweise könnte eine API mit User-Ressourcen die Einstellungen pro Nutzer als Settings-Singleton verfügbar machen.

rpc GetSettings(GetSettingsRequest) returns (Settings) {
  option (google.api.http) = {
    get: "/v1/{name=users/*/settings}"
  };
}

rpc UpdateSettings(UpdateSettingsRequest) returns (Settings) {
  option (google.api.http) = {
    patch: "/v1/{settings.name=users/*/settings}"
    body: "settings"
  };
}

[...]

message Settings {
  string name = 1;
  // Settings fields omitted.
}

message GetSettingsRequest {
  string name = 1;
}

message UpdateSettingsRequest {
  Settings settings = 1;
  // Field mask to support partial updates.
  FieldMask update_mask = 2;
}

Halbgeschlossenes Streaming

Bei APIs für bidirektionales oder Client-Streaming sollte der Server sich wie durch das RPC-System vorgesehen auf das vom Client initiierte halbgeschlossene Verfahren verlassen, um den clientseitigen Stream durchzuführen. Es ist nicht notwendig, eine explizite Abschlussnachricht festzulegen.

Alle Informationen, die der Client vor dem Schließen in eine Richtung zu senden hat, müssen als Teil der Anfragenachricht festgelegt werden.

Auf Domains beschränkte Namen

Ein auf Domains beschränkter Name ist ein Entitätsname, dem ein DNS-Domainname vorangestellt wird, um Namenskollisionen zu vermeiden. Es ist ein nützliches Entwurfsmuster, wenn verschiedene Organisationen ihre Entitätsnamen dezentral definieren. Die Syntax ähnelt einem URI ohne Schema.

Auf Domains beschränkte Namen werden häufig von Google- und Kubernetes-APIs verwendet, beispielsweise:

  • Die Darstellung von Protobuf-Typ Any: type.googleapis.com/google.protobuf.Any
  • Stackdriver-Messwerttypen: compute.googleapis.com/instance/cpu/utilization
  • Labelschlüssel: cloud.googleapis.com/location
  • Kubernetes API-Versionen: networking.k8s.io/v1
  • Das Feld kind in der OpenAPI-Erweiterung x-kubernetes-group-version-kind.

Bool gegen Enum und String

Beim Entwerfen einer API-Methode wird häufig eine Reihe von Auswahlmöglichkeiten für eine bestimmte Funktion angegeben, z. B. das Aktivieren von Tracing oder Deaktivieren von Caching. Häufig wird dies durch die Einführung eines Anfragefelds vom Typ bool, enum oder string erreicht. Es ist nicht immer klar, welcher Typ für einen bestimmten Anwendungsfall verwendet wird. Wir empfehlen folgende Auswahl:

  • Verwenden Sie den Typ bool, wenn Sie ein festes Design haben und die Funktionalität absichtlich nicht erweitern möchten. Beispiel: bool enable_tracing oder bool enable_pretty_print.

  • Verwenden Sie einen enum-Typ, wenn Sie ein flexibles Design wünschen, aber nicht davon ausgehen, dass sich das Design häufig ändert. Als Faustregel gilt, dass die Enum-Definition nur einmal pro Jahr geändert wird. Beispiel: enum TlsVersion oder enum HttpVersion.

  • Verwenden Sie den Typ string, wenn es sich um ein offenes Design handelt oder das Design häufig durch einen externen Standard geändert werden kann. Die unterstützten Werte müssen klar dokumentiert sein. Beispiel:

Datenaufbewahrung

Beim Entwerfen eines API-Dienstes ist die Datenaufbewahrung ein kritischer Aspekt der Dienstzuverlässigkeit. Nutzerdaten werden häufig versehentlich durch Softwarefehler oder menschliche Fehler gelöscht. Ohne die Datenaufbewahrung und die entsprechende Funktion zum Wiederherstellen kann ein einfacher Fehler zu schwerwiegenden Folgen für das Unternehmen führen.

Im Allgemeinen empfehlen wir die folgende Richtlinie zur Datenaufbewahrung für API-Dienste:

  • Bei Nutzermetadaten, Nutzereinstellungen und anderen wichtigen Informationen sollte die Datenaufbewahrung 30 Tage dauern. Zum Beispiel Monitoring von Messwerten, Projektmetadaten und Dienstdefinitionen.

  • Bei umfangreichen Nutzerinhalten sollte die Datenaufbewahrung 7 Tage dauern. Zum Beispiel binäre Blobs und Datenbanktabellen.

  • Bei temporärem oder teurem Speicher sollte die Datenaufbewahrung nach Möglichkeit einen Tag dauern. Beispiel: Memcache-Instanzen und Redis-Server.

Während des Aufbewahrungszeitraums können die Daten ohne Datenverlust wiederhergestellt werden. Wenn es teuer ist, die Datenaufbewahrung kostenlos anzubieten, kann ein Dienst die Datenaufbewahrung als kostenpflichtige Option anbieten.

Große Nutzlasten

Netzwerk-APIs benötigen oft mehrere Netzwerkebenen für ihren Datenpfad. Bei den meisten Netzwerkebenen gibt es feste Grenzen für die Anfrage- und Antwortgröße. 32 MB ist in vielen Systemen ein gängiges Limit.

Wenn Sie eine API-Methode entwerfen, die Nutzlasten über 10 MB verarbeitet, sollten wir die richtige Strategie für Nutzerfreundlichkeit und zukünftiges Wachstum sorgfältig auswählen. Für Google APIs empfehlen wir, Streaming- oder Medienupload-/Downloadvorgänge für große Nutzlasten zu verwenden. Beim Streaming verarbeitet der Server die großen Daten synchron, wie die Cloud Spanner API. Bei Medien werden die großen Daten durch ein großes Speichersystem wie Google Cloud Storage geleitet und der Server kann die Daten asynchron verarbeiten, beispielsweise die Google Drive API.

Optionale einfache Felder

Protocol Buffers Version 3 (proto3) unterstützt einfache Felder vom Typ optional, die semantisch nullable-Typen in vielen Programmiersprachen entsprechen. Sie können verwendet werden, um leere Werte von nicht festgelegten Werten zu unterscheiden.

In der Praxis ist es für Entwickler schwierig, optionale Felder richtig zu verarbeiten. Die meisten JSON-HTTP-Clientbibliotheken, einschließlich Google API-Clientbibliotheken, können nicht von proto3 int32, google.protobuf.Int32Value und optional int32 unterscheiden. Wenn ein alternatives Design gleichermaßen klar ist und keine optionale Primitive erfordert, bevorzugen Sie dies. Wenn Sie die Option nicht optional verwenden, würde dies zu Komplexität oder Mehrdeutigkeit führen, dann verwenden Sie einfache Felder. Wrapper-Typen dürfen nicht weiter verwendet werden. Der Einfachheit halber sollten API-Designer einfache primitive Typen wie int32 verwenden.