Salta al contenuto

App mobile e web

App di spotting, avvisi di voli insoliti, mappe: la chiave resta sul tuo server e l’app chiede a te. Così il consumo dipende da quanto spesso aggiorni, non da quanti utenti hai.

Lo schema

Il tuo server scarica i dati a intervalli fissi e li tiene in memoria; l’app chiede al server solo quello che le serve. Puoi scaricare una zona per ogni area che servi, oppure, con Pro o Business, il mondo intero in una richiesta.

La tua app
chiede al tuo server, senza chiave
Il tuo server
cache in memoria, aggiornata ogni 30 s
API FlyItalyADSB
la chiave sta solo qui

Quanto consuma

Con la cache il conto non dipende dagli utenti. Due esempi, con un aggiornamento ogni 30 secondi:

SchemaAl mesePiano
Il mondo intero in una richiesta86.400Pro (solo Pro e Business hanno il raggio mondiale)
10 zone da 500 km864.000Starter (fino a 1.000 km e 1 milione al mese)
Ogni utente chiede all’API da sé, 1.000 utenti attivi86.400.000oltre il Business: da evitare

Il mondo intero pesa circa 7,2 MB di JSON, 1,1 MB con gzip: non ci sono limiti di banda, contano solo le richieste. Chiedi la compressione (Accept-Encoding: gzip, fetch lo fa da sé).

Il codice

Il tuo server, una cache per tutti (Node 18+)
// server.mjs: una cache per tutti gli utenti della tua app (Node 18+, nessuna dipendenza)
import http from 'node:http';

const KEY = process.env.FIA_API_KEY;
// Pro e Business: il mondo intero. Con Free usa la tua zona (fino a 500 km).
const SOURCE = 'https://api.flyitalyadsb.com/v2/lat/0/lon/0/dist/20000';
const ATTRIBUTION = 'Dati di volo: FlyItalyADSB (flyitalyadsb.com), CC BY-SA 4.0';
let snapshot = { now: 0, ac: [] };

async function refresh() {
  try {
    const r = await fetch(SOURCE, { headers: { 'X-Api-Key': KEY, 'User-Agent': 'my-app-backend/1.0' } });
    if (r.ok) snapshot = await r.json(); // fetch decomprime il gzip da solo
    else console.log('refresh', r.status, r.headers.get('retry-after') ?? '');
  } catch (e) {
    console.log('refresh failed', e.message); // resta l’ultima copia
  }
}
refresh();
setInterval(refresh, 30_000);

const km = (la1, lo1, la2, lo2) => {
  const p = Math.PI / 180;
  const h = Math.sin(((la2 - la1) * p) / 2) ** 2
    + Math.cos(la1 * p) * Math.cos(la2 * p) * Math.sin(((lo2 - lo1) * p) / 2) ** 2;
  return 12742 * Math.asin(Math.sqrt(h));
};

// GET /near?lat=40.64&lon=-73.78&km=25
http.createServer((req, res) => {
  const q = new URL(req.url, 'http://localhost').searchParams;
  const lat = Number(q.get('lat')), lon = Number(q.get('lon'));
  const radius = Math.min(Number(q.get('km')) || 25, 250);
  const ac = snapshot.ac.filter((a) => a.lat != null && km(lat, lon, a.lat, a.lon) <= radius);
  res.writeHead(200, { 'Content-Type': 'application/json', 'Cache-Control': 'max-age=5' });
  res.end(JSON.stringify({ now: snapshot.now, attribution: ATTRIBUTION, ac }));
}).listen(8080);
Nell’app
// Nell’app: chiedi al tuo server, mai all’API con la chiave
const res = await fetch('https://tuo-server.example/near?lat=40.64&lon=-73.78&km=25');
const { ac, attribution } = await res.json();
// mostra «attribution» dove l’utente vede gli aerei

Al posto di LA_TUA_CHIAVE la tua chiave: è gratuita, si chiede qui. Specifica completa in openapi.json.

Funzioni in più per un’app

  • Storico: la traccia di un aereo in un giorno, anche oggi, con /v2/history/{hex}/{data}. Storico.
  • Sorvoli: gli aerei passati sopra un punto tra due istanti, con /v2/overflights.
  • Traffico notevole: emergenze, militari e altri aerei notevoli in una zona con /v2/events, e con i piani a pagamento gli stessi eventi in push sul tuo URL. Avvisi e webhook.
  • Profilo di un aereo in una richiesta: identità, se lo vediamo ora, primo e ultimo giorno nello storico, con /v2/profile/{hex}.

Attenzione a

  • Mai la chiave nell’app o nella pagina web. Il CORS è aperto, ma una chiave nel codice del client la vede chiunque.
  • Aggiornare più spesso di ogni 2 secondi non serve: il dato non cambia più velocemente.
  • L’attribuzione nell’app, dove l’utente vede gli aerei: la riga da usare. Il server dell’esempio la restituisce insieme ai dati.
  • Su un 429 tieni l’ultima copia e riprova dopo Retry-After: gli utenti non se ne accorgono.
  • Non ci sono tratte né foto nei dati: se l’app mostra partenza e arrivo, serve un’altra fonte.

Per approfondire

← Per chi costruisce prodotti