Free data jako páteř, placený overlay za přepínačem — a proč je dnes vypnutý

Open-Meteo pokryje celou předpověď zdarma. Placený overlay z OpenWeather sahal jen na pár okamžitých hodnot — dnes je vypnutý a aplikace jede dál.

Free data jako páteř, placený overlay za přepínačem — a proč je dnes vypnutý

Páteř zdarma: Open-Meteo

Při vývoji meteorologických aplikací dříve či později narazíte na finanční a výkonnostní limity datových zdrojů. Poskytovatelé přesných meteorologických dat si za svá API nechávají dobře zaplatit. Pokud vaše klientská základna roste, účty za tisíce požadavků mohou rychle ohrozit ekonomickou udržitelnost celého projektu. Naštěstí moderní softwarová architektura umožňuje tento problém vyřešit hybridním přístupem. Správná kombinace Open-Meteo a OpenWeather nabízí rovnováhu mezi cenou za volání a přesností tam, kde na ní uživateli nejvíce záleží.

Open-Meteo slouží v tomto návrhu jako bezplatná páteř celého systému. Toto API vyniká skvělou dostupností, v základním režimu nevyžaduje složitou správu API klíčů a nabízí robustní globální datové sady založené na otevřených fyzikálních modelech, jako jsou GFS nebo ECMWF. Z Open-Meteo se stahuje kompletní kostra předpovědi, která obsahuje aktuální stav, podrobnou hodinovou předpověď a denní výhled na sedm dní dopředu. Pro naprostou většinu zobrazovaných informací je tento zdroj zcela dostačující a pro koncového uživatele představuje stabilní základ, který pokrývá většinu jeho informačních potřeb.

Placený overlay jen na okamžité hodnoty — a proč je dnes vypnutý

Ačkoli jsou globální otevřené modely velmi přesné při sledování trendů a dlouhodobějších výhledů, u okamžitého stavu počasí mohou mít drobné zpoždění oproti realitě na konkrétním místě. V takovém případě přichází na řadu placené API od OpenWeather. To má hustou síť lokálních meteostanic a radarů, díky čemuž dokáže poskytnout velmi přesné a aktuální hodnoty pro danou minutu.

Dokud overlay běžel, nestahovali jsme z placeného API kompletní týdenní předpověď — OpenWeather sloužil pouze jako tenký overlay (překryvná vrstva) a ptali jsme se ho výhradně na aktuální stav pro danou lokalitu. Dnes je vypnutý na všech routách; popis níže je tedy o tom, jak byl postavený, ne o tom, co běží.

V praxi to znamená, že systém nejprve sestaví kompletní datovou strukturu z bezplatného Open-Meteo. Následně vezme několik vybraných okamžitých hodnot z OpenWeather (například přesnou aktuální teplotu, pocitovou teplotu a kód aktuálního stavu počasí) a těmito daty přepíše odpovídající pole v původním objektu. Zbytek předpovědi, včetně datově náročných hodinových a denních matic, zůstává nedotčen. Výsledkem je přesný okamžitý stav, aniž by se z placeného API stahovala celá týdenní předpověď.

Best-effort: co selže, to se tiše vynechá

Jedním ze základních pravidel robustní backendové architektury je předpoklad, že jakákoli externí služba může kdykoli selhat. Placené API může vyčerpat nastavené limity, může dojít k výpadku sítě nebo k dočasnému zvýšení latence na straně poskytovatele. Uživatel by však takový výpadek neměl vůbec zaznamenat.

Všechny doplňkové datové vrstvy, ať už jde o placený overlay z OpenWeather, index kvality ovzduší (AQI), nebo oficiální meteorologické výstrahy, jsou proto navrženy v režimu best-effort. Pokud volání těchto doplňkových služeb selže, aplikace nesmí vrátit chybový stav ani zobrazit uživateli prázdnou obrazovku.

Backend tyto chyby tiše zachytí, zapíše je do logu pro interní monitoring a pokračuje v sestavování odpovědi bez nich. Klient v takovém případě dostane kompletní a plně validní předpověď vygenerovanou výhradně z páteřního Open-Meteo. Uživatelský zážitek zůstává zachován a výpadek doplňkového zdroje nemá jak se k uživateli dostat.

Placené volání jen v refresh cestě

Abychom předešli nechtěnému finančnímu zatížení, je nutné striktně oddělit cestu pro čtení dat od cesty pro jejich aktualizaci. Ve složitějších systémech postavených například na kombinaci NestJS, MongoDB a Redis hrozí, že neopatrný vývojář zavolá drahé externí API přímo z controlleru, který obsluhuje běžné uživatelské dotazy na čtení. Při náhlém nárůstu návštěvnosti by takový návrh mohl vést k okamžitému vyčerpání rozpočtu.

