Jak powstał Avia Weather (cz. 2): skąd brać dane i jak ukryć klucz API
9.10.2026 · 3 min czytania
W części 1 ustaliliśmy pomysł i stack. Mam ładny interfejs, który… nie pokazuje żadnej pogody. Pora to zmienić — bo aplikacja pogodowa bez prawdziwych danych to tylko makieta.
Skąd wziąć prawdziwe METAR-y i TAF-y?#
Nie będę przecież ręcznie przepisywał depesz. Potrzebuję źródła, które poda mi aktualne dane dla dowolnego lotniska. Padło na AVWX — API, które zwraca METAR, TAF i informacje o stacji w czytelnym JSON-ie. Jest darmowy plan, który w zupełności wystarcza do nauki i małego projektu.
Jest jeden haczyk: żeby z niego korzystać, trzeba się uwierzytelnić tokenem.
Pierwszy odruch (zły): token we frontendzie#
Mój pierwszy pomysł był prosty: skoro to React woła API, to wkleję token do kodu i po sprawie. I tu zapaliła mi się lampka.
Nawet jeśli schowam token do zmiennej środowiskowej z prefiksem VITE_ — to
nic nie daje! Vite wkompilowuje takie zmienne do paczki, która leci do
przeglądarki. Prefiks VITE_ oznacza wręcz „to jest publiczne, możesz tego
używać na froncie”. Dokładnie takiego zachowania chciałem uniknąć.
Rozwiązanie: funkcja serwerowa jako pośrednik#
Potrzebowałem czegoś pomiędzy przeglądarką a AVWX — kawałka kodu, który działa na serwerze, trzyma token u siebie i tylko podaje mi gotowe dane. Na Netlify robi to funkcja serwerowa (serverless function).
Przepływ wygląda tak:
- Frontend woła moją funkcję:
/.netlify/functions/avwx?station=EPWA - Funkcja (na serwerze) dokłada token i woła AVWX
- AVWX zwraca dane do funkcji
- Funkcja oddaje czysty JSON do frontendu
Token nigdy nie opuszcza serwera. Przeglądarka widzi tylko moją funkcję, a nie AVWX ani klucza.
Uproszczony szkielet funkcji (netlify/functions/avwx.mjs):
export default async (req) => {
const url = new URL(req.url);
const station = url.searchParams.get("station") ?? "";
// Walidacja: tylko 3 lub 4 litery (kod IATA albo ICAO)
if (!/^[A-Za-z]{3,4}$/.test(station)) {
return new Response("Nieprawidłowy kod stacji", { status: 400 });
}
const token = process.env.AVWX_TOKEN; // tylko na serwerze!
const res = await fetch(`https://avwx.rest/api/metar/${station}`, {
headers: { Authorization: `Bearer ${token}` },
});
return new Response(await res.text(), {
status: res.status,
headers: { "Content-Type": "application/json" },
});
};
Dwie rzeczy, na które zwróć uwagę:
Po stronie frontendu — jeden punkt wejścia#
Zamiast wołać funkcję w trzech miejscach (METAR, TAF, stacja), zrobiłem sobie jedną funkcję pomocniczą i trzy cienkie opakowania na niej. Ale o tym — jak ładnie to posprzątać i jak zamienić te kosmiczne kody na ludzki język — w części 3.