diff --git a/README.md b/README.md
index fe09f9e..1be8bfb 100644
--- a/README.md
+++ b/README.md
@@ -44,9 +44,8 @@ Two endpoints so far, both accepting `addr` parameter.
}
],
"Address": {
- "ACRateAccountKey": "12342478585",
- "Address": "500 Queen Street, Auckland Central",
- "Suggestion": "500 Queen Street, Auckland Central"
+ "ID": "12342478585",
+ "Address": "500 Queen Street, Auckland Central"
}
}
diff --git a/addr.go b/addr.go
index 8b71e74..5ba0a5d 100644
--- a/addr.go
+++ b/addr.go
@@ -1,73 +1,85 @@
package aklapi
import (
- "bytes"
"encoding/json"
"errors"
"log"
"net/http"
+ "strconv"
"time"
)
var (
// defined as a variable so it can be overridden in tests.
- addrURI = `https://www.aucklandcouncil.govt.nz/_vti_bin/ACWeb/ACservices.svc/GetMatchingPropertyAddresses`
+ addrURI = `https://www.aucklandcouncil.govt.nz/nextapi/property`
)
// AddrRequest is the address request.
type AddrRequest struct {
- ResultCount int `json:"ResultCount"`
- SearchText string `json:"SearchText"`
- RateKeyRequired bool `json:"RateKeyRequired"`
+ PageSize int
+ SearchText string
}
-// AddrResponse is the address response.
-type AddrResponse []Address
-
-// AddrSuggestion is the address suggestion.
+// Address is the address and its unique identifier (rate account key).
type Address struct {
- ACRateAccountKey string `json:"ACRateAccountKey"`
- Address string `json:"Address"`
- Suggestion string `json:"Suggestion"`
+ ID string `json:"ID"`
+ Address string `json:"Address"`
+}
+
+// AddrResponse is the address response.
+type AddrResponse struct {
+ Items []Address `json:"items"`
}
func (s Address) String() string {
- return "<" + s.Address + " (" + s.ACRateAccountKey + ")>"
+ return "<" + s.Address + " (" + s.ID + ")>"
}
// AddressLookup is a convenience function to get addresses.
-func AddressLookup(addr string) (AddrResponse, error) {
- return MatchingPropertyAddresses(&AddrRequest{SearchText: addr, RateKeyRequired: false, ResultCount: 10})
+func AddressLookup(addr string) (*AddrResponse, error) {
+ return MatchingPropertyAddresses(&AddrRequest{SearchText: addr, PageSize: 10})
}
// MatchingPropertyAddresses wrapper around the AKL Council API.
-func MatchingPropertyAddresses(addrReq *AddrRequest) (AddrResponse, error) {
+func MatchingPropertyAddresses(addrReq *AddrRequest) (*AddrResponse, error) {
cachedAr, ok := addrCache.Lookup(addrReq.SearchText)
if ok {
log.Printf("cached address result: %q", cachedAr)
return cachedAr, nil
}
- var buf bytes.Buffer
- enc := json.NewEncoder(&buf)
- if err := enc.Encode(addrReq); err != nil {
+
+ req, err := http.NewRequest("GET", addrURI, nil)
+ if err != nil {
return nil, err
}
+ q := req.URL.Query()
+ q.Add("query", addrReq.SearchText)
+ if addrReq.PageSize > 0 {
+ q.Add("pageSize", strconv.Itoa(addrReq.PageSize))
+ }
+ req.URL.RawQuery = q.Encode()
start := time.Now()
- resp, err := http.Post(addrURI, "application/json; charset=UTF-8", &buf)
+ client := &http.Client{}
+ resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
log.Printf("address call complete in %s", time.Since(start))
+ if resp.StatusCode != http.StatusOK {
+ return nil, errors.New("address API returned status code: " + strconv.Itoa(resp.StatusCode))
+ }
+
dec := json.NewDecoder(resp.Body)
- ar := AddrResponse{}
- if err := dec.Decode(&ar); err != nil {
+ var apiResp AddrResponse
+ if err := dec.Decode(&apiResp); err != nil {
return nil, err
}
- addrCache.Add(addrReq.SearchText, ar)
- return ar, nil
+
+ addrCache.Add(addrReq.SearchText, &apiResp)
+ return &apiResp, nil
}
func oneAddress(addr string) (*Address, error) {
@@ -76,8 +88,8 @@ func oneAddress(addr string) (*Address, error) {
return nil, err
}
// need exactly one address to continue
- if len(resp) != 1 {
+ if len(resp.Items) != 1 {
return nil, errors.New("ambiguous or empty address results")
}
- return &resp[0], nil
+ return &resp.Items[0], nil
}
diff --git a/addr_cache.go b/addr_cache.go
index 1ff2530..240ef09 100644
--- a/addr_cache.go
+++ b/addr_cache.go
@@ -1,10 +1,10 @@
package aklapi
-type addrResponseCache map[string]AddrResponse
+type addrResponseCache map[string]*AddrResponse
var addrCache = make(addrResponseCache)
-func (c addrResponseCache) Lookup(searchText string) (resp AddrResponse, ok bool) {
+func (c addrResponseCache) Lookup(searchText string) (resp *AddrResponse, ok bool) {
if NoCache {
return nil, false
}
@@ -12,6 +12,6 @@ func (c addrResponseCache) Lookup(searchText string) (resp AddrResponse, ok bool
return
}
-func (c addrResponseCache) Add(searchText string, ar AddrResponse) {
+func (c addrResponseCache) Add(searchText string, ar *AddrResponse) {
c[searchText] = ar
}
diff --git a/addr_cache_test.go b/addr_cache_test.go
index 2bf79c3..3b25fe4 100644
--- a/addr_cache_test.go
+++ b/addr_cache_test.go
@@ -19,13 +19,13 @@ func Test_addrResponseCache_Lookup(t *testing.T) {
NoCache bool // if true, set NoCache to true before running test
c addrResponseCache
args args
- wantResp AddrResponse
+ wantResp *AddrResponse
wantOk bool
}{
{"not in cache",
false,
addrResponseCache{
- "xxx": AddrResponse{*testAddr},
+ "xxx": &AddrResponse{Items: []Address{*testAddr}},
},
args{"yyy"},
nil,
@@ -34,16 +34,16 @@ func Test_addrResponseCache_Lookup(t *testing.T) {
{"cached",
false,
addrResponseCache{
- testAddr.Address: AddrResponse{*testAddr},
+ testAddr.Address: &AddrResponse{Items: []Address{*testAddr}},
},
args{testAddr.Address},
- AddrResponse{*testAddr},
+ &AddrResponse{Items: []Address{*testAddr}},
true,
},
{"cached, no cache mode",
true,
addrResponseCache{
- testAddr.Address: AddrResponse{*testAddr},
+ testAddr.Address: &AddrResponse{Items: []Address{*testAddr}},
},
args{testAddr.Address},
nil,
@@ -67,7 +67,7 @@ func Test_addrResponseCache_Lookup(t *testing.T) {
func Test_addrResponseCache_Add(t *testing.T) {
type args struct {
searchText string
- ar AddrResponse
+ ar *AddrResponse
}
tests := []struct {
name string
@@ -77,9 +77,9 @@ func Test_addrResponseCache_Add(t *testing.T) {
}{
{"add",
addrResponseCache{},
- args{testAddr.Address, AddrResponse{*testAddr}},
+ args{testAddr.Address, &AddrResponse{Items: []Address{*testAddr}}},
addrResponseCache{
- testAddr.Address: AddrResponse{*testAddr},
+ testAddr.Address: &AddrResponse{Items: []Address{*testAddr}},
},
},
}
diff --git a/addr_test.go b/addr_test.go
index 9235de9..ca345aa 100644
--- a/addr_test.go
+++ b/addr_test.go
@@ -10,9 +10,8 @@ import (
)
var testAddr = &Address{
- ACRateAccountKey: "42",
- Address: "Red Square",
- Suggestion: "Red Square",
+ ID: "42",
+ Address: "Red Square",
}
func TestMatchingPropertyAddresses(t *testing.T) {
@@ -23,21 +22,29 @@ func TestMatchingPropertyAddresses(t *testing.T) {
name string
testSrv *httptest.Server
args args
- want AddrResponse
+ want *AddrResponse
wantErr bool
}{
{"main branch",
httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- writeAddrJSON(w, AddrResponse{*testAddr})
+ writeAddrJSON(w, AddrResponse{Items: []Address{*testAddr}})
})),
args{&AddrRequest{
- ResultCount: 1,
- SearchText: "red sq",
- RateKeyRequired: false,
+ PageSize: 1,
+ SearchText: "red sq",
}},
- AddrResponse{*testAddr},
+ &AddrResponse{Items: []Address{*testAddr}},
false,
},
+ {"non-200 status code",
+ httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusInternalServerError)
+ writeAddrJSON(w, AddrResponse{})
+ })),
+ args{&AddrRequest{}},
+ nil,
+ true,
+ },
{"post error",
httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.NotFound(w, r)
@@ -81,15 +88,15 @@ func TestAddress(t *testing.T) {
name string
testSrv *httptest.Server
args args
- want AddrResponse
+ want *AddrResponse
wantErr bool
}{
{"main branch",
httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- writeAddrJSON(w, AddrResponse{*testAddr})
+ writeAddrJSON(w, AddrResponse{Items: []Address{*testAddr}})
})),
args{"red square"},
- AddrResponse{*testAddr},
+ &AddrResponse{Items: []Address{*testAddr}},
false,
},
}
@@ -124,7 +131,7 @@ func Test_oneAddress(t *testing.T) {
}{
{"one address",
httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- writeAddrJSON(w, AddrResponse{*testAddr})
+ writeAddrJSON(w, AddrResponse{Items: []Address{*testAddr}})
})),
args{"red square"},
testAddr,
@@ -132,7 +139,7 @@ func Test_oneAddress(t *testing.T) {
},
{"several address",
httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- writeAddrJSON(w, AddrResponse{*testAddr, *testAddr})
+ writeAddrJSON(w, AddrResponse{Items: []Address{*testAddr, *testAddr}})
})),
args{"red squarex"},
nil,
@@ -140,7 +147,7 @@ func Test_oneAddress(t *testing.T) {
},
{"no address",
httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Write([]byte("[]"))
+ w.Write([]byte("{\"items\":[]}"))
})),
args{"red squarec"},
nil,
diff --git a/rubbish.go b/rubbish.go
index 8c214cb..8e670a7 100644
--- a/rubbish.go
+++ b/rubbish.go
@@ -101,7 +101,7 @@ func CollectionDayDetail(addr string) (*CollectionDayDetailResult, error) {
return nil, err
}
start := time.Now()
- result, err := fetchandparse(address.ACRateAccountKey)
+ result, err := fetchandparse(address.ID)
if err != nil {
return nil, err
}
@@ -112,8 +112,8 @@ func CollectionDayDetail(addr string) (*CollectionDayDetailResult, error) {
}
// fetchandparse retrieves the data from the webpage and attempts to parse it.
-func fetchandparse(ACRateAccountKey string) (*CollectionDayDetailResult, error) {
- resp, err := http.Get(fmt.Sprintf(collectionDayURI, ACRateAccountKey))
+func fetchandparse(addressID string) (*CollectionDayDetailResult, error) {
+ resp, err := http.Get(fmt.Sprintf(collectionDayURI, addressID))
if err != nil {
return nil, err
}
diff --git a/rubbish_test.go b/rubbish_test.go
index 85df952..fd913fd 100644
--- a/rubbish_test.go
+++ b/rubbish_test.go
@@ -42,22 +42,22 @@ func Test_parse(t *testing.T) {
&CollectionDayDetailResult{
Collections: []RubbishCollection{
{
- Day: "Tuesday, 18 November",
- Date: adjustYear(time.Date(0, 11, 18, 0, 0, 0, 0, defaultLoc)),
+ Day: "Tuesday, 16 December",
+ Date: adjustYear(time.Date(0, 12, 16, 0, 0, 0, 0, defaultLoc)),
Rubbish: true,
Recycle: false,
FoodScraps: false,
},
{
- Day: "Tuesday, 18 November",
- Date: adjustYear(time.Date(0, 11, 18, 0, 0, 0, 0, defaultLoc)),
+ Day: "Tuesday, 16 December",
+ Date: adjustYear(time.Date(0, 12, 16, 0, 0, 0, 0, defaultLoc)),
Rubbish: false,
Recycle: false,
FoodScraps: true,
},
{
- Day: "Tuesday, 25 November",
- Date: adjustYear(time.Date(0, 11, 25, 0, 0, 0, 0, defaultLoc)),
+ Day: "Tuesday, 23 December",
+ Date: adjustYear(time.Date(0, 12, 23, 0, 0, 0, 0, defaultLoc)),
Rubbish: false,
Recycle: true,
FoodScraps: false,
@@ -71,14 +71,14 @@ func Test_parse(t *testing.T) {
&CollectionDayDetailResult{
Collections: []RubbishCollection{
{
- Day: "Saturday, 15 November",
- Date: adjustYear(time.Date(0, 11, 15, 0, 0, 0, 0, defaultLoc)),
+ Day: "Friday, 12 December",
+ Date: adjustYear(time.Date(0, 12, 12, 0, 0, 0, 0, defaultLoc)),
Rubbish: true,
Recycle: false,
},
{
- Day: "Saturday, 15 November",
- Date: adjustYear(time.Date(0, 11, 15, 0, 0, 0, 0, defaultLoc)),
+ Day: "Friday, 12 December",
+ Date: adjustYear(time.Date(0, 12, 12, 0, 0, 0, 0, defaultLoc)),
Rubbish: false,
Recycle: true,
},
@@ -116,31 +116,30 @@ func TestCollectionDayDetail(t *testing.T) {
&CollectionDayDetailResult{
Collections: []RubbishCollection{
{
- Day: "Tuesday, 18 November",
- Date: adjustYear(time.Date(0, 11, 18, 0, 0, 0, 0, defaultLoc)),
+ Day: "Tuesday, 16 December",
+ Date: adjustYear(time.Date(0, 12, 16, 0, 0, 0, 0, defaultLoc)),
Rubbish: true,
Recycle: false,
FoodScraps: false,
},
{
- Day: "Tuesday, 18 November",
- Date: adjustYear(time.Date(0, 11, 18, 0, 0, 0, 0, defaultLoc)),
+ Day: "Tuesday, 16 December",
+ Date: adjustYear(time.Date(0, 12, 16, 0, 0, 0, 0, defaultLoc)),
Rubbish: false,
Recycle: false,
FoodScraps: true,
},
{
- Day: "Tuesday, 25 November",
- Date: adjustYear(time.Date(0, 11, 25, 0, 0, 0, 0, defaultLoc)),
+ Day: "Tuesday, 23 December",
+ Date: adjustYear(time.Date(0, 12, 23, 0, 0, 0, 0, defaultLoc)),
Rubbish: false,
Recycle: true,
FoodScraps: false,
},
},
Address: &Address{
- ACRateAccountKey: "42",
- Address: "Red Square",
- Suggestion: "Red Square",
+ ID: "42",
+ Address: "Red Square",
},
},
false,
@@ -285,7 +284,7 @@ func TestRubbishCollection_parseDate(t *testing.T) {
func testMux() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/addr", func(w http.ResponseWriter, r *http.Request) {
- data, err := json.Marshal(AddrResponse{*testAddr})
+ data, err := json.Marshal(AddrResponse{Items: []Address{*testAddr}})
if err != nil {
panic(err)
}
diff --git a/test_assets/1-luanda-drive.html b/test_assets/1-luanda-drive.html
index da9eeee..d8a3fe7 100644
--- a/test_assets/1-luanda-drive.html
+++ b/test_assets/1-luanda-drive.html
@@ -1,29 +1,29 @@
-
Your collection day Skip to main content
Ngā kōrero kohinga mōu Your collection day 1 Luanda Drive Ranui, Auckland 0612 Your next collection dates
Rubbish: Tuesday, 18 November
Food scraps: Tuesday, 18 November
Recycling: Tuesday, 25 November
Put bins out the night before or before 7am.
Where you can put your rubbish, food scraps and recycling for collection Household rubbish Put your rubbish bin out on the kerbside (not on the footpath or road) before 7am on your collection day.
Food scraps Put your food scraps bin on the kerbside before 7am on your collection day, or the night before.
Lock your food scraps bin by placing the black handle in upright position. Put your food scraps bins next to your rubbish and recycling bins with enough space for our collection trucks to safely empty bins.
If you share the berm with your neighbours, you should place the food scraps bin in a cluster or group. For more information, see How to use your food scraps bin .
Household recycling We only collect recycling from our official yellow-lidded green-bodied wheelie bins.
Put your recycling bin out on the kerbside (not on the footpath or road) before 7am on your collection day.
The bin is the property of Auckland Council and needs to stay with this property if you move.
These bins cannot be used for commercial quantities of recycling.
Commercial rubbish Put your rubbish bin out on the kerbside (not on the footpath or road) before 7am on your collection day.
Commercial recycling All properties are supplied with one yellow-lidded green-bodied recycling bin for household recycling collections.
Put your recycling bin out on the kerbside (not on the footpath or road) before 7am on your collection day.
The bin is the property of Auckland Council and needs to stay with this property if you move.
These bins cannot be used for commercial quantities of recycling.
\ No newline at end of file
diff --git a/test_assets/500-queen-street.html b/test_assets/500-queen-street.html
index 2605d12..98f4085 100644
--- a/test_assets/500-queen-street.html
+++ b/test_assets/500-queen-street.html
@@ -1,4 +1,4 @@
-Your collection day Skip to main content
Ngā kōrero kohinga mōu Your collection day 500 Queen Street Auckland Central, Auckland 1010 Your next collection dates
Rubbish: Saturday, 15 November
Food scraps:
Recycling: Saturday, 15 November
Put bags out before collection times: Monday to Saturday, 5pm to 5.30pm and 12am to 4am Sunday after 12am only
Where you can put your rubbish, food scraps and recycling for collection Household rubbish Put your rubbish in council supplied orange rubbish bags on the kerbside just before your collection time.
Properties in the inner CBD are supplied with 52 orange rubbish bags every six months.
Food scraps This property is listed as out of food scraps service area and will not receive collection service.
Household recycling Put all recycling on the kerb just before your collection time.
Properties in the inner CBD are supplied with 78 clear recycling bags every six months.
Paper and cardboard Paper Put paper in council supplied clear recycling bags. This includes:
newspaper mail magazines receipts office paperTetra Pak cartons. The bag may indicate a different message but will change when new bags are made.
Cardboard Put cardboard separate from the recycling bag. It should be bound or stacked together.
General recycling Put all non-cardboard recycling in the clear recycling bag.
Commercial rubbish Put your rubbish in council supplied orange rubbish bags on the kerbside just before your collection time.
Properties in the inner CBD are supplied with 52 orange rubbish bags every six months.
Commercial recycling Put all recycling on the kerb just before your collection time.
Properties in the inner CBD are supplied with 156 clear recycling bags annually at 6 monthly intervals.
Paper and cardboard Paper Put paper in the clear recycling bag. This includes:
newspaper mail magazines receipts office paperTetra Pak cartons. The bag may indicate a different message but will change when new bags are made.
Cardboard Put cardboard separate from the recycling bag. It should be bound or stacked together.
General recycling Put all non-cardboard recycling in the clear recycling bag.
\ No newline at end of file