improved rest api - CRUD weather sensor + db
This commit is contained in:
parent
e483794ce1
commit
6391b39c8e
4 changed files with 153 additions and 57 deletions
165
api/rest-api.go
165
api/rest-api.go
|
@ -4,7 +4,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
"weather-data/storage"
|
"weather-data/storage"
|
||||||
"weather-data/weathersource"
|
"weather-data/weathersource"
|
||||||
|
|
||||||
|
@ -43,24 +42,40 @@ func (api *weatherRestApi) handleRequests() *mux.Router {
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
|
|
||||||
router.HandleFunc("/", api.homePageHandler)
|
router.HandleFunc("/", api.homePageHandler)
|
||||||
router.HandleFunc("/random", api.randomWeatherHandler)
|
|
||||||
router.HandleFunc("/randomlist", api.randomWeatherListHandler)
|
router.HandleFunc("/{_dummy:(?i)random}", api.randomWeatherHandler).Methods("GET")
|
||||||
router.HandleFunc("/addData", api.addDataHandler)
|
router.HandleFunc("/{_dummy:(?i)randomlist}", api.randomWeatherListHandler).Methods("GET")
|
||||||
router.HandleFunc("/getData/{id}", api.getData)
|
|
||||||
router.HandleFunc("/registerWeatherSensor/{name}", api.registerWeatherSensor)
|
router.HandleFunc("/{_dummy:(?i)sensor}/{id}/{_dummy:(?i)weather-data}", api.getWeatherDataHandler).Methods("GET")
|
||||||
|
router.HandleFunc("/{_dummy:(?i)sensor}/{id}/{_dummy:(?i)weather-data}", api.addWeatherDataHandler).Methods("POST")
|
||||||
|
|
||||||
|
router.HandleFunc("/{_dummy:(?i)sensor}/{id}", api.getWeatherSensorHandler).Methods("GET")
|
||||||
|
router.HandleFunc("/{_dummy:(?i)sensor}/{id}", api.updateWeatherSensorHandler).Methods("PUT")
|
||||||
|
router.HandleFunc("/{_dummy:(?i)sensor}/{id}", api.deleteWeatherSensorHandler).Methods("DELETE")
|
||||||
|
|
||||||
|
router.HandleFunc("/{_dummy:(?i)register/sensor}/{name}", api.registerWeatherSensorHandler).Methods("POST")
|
||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
|
||||||
func caselessMatcher(next http.Handler) http.Handler {
|
func (api *weatherRestApi) randomWeatherHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
w.Header().Add("content-type", "application/json")
|
||||||
r.URL.Path = strings.ToLower(r.URL.Path)
|
w.WriteHeader(http.StatusOK)
|
||||||
next.ServeHTTP(w, r)
|
json.NewEncoder(w).Encode(storage.NewRandomWeatherData().ToMap())
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *weatherRestApi) getData(w http.ResponseWriter, r *http.Request) {
|
func (api *weatherRestApi) randomWeatherListHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Add("content-type", "application/json")
|
var datapoints = make([]*storage.WeatherData, 0)
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
datapoints = append(datapoints, storage.NewRandomWeatherData())
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Add("content-type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(storage.ToMap(datapoints))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *weatherRestApi) getWeatherDataHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
id := vars["id"]
|
id := vars["id"]
|
||||||
|
|
||||||
|
@ -72,7 +87,7 @@ func (api *weatherRestApi) getData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
query.SensorId, err = uuid.Parse(id)
|
query.SensorId, err = uuid.Parse(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "could not parse uuid", http.StatusBadRequest)
|
http.Error(w, "could not parse id of sensor", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,32 +98,15 @@ func (api *weatherRestApi) getData(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
res := storage.ToMap(storage.GetOnlyQueriedFields(data, query))
|
res := storage.ToMap(storage.GetOnlyQueriedFields(data, query))
|
||||||
|
|
||||||
|
w.Header().Add("content-type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
json.NewEncoder(w).Encode(res)
|
json.NewEncoder(w).Encode(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *weatherRestApi) randomWeatherHandler(w http.ResponseWriter, r *http.Request) {
|
func (api *weatherRestApi) addWeatherDataHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Add("content-type", "application/json")
|
vars := mux.Vars(r)
|
||||||
json.NewEncoder(w).Encode(storage.NewRandomWeatherData())
|
id := vars["id"]
|
||||||
}
|
|
||||||
|
|
||||||
func (api *weatherRestApi) randomWeatherListHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var datapoints = make([]*storage.WeatherData, 0)
|
|
||||||
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
datapoints = append(datapoints, storage.NewRandomWeatherData())
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Add("content-type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(datapoints)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *weatherRestApi) addDataHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.Method != "POST" {
|
|
||||||
http.Error(w, "only POST-Method allowed", http.StatusMethodNotAllowed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Add("content-type", "application/json")
|
|
||||||
|
|
||||||
var data = make(map[string]interface{})
|
var data = make(map[string]interface{})
|
||||||
err := json.NewDecoder(r.Body).Decode(&data)
|
err := json.NewDecoder(r.Body).Decode(&data)
|
||||||
|
@ -116,6 +114,7 @@ func (api *weatherRestApi) addDataHandler(w http.ResponseWriter, r *http.Request
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
delete(data, "sensorId")
|
||||||
|
|
||||||
weatherData, err := storage.FromMap(data)
|
weatherData, err := storage.FromMap(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -123,27 +122,24 @@ func (api *weatherRestApi) addDataHandler(w http.ResponseWriter, r *http.Request
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
weatherData.SensorId, err = uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "could not parse id of sensor", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err = api.addNewWeatherData(*weatherData)
|
err = api.addNewWeatherData(*weatherData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.Header().Add("content-type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusCreated)
|
||||||
json.NewEncoder(w).Encode(weatherData.ToMap())
|
json.NewEncoder(w).Encode(weatherData.ToMap())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *weatherRestApi) homePageHandler(w http.ResponseWriter, r *http.Request) {
|
func (api *weatherRestApi) registerWeatherSensorHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintf(w, "Welcome to the Weather API!")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *weatherRestApi) registerWeatherSensor(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.Method != "POST" {
|
|
||||||
http.Error(w, "only POST-Method allowed", http.StatusMethodNotAllowed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Add("content-type", "application/json")
|
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
name := vars["name"]
|
name := vars["name"]
|
||||||
|
|
||||||
|
@ -153,9 +149,80 @@ func (api *weatherRestApi) registerWeatherSensor(w http.ResponseWriter, r *http.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.Header().Add("content-type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusCreated)
|
||||||
json.NewEncoder(w).Encode(sensor)
|
json.NewEncoder(w).Encode(sensor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *weatherRestApi) updateWeatherSensorHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
id := vars["id"]
|
||||||
|
|
||||||
|
sensorId, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var sensor storage.WeatherSensor
|
||||||
|
err = json.NewDecoder(r.Body).Decode(&sensor)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sensor.Id = sensorId
|
||||||
|
|
||||||
|
api.sensorRegistry.UpdateSensor(&sensor)
|
||||||
|
|
||||||
|
w.Header().Add("content-type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(sensor)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *weatherRestApi) getWeatherSensorHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
id := vars["id"]
|
||||||
|
|
||||||
|
sensorId, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
weatherSensor, err := api.sensorRegistry.ResolveSensorById(sensorId)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "sensor not exists", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Add("content-type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(weatherSensor)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *weatherRestApi) deleteWeatherSensorHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
id := vars["id"]
|
||||||
|
|
||||||
|
sensorId, err := uuid.Parse(id)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = api.sensorRegistry.DeleteSensor(sensorId)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *weatherRestApi) homePageHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintf(w, "Welcome to the Weather API!")
|
||||||
|
}
|
||||||
|
|
||||||
//AddNewWeatherDataCallback adds a new callbackMethod for incoming weather data
|
//AddNewWeatherDataCallback adds a new callbackMethod for incoming weather data
|
||||||
func (api *weatherRestApi) AddNewWeatherDataCallback(callback weathersource.NewWeatherDataCallbackFunc) {
|
func (api *weatherRestApi) AddNewWeatherDataCallback(callback weathersource.NewWeatherDataCallbackFunc) {
|
||||||
api.weatherSource.AddNewWeatherDataCallback(callback)
|
api.weatherSource.AddNewWeatherDataCallback(callback)
|
||||||
|
|
|
@ -130,6 +130,29 @@ func (registry *mongodbSensorRegistry) GetSensors() ([]*WeatherSensor, error) {
|
||||||
return readData, nil
|
return readData, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (registry *mongodbSensorRegistry) DeleteSensor(sensorId uuid.UUID) error {
|
||||||
|
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
_, err := registry.sensorCollection.DeleteOne(ctx, bson.M{"id": sensorId})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (registry *mongodbSensorRegistry) UpdateSensor(sensor *WeatherSensor) error {
|
||||||
|
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
_, err := registry.sensorCollection.ReplaceOne(ctx,
|
||||||
|
bson.M{"id": sensor.Id},
|
||||||
|
sensor)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (registry *mongodbSensorRegistry) Close() error {
|
func (registry *mongodbSensorRegistry) Close() error {
|
||||||
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
err := registry.client.Disconnect(ctx)
|
err := registry.client.Disconnect(ctx)
|
||||||
|
|
|
@ -6,6 +6,8 @@ type SensorRegistry interface {
|
||||||
RegisterSensorByName(string) (*WeatherSensor, error)
|
RegisterSensorByName(string) (*WeatherSensor, error)
|
||||||
ExistSensor(*WeatherSensor) (bool, error)
|
ExistSensor(*WeatherSensor) (bool, error)
|
||||||
ResolveSensorById(uuid.UUID) (*WeatherSensor, error)
|
ResolveSensorById(uuid.UUID) (*WeatherSensor, error)
|
||||||
|
DeleteSensor(uuid.UUID) error
|
||||||
|
UpdateSensor(*WeatherSensor) error
|
||||||
GetSensors() ([]*WeatherSensor, error)
|
GetSensors() ([]*WeatherSensor, error)
|
||||||
Close() error
|
Close() error
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"errors"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -89,19 +89,23 @@ func FromMap(value map[string]interface{}) (*WeatherData, error) {
|
||||||
copy[key] = value
|
copy[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, exists := copy[SensorId]
|
||||||
idString, ok := copy[SensorId].(string)
|
idString, ok := copy[SensorId].(string)
|
||||||
if !ok {
|
if exists && !ok {
|
||||||
return nil, fmt.Errorf("sensorId must be of type string")
|
return nil, errors.New("sensorId must be of type string")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if exists {
|
||||||
data.SensorId, err = uuid.Parse(idString)
|
data.SensorId, err = uuid.Parse(idString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
delete(copy, SensorId)
|
delete(copy, SensorId)
|
||||||
|
}
|
||||||
|
|
||||||
timeStampString, ok := copy[TimeStamp].(string)
|
timeStampString, ok := copy[TimeStamp].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("timeStamp must be of type string")
|
return nil, errors.New("timeStamp must be of type string")
|
||||||
}
|
}
|
||||||
data.TimeStamp, err = time.Parse(time.RFC3339, timeStampString)
|
data.TimeStamp, err = time.Parse(time.RFC3339, timeStampString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Add table
Reference in a new issue