API‑ontwerp voor mobiele batterijduur: vermindering van veelvuldige API‑aanroepen
API‑ontwerp voor mobiele batterijduur: leer batchen, cachingheaders en payloads verkleinen om radio‑wakeups te verminderen, schermen te versnellen en het verbruik te verlagen.

Waarom veelvuldige ("chatty") API's de batterij op mobiel leegtrekken
Een "chatty" API laat een app veel kleine requests afvuren om één scherm op te bouwen. Op papier lijken die requests goedkoop, maar op een telefoon tellen ze snel op.
De grootste batterijimpact komt vaak van de netwerkradio. Cellular‑ en Wi‑Fi‑chips schakelen naar energie-intensievere staten om data te verzenden en te ontvangen. Als een app veel verzoeken dicht op elkaar afvuurt, blijft de radio steeds wakker en actief langer. Zelfs als elke response klein is, kosten herhaalde wakeups echte energie.
Er is ook CPU‑werk. Elk verzoek betekent headers opbouwen, TLS‑werk, JSON parsen, caches bijwerken en app‑code uitvoeren om resultaten te mergen. Als verbindingen wegvallen, moet die setup zich herhalen.
Chattiness maakt de UI ook trager aanvoelen. In plaats van één voorspelbare laadactie wacht het scherm op een keten van calls. Je krijgt langere spinners, gedeeltelijke renders die verspringen en meer timeouts bij zwak netwerk. Achtergrondverversing wordt op dezelfde manier erger: meer retries, meer wakeups en meer batterijverbruik.
Een praktische manier om over API‑ontwerp voor mobiele batterijduur na te denken is simpel: toon dezelfde UI met minder rondreizen, minder bytes en minder achtergrondwerk.
Je kunt succes volgen met een paar concrete verbeteringen:
- Minder API‑calls per schermlade
- Minder gedownloade bytes per scherm
- Betere mediaan en worst‑case time-to-interactive op mobiel netwerk
- Minder achtergrondfetches en retries voor hetzelfde resultaat
Wanneer die verbeteren, verbeteren responsiviteit en batterijduur meestal samen.
Wat je moet meten voordat je iets verandert
Voordat je gaat batchen of caching tweaken, krijg een duidelijk beeld van wat de app nu doet. De snelste winst komt vaak van het repareren van een paar herhaalde boosdoeners, maar je vindt ze alleen als je echte schermen en flows meet (niet slechts één gelukkige pad test).
Voor een handvol hoog‑traffic schermen, log de basis: hoeveel requests per laadactie, welke endpoints worden aangeroepen, verzonden en ontvangen bytes (headers plus body), retry‑ en timeout‑percentages, en hoe lang het duurt voordat de UI bruikbaar aanvoelt. Als het kan, splitst foutpercentages op naar netwerktype (Wi‑Fi vs cellular). Die splitsingen onthullen vaak problemen die je op een stabiele verbinding mist.
Scheid foreground traffic van background traffic. Een scherm kan rustig lijken, maar de telefoon kan bezig zijn met achtergrondverversing, push‑gestuurde sync, analytics uploads of "voor het geval" prefetch calls. Track die apart zodat je niet het verkeerde optimaliseert.
Hotspots concentreren zich vaak rond een paar momenten: app‑start, home/feed schermen, detailschermen die naar veel calls leads, en pull‑to‑refresh. Kies er één en meet end‑to‑end.
Stel een baseline‑budget in zodat het team het eens is over wat “goed” betekent. Bijvoorbeeld: "Een cold load van het order‑tracking scherm mag niet meer dan 6 requests doen en niet meer dan 250 KB downloaden voordat de status wordt getoond."
Als je een eenvoudige KPI‑pair wil gebruiken om te starten, gebruik (1) requests per schermlade en (2) retry‑rate. Het verminderen van retries bespaart vaak meer batterij dan verwacht, omdat herhaalde retries de radio langer actief houden.
Stap voor stap: minder requests met batching
Chatty API's ontstaan gemakkelijk per ongeluk. Elk widget laadt "zijn" data, en één scherm triggert een dozijn kleine calls. De oplossing is meestal niet ingewikkeld: identificeer wat altijd samen laadt en geef het terug in minder calls.
Begin met het in kaart brengen van één hoog‑traffic scherm (home, inbox, orderlijst). Schrijf op wat above the fold verschijnt en traceer elk UI‑element naar het verzoek dat het voedt. Je vindt vaak duplicaten (bijv. hetzelfde gebruikersprofiel twee keer) en calls die altijd samen komen (profiel plus permissies plus ongelezen telling).
Groepeer daarna calls die betrouwbaar samen voorkomen. Je hebt meestal twee opties:
- Maak een doelgericht endpoint voor dat scherm (vaak stabieler)
- Voeg een batch‑endpoint toe dat een kleine, voorspelbare lijst van resources accepteert
Houd batches scherm‑gericht en begrensd zodat ze makkelijk te cachen, te monitoren en te debuggen zijn.
Een paar regels houden batching beheersbaar. Geef alleen terug wat het scherm nu nodig heeft, niet volledige objecten "voor het geval". Als sommige onderdelen optioneel zijn, maak dat expliciet zodat de UI de belangrijke delen snel kan renderen. Ontwerp het antwoord ook zo dat gedeeltelijke fouten niet dwingen tot volledige retry. Het is veel goedkoper om alleen te herproberen wat faalde dan de hele batch opnieuw te sturen.
Cachingheaders die batterij besparen (niet alleen bandbreedte)
Caching is een batterijfunctie. Elk verzoek wekt de radio, houdt de CPU bezig en triggert parsing en app‑logica. Goede cachingheaders veranderen veel verversingen in lichte checks.
De grootste winst is conditionele requests. In plaats van dezelfde data opnieuw te downloaden vraagt de app: "Is dit veranderd?" Zo niet, dan antwoordt de server met een klein 304 Not Modified.
Gebruik ETag op responses die een versie van een resource representeren, en laat de client If-None-Match meesturen bij de volgende fetch. Als het genereren van een ETag lastig is, werkt Last-Modified met If-Modified-Since goed voor eenvoudige "updated at" resources.
Voor data die zelden verandert, maak de cachebeslissing expliciet. Cache-Control moet de realiteit weerspiegelen. Een korte max-age voor gebruikersprofielen kan prima zijn, terwijl appconfig, referentielijsten en featureflags vaak langer kunnen.
Aan de clientzijde: behandel 304 als een snelle weg. Parse geen JSON (die is er niet), bouw geen modellen opnieuw en laat de UI niet flikkeren. Houd wat al op het scherm staat en werk alleen indicatoren bij.
Voorbeeld: een order‑tracking scherm pollt elke 15 seconden de orderstatus. Als de response een ETag bevat, kunnen de meeste checks 304 teruggeven. De app behoudt de laatste status en doet alleen echt werk wanneer de status verandert (bijv. "Packed" naar "Shipped").
Wees intentioneel met gevoelige data. Caching is niet automatisch onveilig, maar heeft duidelijke regels nodig. Vermijd cachen van responses met persoonlijke gegevens of tokens tenzij producteisen dat toelaten. Gebruik korte levensduren voor gebruikersspecifieke data en voorkom dat gedeelde caches private responses opslaan (gebruik Cache-Control: private waar nodig).
Slimmere payloads: minder sturen, minder parsen
Elke extra byte kost meer dan alleen bandbreedte op mobiel. Het houdt de radio langer wakker en laat de app CPU‑tijd besteden aan het decoderen van JSON en het updaten van modellen. Als je probeert API‑chattiness te verminderen, is het trimmen van payloads vaak de snelste winst.
Begin met een audit van payloads per scherm. Kies één scherm (bijv. de home feed), log responsegroottes en bekijk veld‑voor‑veld: rendert de client dit, of gebruikt het het om te beslissen wat te tonen? Zo niet, verwijder het uit dat endpoint.
Voor lijsten is een kleine "summary"‑vorm meestal voldoende. Een rij in een lijst heeft vaak een id, titel, status en timestamp nodig. Die heeft geen volledige beschrijvingen of diep geneste objecten nodig. Haal details alleen op wanneer de gebruiker een item opent.
Een paar veranderingen snijden payloads snel terug:
- Geef voorkeur aan ids of korte enum‑codes boven herhaalde lange strings
- Stuur geen voor de hand liggende defaults terug die de client veilig kan aannemen
- Vermijd het herhalen van hetzelfde geneste object in elk lijstitem
- Houd veldnamen en types stabiel zodat de client minder hoeft te vertakken en te herparseren
Compressie kan helpen, vooral op trage netwerken, maar test de CPU‑tradeoff op echte apparaten. Gzip of Brotli verkleinen vaak transfers sterk, maar oudere telefoons kunnen merkbare tijd kwijt zijn aan het decompressen van zeer grote responses. De grootste winst blijft het sturen van minder data van meet af aan.
Behandel response‑vormen als een contract. Wanneer veldnamen en types consistent blijven, heeft de app minder fallback‑logica en minder defensieve code nodig, wat helpt de UI soepel en het batterijverbruik laag te houden.
Ontwerp voor slechte netwerken en minder retries
Een mobiele app verbruikt niet alleen batterij bij het versturen van requests. Hij verbruikt ook batterij bij mislukken, retryen, de radio weer wakker maken en het werk herhalen. Als een API uitgaat van perfecte Wi‑Fi, betalen echte gebruikers op wankele 4G daar voor.
Maak het makkelijk om minder data op te vragen. Geef de voorkeur aan server‑filters en paginatie boven "alles downloaden en op de telefoon filteren." Als een scherm de laatste 20 events voor één gebruiker nodig heeft, ondersteun die exacte query zodat de app geen honderden rijen hoeft te halen om de meeste weg te gooien.
Ondersteun delta‑sync zodat de app kan vragen "wat is er veranderd sinds ik voor het laatst checkte?" Dat kan simpel zijn: retourneer een timestamp of een oplopend versienummer en laat de client alleen updates en deletes sinds dat punt opvragen.
Retries zijn onvermijdelijk, dus maak updates idempotent. Een retry mag niet dubbel rekenen, dubbel indienen of duplicaten aanmaken. Idempotentiekeys voor create‑operaties en update‑semantiek die state instelt (in plaats van "tel er één bij op") helpen veel.
Wanneer retries optreden, voorkom retry‑storms. Gebruik exponential backoff met jitter zodat duizenden apparaten niet tegelijk je servers bestormen en zodat de telefoon niet om de seconde wakker wordt.
Geef duidelijke foutcodes terug die de app helpen beslissen wat te doen. Een 401 triggert re-auth, een 404 stopt meestal met retryen, een 409 kan vereisen dat je state ververst, en 429 of 503 moeten backoff triggeren.
Clientgedrag dat API‑kosten vermenigvuldigt
Zelfs met een goed ontworpen API kan de client stilletjes het netwerkwerk vermenigvuldigen. Op mobiel kosten die extra wakeups en radio‑tijd vaak meer batterij dan de bytes zelf.
Cache data die zelden verandert. Profielfoto's, featureflags en referentiegegevens (landen, statussen, categorieën) hoeven niet bij elk schermbezoek opgehaald te worden. Geef ze redelijke levensduren, sla ze op schijf op en ververs alleen wanneer nodig. Als de API validatie ondersteunt (ETag of Last-Modified), is een snelle recheck vaak veel goedkoper dan een volledige download.
Een andere veelvoorkomende kwestie is dubbele in‑flight requests. Twee delen van de app vragen hetzelfde resource tegelijk (bijv. header en instellingen vragen allebei het profiel). Zonder coalescing stuur je twee calls, parse je twee responses en werk je state twee keer bij. Behandel één netwerkcall als de enige bron van waarheid en laat meerdere verbruikers erop wachten.
Achtergrondverversing moet doelgericht zijn. Als het niet snel iets verandert wat de gebruiker ziet of geen notificatie triggert, kan het meestal wachten. Voorkom refresh‑logica bij elke app‑resume. Voeg een korte cooldown toe en controleer wanneer de data voor het laatst is bijgewerkt.
Als je backends bouwt met AppMaster, is het makkelijker om clientgedrag te ondersteunen door endpoints rond schermen te vormen, response‑schema's consistent te houden en cachingheaders gecontroleerd toe te voegen zodat clients het grootste deel van de tijd stil kunnen blijven.
Veelgemaakte fouten met batching, caching en payloads
Het doel is minder radio‑wakeups, minder CPU‑werk en minder retries. Een paar patronen kunnen de besparing ongedaan maken en zelfs schermen trager laten aanvoelen.
Wanneer batching het erger maakt
Batching helpt totdat de batch verandert in een "geef me alles"‑call. Als de server veel tabellen moet joinen, zware permissiechecks draait en een enorm antwoord bouwt, kan dat ene verzoek langer duren dan meerdere kleintjes. Op mobiel houdt één traag verzoek de app wachtend, houdt het netwerk actief en verhoogt het timeout‑risico.
Een gezondere batch is scherm‑gevormd: alleen wat één view nodig heeft, met duidelijke limieten. Als je het antwoord niet in één zin kunt beschrijven, is het endpoint waarschijnlijk te breed.
Caching die verouderde schermen creëert
Cachen zonder duidelijke invalidatie leidt tot een slechte lus: gebruikers zien oude data, trekken om te verversen en de app doet extra volledige reloads. Gebruik cachingheaders met een plan voor wat de data bijwerkt (create/update acties, serverevents of korte freshness windows) zodat de client op gecachte responses kan vertrouwen.
Polling is een andere batterijval. Een strakke 5‑seconden timer houdt het apparaat bezig, zelfs als niets verandert. Geef voorkeur aan server‑gedreven updates waar mogelijk, of back off agressief (langere intervallen na lege polls, pauzeer op de achtergrond).
Oversized payloads zijn een stille kost. Het terugsturen van gigantische geneste objecten "voor het gemak" betekent meer bytes, meer JSON‑parsing en meer geheugenchurn. Stuur alleen wat het scherm nodig heeft en haal details on demand.
Tot slot: negeer gedeeltelijke fouten in een batch niet. Als één subresultaat faalt en je de hele batch herpropt, dupliceer je verkeer. Ontwerp responses zodat de client alleen de gefaalde delen kan herhalen.
Een korte checklist: houd batches begrensd, definieer cache‑freshness vooraf, vermijd strakke polling, snoei payloads en ondersteun gedeeltelijk succes.
Snelle pre‑release checklist
Voer vóór release één pass uit die alleen op netwerkgedrag is gericht. De meeste batterijwinst komt van het wegnemen van verrassingen: minder wakeups, minder parsen en minder retries op de achtergrond.
Draai dit op je drie belangrijkste schermen:
- Cold loads eindigen in een klein, voorspelbaar aantal requests (let op verborgen opvolgcalls zoals per‑item lookups).
- Responses bevatten duidelijke cachingregels (
ETagofLast-Modifiedwaar passend) en retourneren304 Not Modifiedwanneer niets is veranderd. - Lijstendpoints zijn begrensd: stabiele sortering, paginatie en geen ongebruikte velden standaard.
- Retry‑logica backt off met jitter en stopt bij fouten die zichzelf niet oplossen; totale retry‑tijd is begrensd.
- Achtergrondupdates zijn gerechtvaardigd; vermijd constante polling tenzij het echt verandert wat de gebruiker ziet.
Een eenvoudige realiteitscheck: laad een scherm, zet vliegtuigmodus aan en open het opnieuw. Als het nog iets bruikbaars toont (gecachete content, laatst bekende staat, vriendelijke placeholders), heb je waarschijnlijk onnodige calls verminderd en de waargenomen snelheid verbeterd.
Voorbeeld: een order‑tracking scherm goedkoper maken om te laden
Een klant opent een order‑tracking app op mobiel met 20% batterij over. Ze willen één ding: "Waar is mijn pakket nu?" Het scherm lijkt simpel, maar het API‑verkeer erachter kan verrassend duur zijn.
Voorheen laadt de app het scherm met een burst aan requests. De UI wacht terwijl de radio steeds wakker wordt, en een paar calls timen uit bij een zwakke verbinding.
Een typisch "voor" patroon ziet er zo uit:
GET /orders/{id}voor het orderoverzichtGET /orders/{id}/itemsvoor line itemsGET /orders/{id}/historyvoor statuseventsGET /mevoor gebruikersprofiel en voorkeurenGET /settingsvoor weergaveregels (valuta, datumformaat)
Pas nu drie veranderingen toe die niks aan de UI veranderen.
Eerst: voeg één schermendpoint toe dat alleen terugstuurt wat de view nodig heeft in één roundtrip: orderoverzicht, nieuwste status, recente geschiedenis en itemtitels. Ten tweede: cache het profiel: GET /me retourneert een ETag en Cache-Control: private, max-age=86400, zodat de meeste opens een snelle 304 worden (of geen request als de cache nog vers is). Ten derde: slank de payload in: de itemslijst stuurt alleen id, name, qty en thumbnail_url, niet volledige productbeschrijvingen of onnodige metadata.
Het resultaat is minder rondreizen, minder bytes en minder retries wanneer het netwerk hapert. De radio van de telefoon slaapt vaker, en daar zit de echte batterijwinst.
Voor de gebruiker verschijnt er niets "nieuws". Het scherm is hetzelfde, maar laadt sneller, voelt responsiever en blijft werken als de verbinding slecht is.
Volgende stappen: een praktisch uitrolplan (en waar AppMaster kan helpen)
Als je snelle winst wilt, begin klein en bewijs impact. Batterijwinst komt meestal van minder radio‑wakeups en minder parse‑werk, niet van een grote rewrite.
Drie veranderingen die veilig, meetbaar en gemakkelijk terug te draaien zijn:
- Meet één scherm end‑to‑end (requestaantal, totale bytes, time to interactive, fout‑ en retry‑percentages)
- Batch dat scherms requests in één of twee calls (houd oude endpoints voor compatibiliteit)
- Voeg
ETag‑ondersteuning toe op je hoogste‑traffic GET‑endpoints zodat clientsIf-None-Matchkunnen gebruiken en304 Not Modifiedontvangen
Kies een feature met stabiel gebruik, zoals een orderlijst of berichteninbox. Ship achter een server‑side flag als je kunt, en vergelijk dan KPI's voor het oude vs nieuwe pad over een paar dagen. Zoek naar minder requests per sessie, minder retries en minder bytes per actieve gebruiker.
Coördineer API‑ en appreleases zodat oudere clients niet breken. Een praktische regel: voeg nieuw gedrag eerst toe, migreer clients daarna, en verwijder oude gedrag als laatste. Als je cachinggedrag verandert, wees voorzichtig met gepersonaliseerde data en zorg dat gedeelde caches gebruikers niet mengen.
Als je backendwijzigingen sneller wilt prototype‑en en uitrollen, kan AppMaster (appmaster.io) helpen je data visueel te modelleren, bedrijfslogica met drag‑and‑drop te bouwen en productieklare source code te regenereren naarmate eisen veranderen.
Probeer eerst één gebatcht endpoint plus ETag op een enkel veelgebruikt scherm. Als de cijfers verbeteren, weet je precies waar je meer engineeringtijd in kunt investeren.
FAQ
Een handige vuistregel is om een budget per scherm vast te stellen en vervolgens echte sessies te meten. Veel teams beginnen met zoiets als 4–8 requests voor een cold screen load op mobiel en verscherpen dat daarna wanneer de grootste boosdoeners zijn opgelost. Het juiste aantal is wat consequent je time-to-interactive‑doel haalt zonder retries of langdurige radio‑activiteit te veroorzaken.
Batchen helpt meestal wanneer meerdere calls altijd samen gebeuren, maar het kan nadelig zijn als de batch traag of omvangrijk wordt. Houd batchresponses “scherm‑gericht” en begrensd zodat één request niet verandert in een single point of failure. Als een gebatcht endpoint vaak timeouts geeft of veel onbruikbare data terugstuurt, splitst het dan terug in een klein aantal gerichte calls.
Begin met ETag plus conditionele requests met If-None-Match, omdat dit veel verversingen kan veranderen in kleine 304 Not Modified responses. Voeg Cache-Control toe die overeenkomt met hoe vaak de data echt verandert, zodat de client onnodig netwerkwerk kan vermijden. Als ETag lastig is, is Last-Modified met If-Modified-Since een degelijk alternatief voor resources met een duidelijke update‑tijd.
Gebruik ETag wanneer je een betrouwbare “versie”-controle voor een resource wilt, vooral als inhoudswijzigingen niet netjes op tijdstempels terug te voeren zijn. Gebruik Last-Modified wanneer de server een duidelijke update‑tijd heeft en je genoegen neemt met tijdstempel‑nauwkeurigheid. Als je maar één kunt implementeren, is ETag vaak nauwkeuriger om onnodige downloads te vermijden.
Instrumenteer per scherm en per sessie, niet alleen per endpoint. Log requestaantallen, bytes (headers plus body), retries, timeouts en time-to-interactive, en scheid foreground van background werk zodat je niet de verkeerde traffic optimaliseert. Meestal zie je dat een paar schermen of flows de meeste herhaalde radio‑wakeups veroorzaken.
Laat elk subresultaat in de batch onafhankelijk slagen of falen en geef voldoende foutdetails zodat de client alleen kan herproberen wat faalde. Vermijd dat de client de hele batch opnieuw moet opvragen omdat één deel mislukte. Dit vermindert dubbele traffic en voorkomt extra radio‑wakeups bij onstabiele verbindingen.
Snoei responses naar wat het scherm nu daadwerkelijk weergeeft en gebruik samenvattingsvormen voor lijsten. Verplaats grote of zelden gebruikte velden naar een detail‑endpoint dat alleen laadt wanneer de gebruiker een item opent. Dit vermindert bytes over het netwerk en reduceert JSON‑parsing en model‑updates, wat een merkbare CPU‑ en batterijkost op telefoons kan zijn.
Gebruik exponential backoff met jitter en begrens het totale retry‑venster zodat de telefoon niet elke paar seconden wakker wordt. Maak schrijfoperaties idempotent zodat een retry geen duplicaten of dubbele acties veroorzaakt. Geef ook duidelijke statuscodes terug zodat de client stopt met retryen als de fout zichzelf niet oplost.
Strakke pollingintervallen houden radio en CPU actief, zelfs als er niets verandert. Als je moet pollen, vergroot de interval wanneer responses niet veranderen en pauzeer polling op de achtergrond. Waar mogelijk: schakel over naar event‑gestuurde updates zodat de app alleen wakker wordt als er daadwerkelijk iets nieuws is.
In AppMaster kun je schermgerichte endpoints maken en response‑schema's consistent houden, wat batchen en payload‑vormen makkelijker beheersbaar maakt. Je kunt ook caching‑vriendelijk gedrag implementeren door versioneringslogica toe te voegen en headers terug te geven die conditionele requests ondersteunen, zodat clients snelle “geen wijziging” antwoorden krijgen. Een praktische aanpak is te beginnen met één veelgebruikt scherm: ship één gebatcht endpoint en voeg ETag‑ondersteuning toe op de belangrijkste GETs, meet dan de daling in requests en retries.


