Open-Source-Projekt
skydoves/sandwich avatar
skydoves/sandwich

Sandwich: eine sealed API-Response-Bibliothek für Kotlin-Netzwerkschichten

Projektüberblick: Sandwich ist eine anpassungsfähige und leichte, versiegelte API-Bibliothek, die für die Verarbeitung von API-Antworten und Ausnahmen in Kotlin für Retrofit, Ktor und Kotlin Multiplatform entwickelt wurde.

1.773 Sterne114 ForksKotlinApache-2.0

Auf einen Blick

Was ist das?
Sandwich modelliert Retrofit- und Ktor-Antworten als sealed ApiResponse-Werte mit Erfolgs-, Fehler- und Ausnahme-Zweigen sowie Operatoren für Mapping, Wiederherstellung und Wiederholung.
Für wen ist es gedacht?
Sandwich bündelt die Antwortverarbeitung um drei sealed Typen, Erweiterungs-Scopes je Zweig, coroutine-fähige Operatoren und einen globalen Operator-Hook, alles unter Apache-2.0 mit gebündelten R8-Regeln.
Darf ich es kommerziell nutzen?
Ja. Apache-2.0 ist eine freizügige Lizenz: Sie dürfen darauf aufbauende Software nutzen, verändern und verkaufen, solange Sie die Urheberrechts- und Lizenzhinweise beibehalten.
Wird es noch gepflegt?
Ja. Die letzten Commits kamen vor 2 Tagen.
In welcher Sprache ist es geschrieben?
Hauptsächlich Kotlin, laut der Sprachstatistik von GitHub.

Die Antworten beruhen auf den GitHub-Daten des Projekts (zuletzt abgeglichen am 18. September 2026) und auf unserer Analyse. Sie sind keine Rechtsberatung.

TIEFGEHENDE OPEN-SOURCE-ANALYSE

Das Problem, das Sandwich adressiert

Sandwich wird in seiner README als anpassungsfähige und leichtgewichtige sealed API-Bibliothek zur Behandlung von API-Antworten und Ausnahmen in Kotlin für Retrofit, Ktor und Kotlin Multiplatform beschrieben. Das Projekt wurde entwickelt, um die Erstellung standardisierter Schnittstellen zur Modellierung von Antworten von Retrofit, Ktor und anderen Quellen zu vereinfachen, sodass Body-Daten, Fehler und Ausnahmefälle mit funktionalen Operatoren in einer mehrschichtigen Architektur behandelt werden können. Die README sagt, dass dadurch die Notwendigkeit entfällt, Wrapper-Klassen wie Resource oder Result zu schreiben, und sich Anwendungscode auf die Geschäftslogik konzentrieren kann. Sie listet außerdem globale Antwortverarbeitung, Mapper, Operator und ApiResponse mit Coroutines als Kernfunktionen auf. Im konkreten Projekt sollte man dabei die genannten Eingabedateien, Konfigurationswerte und Ausgaben gemeinsam betrachten. So lässt sich erkennen, ob das beschriebene Verhalten unter den eigenen Bedingungen eintritt und welche Grenzen die README offenlässt. Im konkreten Projekt sollte man dabei die genannten Eingabedateien, Konfigurationswerte und Ausgaben gemeinsam betrachten. So lässt sich erkennen, ob das beschriebene Verhalten unter den eigenen Bedingungen eintritt und welche Grenzen die README offenlässt.

ApiResponse und seine drei Ergebnis-Typen

Die zentrale Abstraktion ist ApiResponse, eine Schnittstelle, die die README als eine Möglichkeit definiert, konsistente Antworten aus API- oder I/O-Aufrufen zu erzeugen, einschließlich Netzwerk, Datenbank oder anderen Quellen. Sie umfasst drei unterschiedliche Typen. ApiResponse.Success repräsentiert eine erfolgreiche Antwort und kann einen Datenwert plus ein optionales Tag tragen, um die Herkunft zu unterscheiden oder die Nachbearbeitung zu erleichtern. ApiResponse.Failure.Exception signalisiert fehlgeschlagene Aufgaben, die durch unerwartete Ausnahmen während der Anfrageerstellung oder Antwortverarbeitung abgefangen wurden, etwa einen Netzwerkverbindungsfehler. ApiResponse.Failure.Error bezeichnet fehlgeschlagene Anfragen, typischerweise durch fehlerhafte Anfragen oder interne Serverfehler, und kann eine Fehler-Payload mit detaillierten Informationen enthalten. Die README zeigt Konstruktoren für jeden Typ und demonstriert benutzerdefinierte Fehlertypen, die Failure.Error oder Failure.Exception erweitern, etwa LimitedRequest und WrongArgument. Im konkreten Projekt sollte man dabei die genannten Eingabedateien, Konfigurationswerte und Ausgaben gemeinsam betrachten. So lässt sich erkennen, ob das beschriebene Verhalten unter den eigenen Bedingungen eintritt und welche Grenzen die README offenlässt. Im konkreten Projekt sollte man dabei die genannten Eingabedateien, Konfigurationswerte und Ausgaben gemeinsam betrachten. So lässt sich erkennen, ob das beschriebene Verhalten unter den eigenen Bedingungen eintritt und welche Grenzen die README offenlässt.

Antworten erzeugen und die Erweiterungs-Scopes

Die README dokumentiert mehrere Möglichkeiten, eine ApiResponse zu erzeugen. ApiResponse.of und apiResponseOf umhüllen ein Anfrage-Lambda, während ApiResponse.suspendOf und suspendApiResponseOf suspendierte Funktionen im Lambda akzeptieren. Eine Anmerkung in der README besagt, dass Sie, wenn Sie den globalen Operator oder den globalen ApiResponse-Mapper verwenden möchten, Antworten mit of oder suspendOf erzeugen sollten, damit diese globalen Funktionen angewendet werden. Sobald Sie eine Antwort haben, laufen die Scopes onSuccess, onError, onException und onFailure nur, wenn die Antwort dem jeweiligen Typ entspricht. onFailure deckt sowohl den Fehler- als auch den Ausnahme-Zweig ab, und die README zeigt, wie jeder Scope auf die relevanten Daten, Meldungen, Payloads oder Ausnahmen zugreift. Der Fehler-Scope stellt messageOrNull und payload bereit; der Ausnahme-Scope stellt messageOrNull und die Ausnahme bereit. Im konkreten Projekt sollte man dabei die genannten Eingabedateien, Konfigurationswerte und Ausgaben gemeinsam betrachten. So lässt sich erkennen, ob das beschriebene Verhalten unter den eigenen Bedingungen eintritt und welche Grenzen die README offenlässt. Im konkreten Projekt sollte man dabei die genannten Eingabedateien, Konfigurationswerte und Ausgaben gemeinsam betrachten. So lässt sich erkennen, ob das beschriebene Verhalten unter den eigenen Bedingungen eintritt und welche Grenzen die README offenlässt.

Coroutines, Flow und funktionale Operatoren

Die coroutine-fähigen Varianten suspendOnSuccess, suspendOnError, suspendOnException und suspendOnFailure erlauben es, suspendierte Funktionen wie einen DAO-Insert innerhalb des Scopes aufzurufen. Die toFlow-Erweiterung wandelt eine ApiResponse in einen Coroutines-Flow um, mit einer Variante, die ein Transformations-Lambda für die Daten akzeptiert. Zu den in der README dokumentierten funktionalen Erweiterungen gehören Wiederherstellung (recover, recoverWith), Validierung (validate, requireNotNull), Filtern (filter, filterNot), Kombinieren (zip, zip3) und Beobachten (peek, peekSuccess, peekFailure, peekError, peekException). Die README sagt, dass jede Erweiterung ein suspendiertes Pendant wie suspendRecover und suspendValidate hat. Ein ausgeführtes Beispiel verkettet validate, filter, recover und peekSuccess auf einer Antwort. Im konkreten Projekt sollte man dabei die genannten Eingabedateien, Konfigurationswerte und Ausgaben gemeinsam betrachten. So lässt sich erkennen, ob das beschriebene Verhalten unter den eigenen Bedingungen eintritt und welche Grenzen die README offenlässt. Im konkreten Projekt sollte man dabei die genannten Eingabedateien, Konfigurationswerte und Ausgaben gemeinsam betrachten. So lässt sich erkennen, ob das beschriebene Verhalten unter den eigenen Bedingungen eintritt und welche Grenzen die README offenlässt.

Wiederholung, sequenzielle Aufrufe und Datenabruf

Für Wiederholungslogik dokumentiert die README ein RetryPolicy-Interface mit den Methoden shouldRetry und retryTimeout sowie eine runAndRetry-Erweiterung, die eine Aufgabe unter dieser Richtlinie ausführt; die Beispielrichtlinie wiederholt bis zu drei Versuche mit einem Timeout von 3000 ms. Für abhängige Anfragen verketten then und suspendThen Aufgaben, sodass jeder Schritt das Ergebnis des vorherigen erhält; die README verkettet getUserToken, getUserDetails und queryPosters in dieser Reihenfolge. Die Abruf-Helfer getOrNull, getOrElse und getOrThrow geben bei Erfolg die gekapselten Daten zurück; bei Fehlern liefern sie jeweils null, einen Standardwert oder werfen die gekapselte Throwable. Das Beispiel in der README verwendet getOrThrow in einem try/catch und gibt den Stack-Trace aus. Im konkreten Projekt sollte man dabei die genannten Eingabedateien, Konfigurationswerte und Ausgaben gemeinsam betrachten. So lässt sich erkennen, ob das beschriebene Verhalten unter den eigenen Bedingungen eintritt und welche Grenzen die README offenlässt. Im konkreten Projekt sollte man dabei die genannten Eingabedateien, Konfigurationswerte und Ausgaben gemeinsam betrachten. So lässt sich erkennen, ob das beschriebene Verhalten unter den eigenen Bedingungen eintritt und welche Grenzen die README offenlässt.