Placené volání proto smí spustit jen aktualizační cesta a cold miss uvnitř ní. Běžné čtení buď najde data v cache, nebo počká na jediné doplnění dat pro danou lokalitu — nikdy nespustí vlastní placený dotaz navíc.

Data se aktualizují kontrolovaně na pozadí, případně přes zvláštní aktualizační mechanismus, který je chráněn přísným rate-limitingem. Tímto způsobem je zajištěno, že se drahé API volá pouze tehdy, když je to skutečně nutné, a to maximálně jedním voláním externího API na lokalitu v definovaném časovém okně. Controller pro běžné čtení tak nikdy nemůže omylem vygenerovat zbytečné náklady.

Mapper jako jediné místo normalizace

Různí poskytovatelé meteorologických dat používají odlišné formáty odpovědí. Zatímco Open-Meteo vrací data v plochých polích, kde indexy reprezentují časové řady, OpenWeather spoléhá na hluboce zanořené objekty JSON. Pokud by se tyto formáty míchaly napříč aplikací, kód by se rychle stal neudržovatelným.

Řešením je striktní normalizace dat na vstupu do systému. K tomuto účelu slouží vyhrazená mapovací vrstva. Tento mapper je jediným místem v celé aplikaci, které zná specifika jednotlivých externích API. Přijme surová data z obou zdrojů, ověří je, transformuje a sloučí do jednoho sdíleného objektu pro přenos dat (DTO).

Následující ukázka ilustruje zjednodušený koncept takového mapperu v TypeScriptu:

interface WeatherDTO {
  temperature: number;
  windSpeed: number;
  weatherCode: number;
  hourlyForecast: { time: string; temp: number }[];
}

interface OpenMeteoRaw {
  current: { temperature_2m: number; wind_speed_10m: number; weather_code: number };
  hourly: { time: string[]; temperature_2m: number[] };
}

interface OpenWeatherRaw {
  main: { temp: number };
  wind: { speed: number };
  weather: { id: number }[];
}

export class WeatherMapper {
  public static mapToDto(
    openMeteoRaw: OpenMeteoRaw,
    openWeatherRaw?: OpenWeatherRaw,
  ): WeatherDTO {
    // Základní kostra z bezplatného Open-Meteo
    const dto: WeatherDTO = {
      temperature: openMeteoRaw.current.temperature_2m,
      windSpeed: openMeteoRaw.current.wind_speed_10m,
      weatherCode: openMeteoRaw.current.weather_code,
      hourlyForecast: openMeteoRaw.hourly.time.map((time: string, index: number) => ({
        time,
        temp: openMeteoRaw.hourly.temperature_2m[index]
      }))
    };

    // Pokud je k dispozici placený overlay, přepíšeme vybrané hodnoty
    if (openWeatherRaw && openWeatherRaw.main) {
      dto.temperature = openWeatherRaw.main.temp;
      dto.windSpeed = openWeatherRaw.wind.speed;
      dto.weatherCode = this.mapOpenWeatherCode(openWeatherRaw.weather[0].id);
    }

    return dto;
  }

  private static mapOpenWeatherCode(code: number): number {
    // Interní převodní logika kódů počasí na jednotný standard
    return code;
  }
}

Zbytek aplikace, včetně frontendové části a databázových modelů, již pracuje výhradně s tímto jednotným DTO. Pokud se v budoucnu rozhodnete vyměnit OpenWeather za jiného placeného poskytovatele, dotkne se to jeho klienta, mapperu a konfigurace klíčů — zbytek aplikace, který zná jen DTO, zůstane beze změny. Architektura zůstává čistá a snadno rozšiřitelná.

Tento robustní přístup k integraci a normalizaci dat byl úspěšně nasazen v platformě, kterou detailně popisuje celý projekt Weather InTouch. Kombinace spolehlivého bezplatného základu s placeným překryvem drží placená volání na jediném místě a nechává aplikaci fungovat i tehdy, když doplňkový zdroj selže. Samotný překryv je dnes navíc vypnutý: přepisoval hodnoty, které bezplatný model vrací také, a to za řádově vyšší cenu za volání, takže zůstává v kódu za přepínačem, dokud se nevyplatí.

Související články

Kontaktní informace

Klidně se mi ozvěte ohledně nového projektu, konzultace nebo dlouhodobější spolupráce. Rád proberu smysluplné produktové zadání i zajímavé frontendové příležitosti.

Napište mi

© 2026 Martin Hubálek. Všechna práva vyhrazena.

Martin Hubálek IČO: 08827303 Sídlo: Dolní Štěpanice 29, 514 01 Benecko, Česká republika Zapsán v živnostenském rejstříku Nejsem plátce DPH