From 4761167e1c51475163b57bfcf0f2674e4258ea7d Mon Sep 17 00:00:00 2001 From: Johannes Theiner Date: Tue, 21 Jul 2020 16:50:51 +0200 Subject: [PATCH] adding optional query parameters --- src/client/WeatherClient.go | 19 ++++++++++--------- src/client/WeatherStruct.go | 8 ++++++++ src/config/Configuration.go | 25 +++++++++++++++++++++++-- src/server/WeatherServer.go | 37 +++++++++++++++++++++++++++++++++---- src/server/WeatherStruct.go | 2 ++ 5 files changed, 76 insertions(+), 15 deletions(-) diff --git a/src/client/WeatherClient.go b/src/client/WeatherClient.go index a76370a..ed1f620 100644 --- a/src/client/WeatherClient.go +++ b/src/client/WeatherClient.go @@ -9,22 +9,23 @@ import ( "strconv" ) -func GetByCityName(city string) WeatherResponse { - return get("https://api.openweathermap.org/data/2.5/weather?q=" + city) +var baseUrl = "https://api.openweathermap.org/data/2.5/weather" + +func GetByCityName(city string, language string, unit config.Units) WeatherResponse { + return get(baseUrl+"?q="+city, language, unit) } -func GetByCoordinates(longitude, latitude float64) WeatherResponse { - return get("https://api.openweathermap.org/data/2.5/weather?lat=" + strconv.FormatFloat(latitude, 'f', 6, 32) + "&lon=" + strconv.FormatFloat(longitude, 'f', 6, 32)) +func GetByCoordinates(longitude, latitude float64, language string, unit config.Units) WeatherResponse { + return get(baseUrl+"?lat="+strconv.FormatFloat(latitude, 'f', 6, 32)+"&lon="+strconv.FormatFloat(longitude, 'f', 6, 32), language, unit) } -func GetByZipCode(zip int, country string) WeatherResponse { - return get("https://api.openweathermap.org/data/2.5/weather?zip=" + string(zip) + "," + country) +func GetByZipCode(zip int, country string, language string, unit config.Units) WeatherResponse { + return get(baseUrl+"?zip="+string(zip)+","+country, language, unit) } - -func get(url string) WeatherResponse { +func get(url string, language string, unit config.Units) WeatherResponse { var configuration = config.LoadConfiguration() - response, err := http.Get(url + "&appid=" + configuration.ApiKey + "&lang=" + configuration.Language + "&units=" + configuration.Units) + response, err := http.Get(url + "&appid=" + configuration.ApiKey + "&lang=" + language + "&units=" + unit.String()) if err != nil { log.Fatal(err) } diff --git a/src/client/WeatherStruct.go b/src/client/WeatherStruct.go index 88f2778..a69e72e 100644 --- a/src/client/WeatherStruct.go +++ b/src/client/WeatherStruct.go @@ -2,6 +2,7 @@ package client type WeatherResponse struct { Coordinates Coordinates `json:"coord,omitempty"` + Weather []Weather `json:"weather,omitempty"` Base string `json:"base,omitempty"` Main Main `json:"main,omitempty"` Visibility int `json:"visibility,omitempty"` @@ -17,6 +18,13 @@ type WeatherResponse struct { Cod int `json:"cod,omitempty"` } +type Weather struct { + Id int `json:"id,omitempty"` + Main string `json:"main,omitempty"` + Description string `json:"description,omitempty"` + Icon string `json:"icon,omitempty"` +} + type Coordinates struct { Longitude float32 `json:"lon,omitempty"` Latitude float32 `json:"lat,omitempty"` diff --git a/src/config/Configuration.go b/src/config/Configuration.go index 0c3c908..7277223 100644 --- a/src/config/Configuration.go +++ b/src/config/Configuration.go @@ -4,12 +4,13 @@ import ( "fmt" "os" "strconv" + "strings" ) type Configuration struct { ApiKey string Language string - Units string + Units Units Port int JwtSecret string @@ -26,7 +27,7 @@ func LoadConfiguration() *Configuration { return &Configuration{ ApiKey: getEnv("API_KEY", ""), Language: getEnv("LANGUAGE", "en"), - Units: getEnv("UNITS", "metric"), + Units: StringToUnit(getEnv("UNITS", "metric")), Port: getEnvAsInt("PORT", 8080), JwtSecret: getEnv("JWT_SECRET", "super secret value"), SentryDsn: getEnv("SENTRY_DSN", ""), @@ -51,3 +52,23 @@ func getEnvAsInt(name string, defaultVal int) int { return defaultVal } + +type Units int + +const ( + Metric Units = iota + Imperial +) + +func (unit Units) String() string { + return [...]string{"metric", "imperial"}[unit] +} + +func StringToUnit(string string) Units { + + if strings.EqualFold(string, "metric") { + return Metric + } else { + return Imperial + } +} diff --git a/src/server/WeatherServer.go b/src/server/WeatherServer.go index 9c694d1..8439771 100644 --- a/src/server/WeatherServer.go +++ b/src/server/WeatherServer.go @@ -20,8 +20,10 @@ import ( "time" ) +var conf *config.Configuration + func StartServer() { - conf := config.LoadConfiguration() + conf = config.LoadConfiguration() port := strconv.Itoa(conf.Port) log.Println("starting server on port " + port) @@ -97,7 +99,16 @@ func defaultHandler(writer http.ResponseWriter, _ *http.Request) { func cityHandler(writer http.ResponseWriter, req *http.Request) { writer.Header().Set("Content-Type", "application/json") vars := mux.Vars(req) - data := client.GetByCityName(vars["city"]) + + if vars["city"] == "" { + if _, err := writer.Write([]byte("no city provided")); err != nil { + panic(err) + } + } + + language, units := getOptionalArgs(req) + + data := client.GetByCityName(vars["city"], language, units) writer.WriteHeader(http.StatusOK) if err := json.NewEncoder(writer).Encode(convert(data)); err != nil { panic(err) @@ -116,7 +127,9 @@ func coordinatesHandler(writer http.ResponseWriter, req *http.Request) { if err != nil { panic(err) } - data := client.GetByCoordinates(longitude, latitude) + language, units := getOptionalArgs(req) + + data := client.GetByCoordinates(longitude, latitude, language, units) writer.WriteHeader(http.StatusOK) if err := json.NewEncoder(writer).Encode(convert(data)); err != nil { panic(err) @@ -130,7 +143,7 @@ func zipCodeHandler(writer http.ResponseWriter, req *http.Request) { if err != nil { panic(err) } - data := client.GetByZipCode(zip, vars["country"]) + data := client.GetByZipCode(zip, vars["country"], config.LoadConfiguration().Language, config.Metric) writer.WriteHeader(http.StatusOK) if err := json.NewEncoder(writer).Encode(convert(data)); err != nil { panic(err) @@ -141,6 +154,20 @@ func timeoutHandler(h http.Handler) http.Handler { return http.TimeoutHandler(h, 1*time.Second, "timed out") } +func getOptionalArgs(req *http.Request) (language string, units config.Units) { + language = conf.Language + units = conf.Units + + if lang := req.URL.Query().Get("language"); lang != "" { + language = lang + } + if unit := req.URL.Query().Get("units"); unit != "" { + units = config.StringToUnit(unit) + } + + return language, units +} + func convert(weatherData client.WeatherResponse) Weather { return Weather{ TemperatureCurrent: weatherData.Main.Temperature, @@ -149,6 +176,8 @@ func convert(weatherData client.WeatherResponse) Weather { FeelsLike: weatherData.Main.FeelsLike, Pressure: weatherData.Main.Pressure, Humidity: weatherData.Main.Humidity, + Description: weatherData.Weather[0].Description, + Icon: weatherData.Weather[0].Icon, WindSpeeed: weatherData.Wind.Speed, WindDegree: weatherData.Wind.Degree, Clouds: weatherData.Clouds.All, diff --git a/src/server/WeatherStruct.go b/src/server/WeatherStruct.go index 9c32df3..7f143f9 100644 --- a/src/server/WeatherStruct.go +++ b/src/server/WeatherStruct.go @@ -7,6 +7,8 @@ type Weather struct { TemperatureMax float32 `json:"temperature_max"` Pressure int `json:"pressure"` Humidity int `json:"humidity"` + Description string `json:"description"` + Icon string `json:"icon"` WindSpeeed float32 `json:"wind_speed"` WindDegree int `json:"wind_degree"`