Files
go-yelp-fusion/yelp/yelp.go

174 lines
4.3 KiB
Go

package yelp
import (
"encoding/json"
"errors"
"net/http"
"net/url"
)
const (
rootURI = "https://api.yelp.com/"
businessArea = "/v3/businesses"
searchArea = "/v3/businesses/search"
)
var (
errUnspecifiedLocation = errors.New("location must be specified")
errBusinessNotFound = errors.New("business not found")
)
// AuthOptions provide keys required for using the Yelp API. Find more
// information here: https://www.yelp.com/developers/documentation/v3/authentication
type AuthOptions struct {
APIKey string // API Key from the yelp API access site.
}
// Client manages all searches. All searches are performed from an instance of a client.
// It is the top level object used to perform a search or business query. C
type Client struct {
Options *AuthOptions
Client *http.Client
}
// DoSimpleSearch performs a simple search with a term and location.
func (client *Client) DoSimpleSearch(term, location string) (result SearchResult, err error) {
// verify the term and location are not empty
if location == "" {
return SearchResult{}, errUnspecifiedLocation
}
// set up the query options
params := map[string]string{
"term": term,
"location": location,
}
// perform the search request
_, err = client.makeRequest(searchArea, "", params, &result)
if err != nil {
return SearchResult{}, err
}
return result, nil
}
// DoSearch performs a complex search with full search options.
func (client *Client) DoSearch(options SearchOptions) (result SearchResult, err error) {
// get the options from the search provider
params, err := options.getParameters()
if err != nil {
return SearchResult{}, err
}
// perform the search request
_, err = client.makeRequest(searchArea, "", params, &result)
if err != nil {
return SearchResult{}, err
}
return result, nil
}
// GetBusiness obtains a single business by name.
func (client *Client) GetBusiness(name string) (result Business, err error) {
statusCode, err := client.makeRequest(businessArea, name, nil, &result)
if err != nil {
// At some point the Yelp API stopped reporting 404s for missing business names, and
// started reporting 400s :(
if statusCode == 400 || statusCode == 404 {
return Business{}, errBusinessNotFound
}
return Business{}, err
}
return result, nil
}
// makeRequest is an internal/private API used to make underlying requests to the Yelp API.
func (client *Client) makeRequest(area string, id string, params map[string]string, v interface{}) (statusCode int, err error) {
// get the base url
queryURI, err := url.Parse(rootURI)
if err != nil {
return 0, err
}
// add the type of request we're making (search|business)
queryURI.Path = area
if id != "" {
queryURI.Path += "/" + id
}
// Do request
request, err := http.NewRequest("GET", queryURI.String(), nil)
if err != nil {
return 0, err
}
request.Header.Add("Authorization", "Bearer "+client.Options.APIKey)
q := request.URL.Query()
if params["term"] != "" {
q.Add("term", params["term"])
}
if params["location"] != "" {
q.Add("location", params["location"])
}
if params["limit"] != "" {
q.Add("limit", params["limit"])
}
if params["offset"] != "" {
q.Add("offset", params["offset"])
}
if params["sortby"] != "" {
q.Add("sort_by", params["sortby"])
}
if params["categoryfilter"] != "" {
q.Add("category_filter", params["categoryfilter"])
}
if params["locale"] != "" {
q.Add("locale", params["locale"])
}
if params["longitude"] != "" {
q.Add("longitude", params["longitude"])
}
if params["latitude"] != "" {
q.Add("latitude", params["latitude"])
}
request.URL.RawQuery = q.Encode()
response, err := client.Client.Do(request)
if err != nil {
return 0, err
}
if err != nil {
if response != nil {
return response.StatusCode, err
}
return 500, err
}
// close the request when done
defer response.Body.Close()
// ensure the request returned a 200
if response.StatusCode != 200 {
return response.StatusCode, errors.New(response.Status)
}
err = json.NewDecoder(response.Body).Decode(v)
return response.StatusCode, err
}
// New will create a new yelp search client. All search operations should go through this API.
func New(options *AuthOptions, httpClient *http.Client) *Client {
if httpClient == nil {
httpClient = http.DefaultClient
}
return &Client{
Options: options,
Client: httpClient,
}
}