commit 0d6c3e32ae774ba0a91ae1a76df13f0b280f03a7
parent 643d13b91062e6bbd86bf9b93adffdfb47350b1b
Author: Chris Bracken <chris@bracken.jp>
Date: Thu, 11 Nov 2021 16:45:41 -0800
Add JSON API to query readings
Adds an HTTP GET endpoint at /sensor/reading/ to query readings from
storage.
Diffstat:
2 files changed, 52 insertions(+), 5 deletions(-)
diff --git a/http/http.go b/http/http.go
@@ -25,6 +25,7 @@ func CreateServer(ds storage.DataStore) *HttpServer {
func (s HttpServer) ListenAndServe(addr string) error {
mux := goji.NewMux()
mux.HandleFunc(pat.Post("/sensor/airrohr/"), s.PostAirrohr)
+ mux.HandleFunc(pat.Get("/sensor/reading/"), s.QueryReadings)
return http.ListenAndServe(addr, mux)
}
@@ -52,6 +53,23 @@ func (s HttpServer) PostAirrohr(w http.ResponseWriter, r *http.Request) {
errorResponse(w, "Success", http.StatusOK)
}
+func (s HttpServer) QueryReadings(w http.ResponseWriter, r *http.Request) {
+ start := time.Now().Add(time.Hour * -24)
+ end := time.Now()
+ // TODO: extract start/end from r.URL.Query() with a default if not present.
+ readings, err := s.ds.QueryReadings(start, end)
+ if err != nil {
+ fmt.Println("Error: failed to query sensor data: " + err.Error())
+ errorResponse(w, "Bad Request. "+err.Error(), http.StatusBadRequest)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ jsonResp, _ := json.Marshal(readings)
+ w.Write(jsonResp)
+}
+
func errorResponse(w http.ResponseWriter, message string, httpStatusCode int) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(httpStatusCode)
diff --git a/storage/storage.go b/storage/storage.go
@@ -11,19 +11,22 @@ const (
INSERT_READING = "INSERT INTO " +
"sensor_data(sensor_id, sw_version, reading_time, reading_type, reading_value) " +
"VALUES($1, $2, $3, $4, $5)"
+ QUERY_READINGS = "SELECT sensor_id, sw_version, reading_time, reading_type, reading_value " +
+ "FROM sensor_data WHERE reading_time >= $1 AND reading_time < $2"
)
type Reading struct {
- SensorId string
- SoftwareVersion string
- Time time.Time
- Type string
- Value float64
+ SensorId string `json:"sensor_id"`
+ SoftwareVersion string `json:"sw_version"`
+ Time time.Time `json:"time",string`
+ Type string `json:"type"`
+ Value float64 `json:"value"`
}
type DataStore interface {
Close()
StoreReading(r *Reading) error
+ QueryReadings(start time.Time, end time.Time) ([]Reading, error)
}
type PostgresDataStore struct {
@@ -59,6 +62,27 @@ func (s *PostgresDataStore) StoreReading(r *Reading) error {
return err
}
+func (s *PostgresDataStore) QueryReadings(start time.Time, end time.Time) ([]Reading, error) {
+ rows, err := s.db.Query(QUERY_READINGS, start, end)
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+
+ var readings []Reading
+ for rows.Next() {
+ var r Reading
+ if err := rows.Scan(&r.SensorId, &r.SoftwareVersion, &r.Time, &r.Type, &r.Value); err != nil {
+ return readings, err
+ }
+ readings = append(readings, r)
+ }
+ if err = rows.Err(); err != nil {
+ return readings, err
+ }
+ return readings, nil
+}
+
type NullDataStore struct {
}
@@ -72,3 +96,8 @@ func (s *NullDataStore) Close() {
func (s *NullDataStore) StoreReading(r *Reading) error {
return nil
}
+
+func (s *NullDataStore) QueryReadings(start time.Time, end time.Time) ([]Reading, error) {
+ var readings []Reading
+ return readings, nil
+}