-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathaddr.go
More file actions
97 lines (83 loc) · 2.5 KB
/
addr.go
File metadata and controls
97 lines (83 loc) · 2.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package aklapi
import (
"context"
"encoding/json"
"errors"
"log/slog"
"net/http"
"strconv"
"time"
)
var (
// defined as a variable so it can be overridden in tests.
addrURI = `https://experience.aucklandcouncil.govt.nz/nextapi/property`
// defined as a variable so tests can replace it.
addrHTTPClient = &http.Client{Timeout: 15 * time.Second, Transport: &browserTransport{wrapped: http.DefaultTransport}}
)
// AddrRequest is the address request.
type AddrRequest struct {
PageSize int
SearchText string
}
// Address is the address and its unique identifier (rate account key).
type Address struct {
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.ID + ")>"
}
// AddressLookup is a convenience function to get addresses.
func AddressLookup(ctx context.Context, addr string) (*AddrResponse, error) {
return MatchingPropertyAddresses(ctx, &AddrRequest{SearchText: addr, PageSize: 10})
}
// MatchingPropertyAddresses wrapper around the AKL Council API.
func MatchingPropertyAddresses(ctx context.Context, addrReq *AddrRequest) (*AddrResponse, error) {
cachedAr, ok := addrCache.Lookup(addrReq.SearchText)
if ok {
slog.DebugContext(ctx, "found cached address result", "addr", cachedAr)
return cachedAr, nil
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, 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 := addrHTTPClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
slog.DebugContext(ctx, "address call complete", "duration", 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)
var apiResp AddrResponse
if err := dec.Decode(&apiResp); err != nil {
return nil, err
}
addrCache.Add(addrReq.SearchText, &apiResp)
return &apiResp, nil
}
func oneAddress(ctx context.Context, addr string) (*Address, error) {
resp, err := AddressLookup(ctx, addr)
if err != nil {
return nil, err
}
// need exactly one address to continue
if len(resp.Items) != 1 {
return nil, errors.New("ambiguous or empty address results")
}
return &resp.Items[0], nil
}