2025

Better Tonnenticker API

Ein schneller, cachender Proxy vor dem kommunalen Abfallkalender: typisierte Daten, Suche nach Namen und eine eigene iOS-App, die an die Abholtermine erinnert.

Start API
Dezember 2025
Start iOS-App
September 2026

Überblick

Die API ersetzt eine bestehende Schnittstelle einer kommunalen Abfallentsorgung, die nur auf Deutsch antwortet, spürbar langsam ist, kein Caching betreibt, keine Suche nach Namen erlaubt (nur nach IDs) und ein unübersichtliches Entitätsmodell hat — Termine etwa enthalten die Abfallart nicht direkt, sondern nur eine Fraktions-ID, die erst gegen die Liste aller Abfallarten abgeglichen werden muss.

Better Tonnenticker API fasst diese Daten neu und stellt sie in zwei Ausprägungen bereit: eine direkte Durchleitung der Rohdaten und eine aufbereitete, typisierte Sicht mit eigenen Modellen für Orte, Bezirke, Abfallarten und Termine, inklusive Suche nach Namen. Die API ist über OpenAPI/Swagger UI dokumentiert. Es gibt keine eigene Datenbank — der einzige Zustand ist der In-Memory-Cache.

Als Client dazu entstand die iOS-App Better Tonnenticker: Ort und Bezirk einmal auswählen, dann zeigt sie die nächsten Abholtermine und erinnert am Vorabend daran, die Tonne rauszustellen.

Inspiriert wurde das Projekt durch tonnenticker-spider.

Meine Rolle

Konzeption und Umsetzung der gesamten API: die beiden Controller-Ebenen für Rohdaten und typisierte Modelle, die Anbindung an den kommunalen Abfallkalender, das mehrschichtige Caching mit datensatzspezifischen Ablaufzeiten, die Absicherung per API-Key, Containerisierung und Build-Pipelines — und dazu die iOS-App von der Umsetzung des Designs aus Claude Design bis zum Build über Xcode Cloud.

Caching

Da sich viele Kommunaldaten selten ändern, etwa die Liste der Städte und Gemeinden, aber bei jeder Anfrage neu abgerufen werden könnten, cacht die API konsequent auf zwei Ebenen mit Caffeine, jeweils rein im Arbeitsspeicher einer einzelnen Instanz:

  • Auf Service-Ebene cacht der TonnenTickerService die Rohdaten des kommunalen Abfallkalenders — mit einer Ablaufzeit passend zur Änderungshäufigkeit des jeweiligen Datensatzes: Abholtermine 1 Tag, Bezirke 14 Tage, Abfallarten 7 Tage, Orte 24 Tage.
  • Auf Controller-Ebene cacht der WasteController zusätzlich die fertig aufbereiteten, typisierten Ergebnisse mit denselben Ablaufzeiten — ein Treffer hier spart also auch das erneute Mapping.
  • Ein CachePreHeater füllt Abfallarten und Orte direkt beim Anwendungsstart vor, damit die erste echte Anfrage nicht auf einen leeren Cache trifft.
  • Es gibt keine proaktive Aktualisierung im Hintergrund: abgelaufene Einträge werden erst bei der nächsten Anfrage neu geladen. Der Cache ist außerdem rein lokal — er geht bei einem Neustart verloren und würde bei mehreren Instanzen nicht geteilt.

Technische Architektur

Highlights

  • Zweistufige API: Rohdaten-Durchleitung (DirectController) und typisiertes, aufbereitetes Modell (WasteController).
  • Mehrschichtiges Caffeine-Caching mit datensatzspezifischen Ablaufzeiten von 1 bis 24 Tagen statt einer pauschalen Cache-Dauer.
  • Cache-Preheating beim Start, damit die ersten Anfragen nicht auf einen kalten Cache treffen.
    • Problem: Nach jedem Neustart war der Cache leer — die erste Anfrage danach hätte die volle Latenz der langsamen externen API zu spüren bekommen.
    • Lösung: Ein CachePreHeater lädt Abfallarten und Orte direkt beim Start in den Cache, bevor die erste echte Anfrage eintrifft.
    • Per Flag (cache.preheat.enabled) gezielt abschaltbar, etwa für die lokale Entwicklung ohne Netzwerkzugriff.
  • Absicherung per API-Key: Ein eigener Filter in Spring Security prüft den Header X-API-Key, ohne Sessions; ohne gültigen Key antwortet die API mit 401. Fehlt der Key in der Konfiguration, startet die Anwendung gar nicht erst.
  • Getrennte Spring-Profile: Swagger UI und die OpenAPI-Beschreibung sind nur im lokalen Profil aktiv, in Produktion abgeschaltet. Von den Actuator-Endpunkten ist nur der Health-Check freigegeben, und der ohne Details.
  • Containerisiert über ein mehrstufiges Docker-Build (Maven, dann ein schlankes Alpine-Image mit Java 25); je eine Azure-DevOps-Pipeline für Dev und Prod baut das Image und legt es in einer eigenen Container-Registry ab.

Mögliche Weiterentwicklung

  • Cache auf Redis umstellen: Der Cache läuft aktuell rein im Arbeitsspeicher und muss nach jedem Neustart neu aufgebaut werden. Mit einem RedisCacheManagerstatt Caffeine (bei gleichen, per-Cache konfigurierbaren Ablaufzeiten) würde der Cache Neustarts überstehen und ließe sich bei mehreren Instanzen sogar teilen.

Zuletzt aktualisiert: