-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapi.go
64 lines (51 loc) · 1.35 KB
/
api.go
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
package quality
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"time"
)
// API is a thing that can return []Docs for a given information need.
type API interface {
Search(query InformationNeed) ([]Doc, error)
}
// HTTPAPI concrete Api implementation.
type HTTPAPI struct {
Site string
Path string
Decoder HTTPAPIDecode
}
// HTTPAPIDecode
type HTTPAPIDecode func(json []byte) ([]Doc, error)
// Search an api with a given query.
func (api HTTPAPI) Search(q InformationNeed) ([]Doc, error) {
url := api.Site + fmt.Sprintf(api.Path, q.Kind, url.QueryEscape(q.Query))
start := time.Now()
resp, err := http.Get(url)
ms := time.Since(start)
if err != nil {
return []Doc{}, fmt.Errorf("query (%v, %v) failed: %v ", url, ms, err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return []Doc{}, fmt.Errorf("could not read body: %s", err)
}
if resp.StatusCode != http.StatusOK {
return []Doc{}, fmt.Errorf("%s (%v, %v): %s", url, resp.Status, ms, body)
}
docs, err := api.Decoder(body)
if err != nil {
return []Doc{}, fmt.Errorf("could not decode: %s")
}
return docs, nil
}
// search delegates to api.Search.
func search(api API, q InformationNeed) ([]Doc, error) {
docs, err := api.Search(q)
if err != nil {
return []Doc{}, fmt.Errorf("failed to search api: %s", err.Error())
}
return docs, err
}