Operatoren und globale Antwortverarbeitung

ApiResponseOperator, verwendet mit der operator-Erweiterung, definiert wiederverwendbare Prozessoren für Erfolgs-, Fehler- und Ausnahmefälle, sodass eine konsistente Verarbeitungssequenz über mehrere API-Anfragen hinweg geteilt werden kann. Das Beispiel CommonResponseOperator protokolliert in onError und ruft map auf, um Fehler in ein benutzerdefiniertes Modell zu überführen, und protokolliert in onException die Meldung. ApiResponseSuspendOperator und suspendOperator unterstützen suspendierte Lambdas, etwa um aus dem Erfolgs-Scope in einen Flow zu emittieren. Der globale Operator registriert Instanzen in SandwichInitializer, sodass sie auf alle ApiResponse-Instanzen angewendet werden. Die README zeigt einen TokenRefreshGlobalOperator, der Header und Statuscodes 401 und 403 prüft, das Token aktualisiert und mit Hilt und App Startup verdrahtet ist. Eine separate Anmerkung sagt, dass suspendierte Mapper und Operatoren, die bei Ktor und Ktorfit üblich sind, ApiResponse.suspendOf benötigen, damit sie ordnungsgemäß abgewartet werden. Im konkreten Projekt sollte man dabei die genannten Eingabedateien, Konfigurationswerte und Ausgaben gemeinsam betrachten. So lässt sich erkennen, ob das beschriebene Verhalten unter den eigenen Bedingungen eintritt und welche Grenzen die README offenlässt. Im konkreten Projekt sollte man dabei die genannten Eingabedateien, Konfigurationswerte und Ausgaben gemeinsam betrachten. So lässt sich erkennen, ob das beschriebene Verhalten unter den eigenen Bedingungen eintritt und welche Grenzen die README offenlässt.

Verbreitung, Integration und Lizenz

Die README berichtet von über 1.200.000 Downloads in Android- und Backend-Projekten. Das Gradle-Setup verwendet eine BOM, com.github.skydoves:sandwich-bom:2.4.0, plus sandwich für den Kern, sandwich-retrofit für Android, sandwich-ktor, sandwich-ktor-serialization und sandwich-ktorfit für Kotlin Multiplatform sowie sandwich-test für Tests. R8- und ProGuard-Regeln sind in das JAR gebündelt. Zu den aufgeführten Anwendungsfällen gehören Pokedex, ChatGPT Android, DisneyMotions, MarvelHeroes, Neko und TheMovies2. Die Repository-Metadaten zum Zeitpunkt der Erstellung zeigen 1.766 Sterne, 113 Forks und 4 offene Issues, wobei das Repository nicht archiviert ist. Das Projekt ist unter Apache-2.0 lizenziert, Urheberrecht 2020 skydoves (Jaewoong Eum). Die Lizenz gewährt unbefristete, weltweite, nicht-exklusive, gebührenfreie Rechte zur Vervielfältigung, Erstellung abgeleiteter Werke und Verbreitung und erklärt, dass keine Gewährleistung besteht. Die README sagt nichts über Support-Erwartungen oder den Wartungsrhythmus aus. Im konkreten Projekt sollte man dabei die genannten Eingabedateien, Konfigurationswerte und Ausgaben gemeinsam betrachten. So lässt sich erkennen, ob das beschriebene Verhalten unter den eigenen Bedingungen eintritt und welche Grenzen die README offenlässt. Im konkreten Projekt sollte man dabei die genannten Eingabedateien, Konfigurationswerte und Ausgaben gemeinsam betrachten. So lässt sich erkennen, ob das beschriebene Verhalten unter den eigenen Bedingungen eintritt und welche Grenzen die README offenlässt.

Redaktionelles Fazit

Sandwich bündelt die Antwortverarbeitung um drei sealed Typen, Erweiterungs-Scopes je Zweig, coroutine-fähige Operatoren und einen globalen Operator-Hook, alles unter Apache-2.0 mit gebündelten R8-Regeln.

Offizielle Quellen

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Community-Notizen

Community-Notizen