Sto lavorando a un prodotto che espone un'API RESTful per interagire con le entità di sistema (il solito CRUD), che funziona molto bene.
Oltre a CRUD, abbiamo recentemente riscontrato la necessità di esporre la capacità di interrogare dati basati su serie temporali differenti, con filtri diversi e con risoluzioni di aggregazione variabili (ma basate su praticamente le stesse funzioni di aggregazione).
Ad esempio, considera un sistema che gestisce le turbine eoliche. Avresti le solite operazioni CRUD per aggiungere / rimuovere le turbine, ma anche qualche tipo di API per interrogare l'uscita elettrica delle turbine o la velocità di rotazione nel tempo. Potresti voler ottenere una media di queste metriche su tutte le turbine di un sito, o per una singola turbina o per tutte le turbine di un produttore specifico (questi sono i tuoi "filtri"). Potresti volere i dati grezzi (cioè ogni misura eseguita in un determinato periodo di tempo), o punti dati orari, o giornalieri o settimanali (questa è la tua granularità o risoluzione).
Puoi tranquillamente presumere che tutte le query abbiano un filtro orario di inizio / fine e che l'ordinamento sia sempre basato sul tempo.
Il consumatore principale di questi dati è una GUI che rende grafici basati su di esso. È utile, anche se non strettamente necessario, che più metriche siano incapsulate in un singolo endpoint (cioè è possibile ottenere sia la velocità di rotazione della turbina che l'uscita per un punto nel tempo con una singola query).
Ciò che abbiamo fatto storicamente è considerare un tale punto di dati come entità REST (diciamo che chiamiamo TurbineStats
), e abbiamo un endpoint che supportava solo le entità di lista, e accetta i filtri e amp; risoluzione come parametri di query. Ad esempio:
GET /turbine/stats ⏎
?start=2018-01-01T10:11:12 ⏎
&end=2018-01-01T10:11:12 ⏎
&site_id=1234abcd ⏎
&model=ABCXYZ ⏎
&resolution=hourly
[
{
"timestamp": "2018-01-01T11:00:00",
"rotation_speed": 523.53,
"output_kwh": 20.5
},
{
"timestamp": "2018-01-01T12:00:00",
"rotation_speed": 433.13,
"output_kwh": 18.5
},
{
"timestamp": "2018-01-01T13:00:00",
"rotation_speed": 569.0,
"output_kwh": 24.1
},
...
]
Questo funziona, ma ci sembra sempre più simile a un anti-pattern, soprattutto perché:
- Mentre le entità sembrano più o meno uguali e hanno gli stessi campi, i dati possono avere un significato diverso a seconda della query. Ad esempio
rotation_speed
può essere esatto o mediato - Ci sono importanti metadati (come quelli che sono i filtri, quanti punti sono stati considerati, quante turbine sono incluse, ecc.) che possono essere inclusi come parte delle entità ma mescolare dati e metadati è scomodo.
- Richiedere una singola entità ha poco senso. Questa è fondamentalmente una "sola lista" API
- Le entità sono calcolate e non hanno identificatori univoci. Possiamo arrivare con l'identificatore calcolato, ma sembra che lo stiamo facendo solo per essere "RESTful" e non per un uso reale.
Puoi dare un esempio di serie storiche che richiedono l'API che funziona bene e si sente ben progettato, RESTful o no? Ci sono dei buoni schemi da guardare?