Last active
November 1, 2020 11:34
-
-
Save RicardoLinck/8be80ba51534861ed079fcd5417f25f4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package fetch | |
import ( | |
"encoding/json" | |
"errors" | |
"io" | |
"math" | |
"net/http" | |
"sort" | |
"time" | |
) | |
// ErrInvalidAPIVersion represent the error for invalid api version | |
var ErrInvalidAPIVersion = errors.New("invalid api version") | |
// Configuration contain parameters to call the api | |
type Configuration struct { | |
baseURL string | |
apiVersion int | |
fetcher fetcher | |
} | |
// NewConfiguration return a new Configuration struct based on provided parameters | |
func NewConfiguration(baseURL string, apiVersion int) Configuration { | |
return Configuration{ | |
baseURL: baseURL, | |
apiVersion: apiVersion, | |
} | |
} | |
// Person unifies responses from both api version | |
type Person struct { | |
Name string | |
Age int | |
Sports []string | |
} | |
type personAPIv1 struct { | |
Name string `json:"user_name"` | |
DateOfBirth time.Time `json:"dob"` | |
Sports []sportAPIv1 `json:"fav_sports"` | |
} | |
type sportAPIv1 struct { | |
Name string `json:"name"` | |
Order int `json:"order"` | |
} | |
type personAPIv2 struct { | |
Name string `json:"name"` | |
Age int `json:"age"` | |
Sports []string `json:"sports"` | |
} | |
func getEndpointAndDecodeFunc(version int) (string, func(reader io.Reader) (Person, error), error) { | |
switch version { | |
case 1: | |
return "/api/v1/some-data", decodeAndMapv1, nil | |
case 2: | |
return "/api/v2/data", decodeAndMapv2, nil | |
default: | |
return "", nil, ErrInvalidAPIVersion | |
} | |
} | |
type fetcher interface { | |
fetch(url string) (io.ReadCloser, error) | |
} | |
type httpFetcher struct{} | |
func (h httpFetcher) fetch(url string) (io.ReadCloser, error) { | |
response, err := http.DefaultClient.Get(url) | |
return response.Body, err | |
} | |
// FetchData fetches the data from the api using the configuration | |
func (c Configuration) FetchData() (Person, error) { | |
person := Person{} | |
endpoint, decoderFunc, err := getEndpointAndDecodeFunc(c.apiVersion) | |
if err != nil { | |
return person, err | |
} | |
response, err := c.fetcher.fetch(c.baseURL + endpoint) | |
if err != nil { | |
return person, err | |
} | |
defer response.Close() | |
return decoderFunc(response) | |
} | |
func decodeAndMapv1(reader io.Reader) (Person, error) { | |
personV1 := personAPIv1{} | |
person := Person{} | |
err := json.NewDecoder(reader).Decode(&personV1) | |
if err != nil { | |
return person, err | |
} | |
person.Name = personV1.Name | |
person.Age = int(math.Floor(time.Since(personV1.DateOfBirth).Hours() / 24 / 365)) | |
sort.Slice(personV1.Sports, func(i, j int) bool { | |
return personV1.Sports[i].Order < personV1.Sports[j].Order | |
}) | |
for _, sport := range personV1.Sports { | |
person.Sports = append(person.Sports, sport.Name) | |
} | |
return person, nil | |
} | |
func decodeAndMapv2(reader io.Reader) (Person, error) { | |
personV2 := personAPIv2{} | |
person := Person{} | |
err := json.NewDecoder(reader).Decode(&personV2) | |
if err != nil { | |
return person, err | |
} | |
person.Name = personV2.Name | |
person.Age = personV2.Age | |
person.Sports = personV2.Sports | |
return person, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment