diff options
author | Martin Polden <mpolden@mpolden.no> | 2017-07-10 15:04:02 +0200 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2017-07-10 15:04:02 +0200 |
commit | 14bd023670aa6f783473f5858db58b1229050d95 (patch) | |
tree | 5901c303239764fe03ca37f103a0418db412a342 | |
parent | 32ea45b06eb829e38bee60a9b0b76341bed9c38c (diff) |
Cleanup
-rw-r--r-- | api/api.go | 84 | ||||
-rw-r--r-- | api/api_test.go | 14 | ||||
-rw-r--r-- | atb/atb.go | 21 | ||||
-rw-r--r-- | atb/atb_test.go | 4 | ||||
-rw-r--r-- | atb/rpc.go | 6 |
5 files changed, 52 insertions, 77 deletions
@@ -14,15 +14,15 @@ import ( cache "github.com/pmylund/go-cache" ) -// An API defines parameters for running an API server. +// API defines parameters for running an API server. type API struct { Client atb.Client CORS bool cache *cache.Cache - expiration + ttl } -type expiration struct { +type ttl struct { departures time.Duration stops time.Duration } @@ -48,14 +48,9 @@ func (a *API) getBusStops(urlPrefix string) (BusStops, bool, error) { const cacheKey = "stops" cached, hit := a.cache.Get(cacheKey) if hit { - cachedBusStops, ok := cached.(BusStops) - if !ok { - return BusStops{}, false, fmt.Errorf( - "type assertion of cached value failed") - } - return cachedBusStops, hit, nil + return cached.(BusStops), hit, nil } - atbBusStops, err := a.Client.GetBusStops() + atbBusStops, err := a.Client.BusStops() if err != nil { return BusStops{}, hit, err } @@ -72,7 +67,7 @@ func (a *API) getBusStops(urlPrefix string) (BusStops, bool, error) { // Store a pointer to the BusStop struct busStops.nodeIDs[s.NodeID] = &busStops.Stops[i] } - a.cache.Set(cacheKey, busStops, a.expiration.stops) + a.cache.Set(cacheKey, busStops, a.ttl.stops) return busStops, hit, nil } @@ -80,14 +75,9 @@ func (a *API) getDepartures(urlPrefix string, nodeID int) (Departures, bool, err cacheKey := strconv.Itoa(nodeID) cached, hit := a.cache.Get(cacheKey) if hit { - cachedDepartures, ok := cached.(Departures) - if !ok { - return Departures{}, false, fmt.Errorf( - "type assertion of cached value failed") - } - return cachedDepartures, hit, nil + return cached.(Departures), hit, nil } - forecasts, err := a.Client.GetRealTimeForecast(nodeID) + forecasts, err := a.Client.Forecasts(nodeID) if err != nil { return Departures{}, hit, err } @@ -115,7 +105,7 @@ func (a *API) BusStopsHandler(w http.ResponseWriter, r *http.Request) (interface return nil, &Error{ err: err, Status: http.StatusInternalServerError, - Message: "failed to get bus stops from atb", + Message: "Failed to get bus stops from AtB", } } a.setCacheHeader(w, hit) @@ -133,7 +123,7 @@ func (a *API) BusStopHandler(w http.ResponseWriter, r *http.Request) (interface{ return nil, &Error{ err: err, Status: http.StatusBadRequest, - Message: "missing or invalid nodeID", + Message: "Invalid nodeID", } } busStops, hit, err := a.getBusStops(urlPrefix(r)) @@ -141,16 +131,14 @@ func (a *API) BusStopHandler(w http.ResponseWriter, r *http.Request) (interface{ return nil, &Error{ err: err, Status: http.StatusInternalServerError, - Message: "failed to get bus stops from atb", + Message: "Failed to get bus stops from AtB", } } busStop, ok := busStops.nodeIDs[nodeID] if !ok { - msg := fmt.Sprintf("bus stop with nodeID=%d not found", nodeID) return nil, &Error{ - err: err, Status: http.StatusNotFound, - Message: msg, + Message: "Unknown bus stop", } } a.setCacheHeader(w, hit) @@ -168,7 +156,7 @@ func (a *API) DepartureHandler(w http.ResponseWriter, r *http.Request) (interfac return nil, &Error{ err: err, Status: http.StatusBadRequest, - Message: "missing or invalid nodeID", + Message: "Invalid nodeID", } } busStops, hit, err := a.getBusStops(urlPrefix(r)) @@ -176,16 +164,14 @@ func (a *API) DepartureHandler(w http.ResponseWriter, r *http.Request) (interfac return nil, &Error{ err: err, Status: http.StatusInternalServerError, - Message: "could not get bus stops from atb", + Message: "Failed to get bus stops from AtB", } } - _, knownBusStop := busStops.nodeIDs[nodeID] - if !knownBusStop { - msg := fmt.Sprintf("bus stop with nodeID=%d not found", nodeID) + _, ok := busStops.nodeIDs[nodeID] + if !ok { return nil, &Error{ - err: err, Status: http.StatusNotFound, - Message: msg, + Message: "Unknown bus stop", } } departures, hit, err := a.getDepartures(urlPrefix(r), nodeID) @@ -193,7 +179,7 @@ func (a *API) DepartureHandler(w http.ResponseWriter, r *http.Request) (interfac return nil, &Error{ err: err, Status: http.StatusInternalServerError, - Message: "could not get departures from atb", + Message: "Failed to get departures from AtB", } } a.setCacheHeader(w, hit) @@ -207,7 +193,7 @@ func (a *API) DeparturesHandler(w http.ResponseWriter, r *http.Request) (interfa return nil, &Error{ err: err, Status: http.StatusInternalServerError, - Message: "failed to get bus stops from atb", + Message: "Failed to get bus stops from AtB", } } a.setCacheHeader(w, hit) @@ -221,10 +207,10 @@ func (a *API) DeparturesHandler(w http.ResponseWriter, r *http.Request) (interfa return urls, nil } -// RootHandler lists known URLs. -func (a *API) RootHandler(w http.ResponseWriter, r *http.Request) (interface{}, *Error) { +// DefaultHandler lists known URLs. +func (a *API) DefaultHandler(w http.ResponseWriter, r *http.Request) (interface{}, *Error) { if r.URL.Path != "/" { - return a.NotFoundHandler(w, r) + return nil, &Error{Status: http.StatusNotFound, Message: "Resource not found"} } prefix := urlPrefix(r) busStopsURL := fmt.Sprintf("%s/api/v1/busstops", prefix) @@ -236,27 +222,17 @@ func (a *API) RootHandler(w http.ResponseWriter, r *http.Request) (interface{}, }, nil } -// NotFoundHandler handles requests to invalid routes. -func (a *API) NotFoundHandler(w http.ResponseWriter, r *http.Request) (interface{}, *Error) { - return nil, &Error{ - err: nil, - Status: http.StatusNotFound, - Message: "route not found", - } -} - -// New returns an new API using client to communicate with AtB. stopsExpiration -// and depExpiration control the cache expiration times for bus stops and -// departures. -func New(client atb.Client, stopsExpiration, depExpiration time.Duration, cors bool) API { - cache := cache.New(depExpiration, 30*time.Second) +// New returns an new API using client to communicate with AtB. stopTTL and departureTTL control the cache TTL bus stops +// and departures. +func New(client atb.Client, stopTTL, departureTTL time.Duration, cors bool) API { + cache := cache.New(departureTTL, 30*time.Second) return API{ Client: client, CORS: cors, cache: cache, - expiration: expiration{ - stops: stopsExpiration, - departures: depExpiration, + ttl: ttl{ + stops: stopTTL, + departures: departureTTL, }, } } @@ -303,6 +279,6 @@ func (a *API) Handler() http.Handler { mux.Handle("/api/v1/busstops/", appHandler(a.BusStopHandler)) mux.Handle("/api/v1/departures", appHandler(a.DeparturesHandler)) mux.Handle("/api/v1/departures/", appHandler(a.DepartureHandler)) - mux.Handle("/", appHandler(a.RootHandler)) + mux.Handle("/", appHandler(a.DefaultHandler)) return requestFilter(mux, a.CORS) } diff --git a/api/api_test.go b/api/api_test.go index 5824878..9bc1c4b 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -67,7 +67,7 @@ func TestAPI(t *testing.T) { status int }{ // Unknown resources - {"/not-found", `{"status":404,"message":"route not found"}`, 404}, + {"/not-found", `{"status":404,"message":"Resource not found"}`, 404}, // List know URLs {"/", fmt.Sprintf(`{"urls":["%s/api/v1/busstops","%s/api/v1/departures"]}`, server.URL, server.URL), 200}, // List all bus stops @@ -75,14 +75,14 @@ func TestAPI(t *testing.T) { // List all departures {"/api/v1/departures", fmt.Sprintf(`{"urls":["%s/api/v1/departures/16011376"]}`, server.URL), 200}, // Show specific bus stop - {"/api/v1/busstops/", `{"status":400,"message":"missing or invalid nodeID"}`, 400}, - {"/api/v1/busstops/foo", `{"status":400,"message":"missing or invalid nodeID"}`, 400}, - {"/api/v1/busstops/42", `{"status":404,"message":"bus stop with nodeID=42 not found"}`, 404}, + {"/api/v1/busstops/", `{"status":400,"message":"Invalid nodeID"}`, 400}, + {"/api/v1/busstops/foo", `{"status":400,"message":"Invalid nodeID"}`, 400}, + {"/api/v1/busstops/42", `{"status":404,"message":"Unknown bus stop"}`, 404}, {"/api/v1/busstops/16011376", fmt.Sprintf(`{"url":"%s/api/v1/busstops/16011376","stopId":100633,"nodeId":16011376,"description":"Prof. Brochs gt","longitude":10.398126,"latitude":63.415535,"mobileCode":"16011376 (Prof.)","mobileName":"Prof. (16011376)"}`, server.URL), 200}, // Show specific departure - {"/api/v1/departures/", `{"status":400,"message":"missing or invalid nodeID"}`, 400}, - {"/api/v1/departures/foo", `{"status":400,"message":"missing or invalid nodeID"}`, 400}, - {"/api/v1/departures/42", `{"status":404,"message":"bus stop with nodeID=42 not found"}`, 404}, + {"/api/v1/departures/", `{"status":400,"message":"Invalid nodeID"}`, 400}, + {"/api/v1/departures/foo", `{"status":400,"message":"Invalid nodeID"}`, 400}, + {"/api/v1/departures/42", `{"status":404,"message":"Unknown bus stop"}`, 404}, {"/api/v1/departures/16011376", fmt.Sprintf(`{"url":"%s/api/v1/departures/16011376","isGoingTowardsCentrum":true,"departures":[{"line":"6","registeredDepartureTime":"2015-02-26T18:38:00.000","scheduledDepartureTime":"2015-02-26T18:01:00.000","destination":"Munkegata M5","isRealtimeData":true}]}`, server.URL), 200}, } for _, tt := range tests { @@ -93,48 +93,47 @@ func (c *Client) post(m method, data interface{}) ([]byte, error) { if err != nil { return nil, err } - jsonBlob, err := m.ParseResponse(body) + out, err := m.Unmarshal(body) if err != nil { return nil, err } - return jsonBlob, nil + return out, nil } -// GetBusStops retrieves bus stops from AtBs API. -func (c *Client) GetBusStops() (BusStops, error) { +// BusStops retrieves bus stops from AtBs API. +func (c *Client) BusStops() (BusStops, error) { values := struct { Username string Password string }{c.Username, c.Password} - jsonBlob, err := c.post(busStopsList, values) + res, err := c.post(busStopsList, values) if err != nil { return BusStops{}, err } var stops BusStops - if err := json.Unmarshal(jsonBlob, &stops); err != nil { + if err := json.Unmarshal(res, &stops); err != nil { return BusStops{}, err } return stops, nil } -// GetRealTimeForecast retrieves a forecast from AtBs API, using nodeID to -// identify the bus stop. -func (c *Client) GetRealTimeForecast(nodeID int) (Forecasts, error) { +// Forecasts retrieves forecasts from AtBs API, using nodeID to identify the bus stop. +func (c *Client) Forecasts(nodeID int) (Forecasts, error) { values := struct { Username string Password string NodeID int }{c.Username, c.Password, nodeID} - jsonBlob, err := c.post(realTimeForecast, values) + res, err := c.post(realTimeForecast, values) if err != nil { return Forecasts{}, err } var forecasts Forecasts - if err := json.Unmarshal(jsonBlob, &forecasts); err != nil { + if err := json.Unmarshal(res, &forecasts); err != nil { return Forecasts{}, err } return forecasts, nil diff --git a/atb/atb_test.go b/atb/atb_test.go index f73fa94..0aaf0cb 100644 --- a/atb/atb_test.go +++ b/atb/atb_test.go @@ -35,7 +35,7 @@ func TestGetBusStops(t *testing.T) { }, }, } - stops, err := atb.GetBusStops() + stops, err := atb.BusStops() if err != nil { t.Fatal(err) } @@ -48,7 +48,7 @@ func TestGetRealTimeForecast(t *testing.T) { server := newTestServer("/", forecastResponse) defer server.Close() atb := Client{URL: server.URL} - forecasts, err := atb.GetRealTimeForecast(16011376) + forecasts, err := atb.Forecasts(16011376) expected := Forecasts{ Total: 1, Nodes: []NodeInfo{ @@ -8,7 +8,7 @@ import ( type method interface { NewRequest(data interface{}) (string, error) - ParseResponse(body []byte) ([]byte, error) + Unmarshal(b []byte) ([]byte, error) } func compileTemplate(t *template.Template, data interface{}) (string, error) { @@ -35,7 +35,7 @@ func (m *busStopsListMethod) NewRequest(data interface{}) (string, error) { return compileTemplate(m.template, data) } -func (m *busStopsListMethod) ParseResponse(body []byte) ([]byte, error) { +func (m *busStopsListMethod) Unmarshal(body []byte) ([]byte, error) { var stops busStopsListMethod if err := xml.Unmarshal(body, &stops); err != nil { return nil, err @@ -47,7 +47,7 @@ func (m *realTimeForecastMethod) NewRequest(data interface{}) (string, error) { return compileTemplate(m.template, data) } -func (m *realTimeForecastMethod) ParseResponse(body []byte) ([]byte, error) { +func (m *realTimeForecastMethod) Unmarshal(body []byte) ([]byte, error) { var forecast realTimeForecastMethod if err := xml.Unmarshal(body, &forecast); err != nil { return nil, err |