first pass at assessment
This commit is contained in:
82
main.go
82
main.go
@ -1,5 +1,85 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"github.com/icodealot/noaa"
|
||||
)
|
||||
|
||||
type ForecastReq struct {
|
||||
Latitude float64 `json:"latitude"`
|
||||
Longitude float64 `json:"longitude"`
|
||||
}
|
||||
|
||||
type ForecastResp struct {
|
||||
ShortForecast string `json:"shortForecast"`
|
||||
Temperature string `json:"temperature"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Using the default HTTP server
|
||||
// SHORTCUT: no TLS
|
||||
// SHORTCUT: The default HTTP server is good enough for small projects, but would need to be better configured for production
|
||||
// SHORTCUT: no rate limiting
|
||||
http.HandleFunc("GET /forecast", forecast)
|
||||
|
||||
// SHORTCUT: This server is only stopped when the process stops. This should have a graceful shutdown.
|
||||
if err := http.ListenAndServe(":8080", nil); err != nil {
|
||||
slog.Error("stopping server", err)
|
||||
}
|
||||
}
|
||||
|
||||
func forecast(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
|
||||
// SHORTCUT: not checking the body length to see if it is unreasonably large
|
||||
|
||||
// Decode request
|
||||
var foreReq ForecastReq
|
||||
if err := json.NewDecoder(r.Body).Decode(&foreReq); err != nil {
|
||||
slog.Error("decode forecast request error", err)
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Check that request is in range
|
||||
if foreReq.Longitude > 180 || foreReq.Longitude < -180 {
|
||||
slog.Error("invalid request", "latitude", foreReq.Latitude, "longitude", foreReq.Longitude)
|
||||
http.Error(w, "invalid request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Call out to NOAA for forecast
|
||||
resp, err := noaa.Forecast(fmt.Sprintf("%f", foreReq.Latitude), fmt.Sprintf("%f", foreReq.Longitude))
|
||||
if err != nil {
|
||||
slog.Error("noaa forecast request error", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Find today's forecast
|
||||
var result ForecastResp
|
||||
// SHORTCUT: assuming [0] is the closest to "today", and Periods has elements
|
||||
p := resp.Periods[0]
|
||||
result.ShortForecast = p.Summary
|
||||
|
||||
switch {
|
||||
case p.Temperature < 32:
|
||||
result.Temperature = "cold"
|
||||
case p.Temperature < 70:
|
||||
result.Temperature = "moderate"
|
||||
default:
|
||||
result.Temperature = "hot"
|
||||
}
|
||||
|
||||
// Return result
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if err := json.NewEncoder(w).Encode(result); err != nil {
|
||||
slog.Error("encode forecast response error", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user