Skip to content

Commit

Permalink
Merge pull request #1 from bshore/create-a-mock-client
Browse files Browse the repository at this point in the history
Create a mock client
  • Loading branch information
bshore authored Mar 2, 2022
2 parents 984cd2e + c9befbd commit c575af5
Show file tree
Hide file tree
Showing 23 changed files with 1,171 additions and 139 deletions.
34 changes: 30 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,38 @@

`go-hirez` is a Golang API Library for the Hi-Rez (Smite) developer API [PDF reference](https://docs.google.com/document/d/1OFS-3ocSx-1Rvg4afAnEHlT3917MAK_6eJTR6rzr-BM/edit)

## Getting Started
## Getting Started with Mocks

`go-hirez` offers a mocked version of the API that will generate response output.
You can use the mocked API to test functionality without adding to your daily API limit.

_Note: The only method that isn't mocked is `GetOrganizedMatchDetailsBatch`_

```go
package main

import (
mock "github.com/bshore/go-hirez/hirezapi_mock"
"github.com/bshore/go-hirez/models"
)

func main() {
client, err := mock.New("1234", "5678", models.URLSmitePC, models.ResponseTypeJSON)
client.StartSession()

client, err := mock.NewWithSession("1234", "5678", models.URLSmitePC, models.ResponseTypeJSON)
}
```

## Getting Started For Real

```go
package main

import "github.com/bshore/go-hirez/hirezapi"
import (
"github.com/bshore/go-hirez/hirezapi"
"github.com/bshore/go-hirez/models"
)

func main() {
// Recommend storing these as environment variables or secrets
Expand All @@ -16,11 +42,11 @@ func main() {

// NewWithSession is like New() but it also tests connectivity with `Ping()` and calls `CreateSession()`
// for you. This could be useful if you intend to query the API on some sort of schedule.
client, err := hirezapi.NewWithSession(devID, authKey, hirezapi.URLSmitePC, hirezapi.ResponseTypeJSON)
client, err := hirezapi.NewWithSession(devID, authKey, models.URLSmitePC, models.ResponseTypeJSON)

// New initializes a HiRezAPI instance with devID, auth key, url, and response type.
// Note: You will need to call `client.CreateSession()` on your own
client, err := hirezapi.New(devID, authKey, hirezapi.URLSmitePC, hirezapi.ResponseTypeJSON)
client, err := hirezapi.New(devID, authKey, models.URLSmitePC, models.ResponseTypeJSON)

// Direct struct initialization is supported, though the constructor methods are recommended since
// they avoid potential fail cases like typos in the BasePath or an unsuppored RespType
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module github.com/bshore/go-hirez

go 1.15
go 1.17
Empty file added go.sum
Empty file.
30 changes: 14 additions & 16 deletions hirezapi/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,40 @@ import (
"fmt"
"net/http"
"time"

"github.com/bshore/go-hirez/models"
)

// APIClient is the implementation of the HiRezAPI interface.
type APIClient struct {
DeveloperID string
AuthKey string
BasePath string
RespType string
SessionID string
DeveloperID string
AuthKey string
BasePath string
RespType string
SessionID string
SessionStamp string
}

// New initializes a HiRezAPI instance with devID, auth key, url, and response type.
func New(devID, key string, url MustBeURL, respType MustBeResponseType) (HiRezAPI, error) {
func New(devID, key, url, respType string) (HiRezAPI, error) {
if devID == "" {
return nil, errors.New(`must provide a developerID (eg, 1004)`)
}
if key == "" {
return nil, errors.New(`must provide an auth key (eg, 23DF3C7E9BD14D84BF892AD206B6755C)`)
}
api := &APIClient{
BasePath: url.String(),
RespType: respType.String(),
BasePath: url,
RespType: respType,
DeveloperID: devID,
AuthKey: key,
AuthKey: key,
}
return api, nil
}

// NewWithSession is like New() but it also tests connectivity with Ping and
// initializes a session for you.
func NewWithSession(devID, key string, url URL, respType MustBeResponseType) (HiRezAPI, error) {
func NewWithSession(devID, key, url, respType string) (HiRezAPI, error) {
api, err := New(devID, key, url, respType)
if err != nil {
return nil, err
Expand All @@ -66,19 +68,15 @@ func (a *APIClient) makeRequest(methodName, path string) (*http.Response, error)

// generateSignature takes in the requested methodName and generates an md5 hashed signature for sending a request
func (a *APIClient) generateSignature(methodName string) (string, string) {
utcNow := time.Now().UTC().Format(TimeFormat)
utcNow := time.Now().UTC().Format(models.TimeFormat)
sigStr := fmt.Sprintf("%s%s%s%s", a.DeveloperID, methodName, a.AuthKey, utcNow)
bs := []byte(sigStr)
return fmt.Sprintf("%x", md5.Sum(bs)), utcNow
}

func (a *APIClient) unmarshalResponse(b []byte, v interface{}) error {
if a.RespType == ResponseTypeXML.String() {
if a.RespType == models.ResponseTypeXML {
return xml.Unmarshal(b, v)
}
return json.Unmarshal(b, v)
}

func FormatTime(t time.Time) string {
return t.Format(TimeFormat)
}
12 changes: 6 additions & 6 deletions hirezapi/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (a *APIClient) CreateSession() error {
"%s/%s%s/%s/%s/%s",
a.BasePath,
"createsession",
ResponseTypeJSON.String(),
models.ResponseTypeJSON,
a.DeveloperID,
sig,
stamp,
Expand Down Expand Up @@ -103,12 +103,12 @@ func (a *APIClient) GetDataUsed() ([]models.DataUsed, error) {
}

// ChangeBasePath modifies the base path if you want to query a different platform.
func (a *APIClient) ChangeBasePath(url MustBeURL) {
a.BasePath = url.String()
func (a *APIClient) ChangeBasePath(url string) {
a.BasePath = url
a.CreateSession()
}

// ChangeResponseType modifies the response type if you want to switch between JSON and XML
func (a *APIClient) ChangeResponseType(respType MustBeResponseType) {
a.RespType = respType.String()
}
func (a *APIClient) ChangeResponseType(respType string) {
a.RespType = respType
}
21 changes: 11 additions & 10 deletions hirezapi/game.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ import (
"io/ioutil"

"github.com/bshore/go-hirez/models"
"github.com/bshore/go-hirez/utils"
)

// GetGods returns all Gods and their various attributes.
func (a *APIClient) GetGods(langCode string) ([]models.God, error) {
if !IsSmitePath(a.BasePath) {
return nil, fmt.Errorf("GetGods() %s", notSmiteErrMsg)
if !utils.IsSmitePath(a.BasePath) {
return nil, fmt.Errorf("GetGods() %s", utils.NotSmiteErrMsg)
}
if langCode == "" {
langCode = English
langCode = models.English
}
resp, err := a.makeRequest("getgods", langCode)
if err != nil {
Expand All @@ -31,11 +32,11 @@ func (a *APIClient) GetGods(langCode string) ([]models.God, error) {

// GetGodSkins returns all available skins for a particular God.
func (a *APIClient) GetGodSkins(godID int64, langCode string) ([]models.GodSkin, error) {
if !IsSmitePath(a.BasePath) {
return nil, fmt.Errorf("GetGodSkins() %s", notSmiteErrMsg)
if !utils.IsSmitePath(a.BasePath) {
return nil, fmt.Errorf("GetGodSkins() %s", utils.NotSmiteErrMsg)
}
if langCode == "" {
langCode = English
langCode = models.English
}
path := fmt.Sprintf("%d/%s", godID, langCode)
resp, err := a.makeRequest("getgodskins", path)
Expand All @@ -54,11 +55,11 @@ func (a *APIClient) GetGodSkins(godID int64, langCode string) ([]models.GodSkin,

// GetGodRecommendedItems returns the recommended items for a particular God.
func (a *APIClient) GetGodRecommendedItems(godID int64, langCode string) ([]models.GodRecommendedItem, error) {
if !IsSmitePath(a.BasePath) {
return nil, fmt.Errorf("GetGodRecommendedItems() %s", notSmiteErrMsg)
if !utils.IsSmitePath(a.BasePath) {
return nil, fmt.Errorf("GetGodRecommendedItems() %s", utils.NotSmiteErrMsg)
}
if langCode == "" {
langCode = English
langCode = models.English
}
path := fmt.Sprintf("%d/%s", godID, langCode)
resp, err := a.makeRequest("getgodrecommendeditems", path)
Expand All @@ -78,7 +79,7 @@ func (a *APIClient) GetGodRecommendedItems(godID int64, langCode string) ([]mode
// GetItems returns all items and their various attributes.
func (a *APIClient) GetItems(langCode string) ([]models.Item, error) {
if langCode == "" {
langCode = English
langCode = models.English
}
resp, err := a.makeRequest("getitems", langCode)
if err != nil {
Expand Down
10 changes: 5 additions & 5 deletions hirezapi/hirezapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ type HiRezAPI interface {
// GetDataUsed returns API Developer daily usage limits and the current status against those limits.
GetDataUsed() ([]models.DataUsed, error)
// ChangeBasePath modifies the base path if you want to query a different platform
ChangeBasePath(url MustBeURL)
ChangeBasePath(url string)
// ChangeResponseType modifies the response type if you want to switch between JSON and XML
ChangeResponseType(respType MustBeResponseType)
ChangeResponseType(respType string)

// ===== Player Related =====
// GetPlayer returns league and other high level data for a particular player.
Expand Down Expand Up @@ -66,8 +66,8 @@ type HiRezAPI interface {
GetMatchDetails(matchID string) ([]models.MatchPlayer, error)
/*GetMatchDetailsBatch returns the statistics for a particular set of completed matches. (limit batch query to 5-10 matchIDs)
- The actual Hi-Rez API does not automatically group the response by matchID.
- If you want the results to be grouped by matchID, use GetOrganizedMatchDetailsBatch() instead.
- The actual Hi-Rez API does not automatically group the response by matchID.
- If you want the results to be grouped by matchID, use GetOrganizedMatchDetailsBatch() instead.
*/
GetMatchDetailsBatch(matchIDs []string) ([]models.MatchPlayer, error)
// GetOrganizedMatchDetailsBatch is the same as GetMatchDetailsBatch(), except it groups the players by match.
Expand Down Expand Up @@ -119,4 +119,4 @@ type HiRezAPI interface {
GetChampionCards(champID, langCode string) ([]models.ChampionCard, error)
// GetBountyItems returns daily Bounty Item history for the past 6 months.
GetBountyItems() ([]models.BountyItem, error)
}
}
8 changes: 4 additions & 4 deletions hirezapi/matches.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ func (a *APIClient) GetMatchPlayerDetails(matchID string) ([]models.LiveMatchPla
}

/*GetMatchIDsByQueue lists all MatchIDs for a particular match queue.
- queueID can be referened by constants defined in this package (eg, hirezapi.ConquestRanked).
- date must be formatted/formattable by hirezapi.DateFormat (yyyyMMdd).
- hour may be "0" - "23" and optionally may contain a ten minute window separated by a comma (eg, "6,30").
- hour may also be "-1" to fetch the whole day, but may stall/fail due to the amount of data.
- queueID can be referened by constants defined in this package (eg, hirezapi.ConquestRanked).
- date must be formatted/formattable by hirezapi.DateFormat (yyyyMMdd).
- hour may be "0" - "23" and optionally may contain a ten minute window separated by a comma (eg, "6,30").
- hour may also be "-1" to fetch the whole day, but may stall/fail due to the amount of data.
*/
func (a *APIClient) GetMatchIDsByQueue(queueID, date, hour string) ([]models.Match, error) {
path := fmt.Sprintf("%s/%s/%s", queueID, date, hour)
Expand Down
25 changes: 13 additions & 12 deletions hirezapi/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io/ioutil"

"github.com/bshore/go-hirez/models"
"github.com/bshore/go-hirez/utils"
)

// GetESportsProLeagueDetails returns matchup info for each matchup of the current season. match_status = 1 - scheduled, 2 - in progress, 3 - complete
Expand All @@ -25,11 +26,11 @@ func (a *APIClient) GetESportsProLeagueDetails() ([]models.ESportsProLeagueDetai

// GetGodLeaderboard returns the current season's leaderboard for a god/queue. [SmiteAPI: only queues 440, 450, 451]
func (a *APIClient) GetGodLeaderboard(godID, queueID string) ([]models.GodLeaderboardEntry, error) {
if !IsSmitePath(a.BasePath) {
return nil, fmt.Errorf("GetGodLeaderboard() %s", notSmiteErrMsg)
if !utils.IsSmitePath(a.BasePath) {
return nil, fmt.Errorf("GetGodLeaderboard() %s", utils.NotSmiteErrMsg)
}
if IsNotRanked(queueID) {
return nil, fmt.Errorf("GetGodLeaderboard() %s", notRankedErrMsg)
if utils.IsNotRanked(queueID) {
return nil, fmt.Errorf("GetGodLeaderboard() %s", utils.NotRankedErrMsg)
}
path := fmt.Sprintf("%s/%s", godID, queueID)
resp, err := a.makeRequest("getgodleaderboard", path)
Expand All @@ -48,11 +49,11 @@ func (a *APIClient) GetGodLeaderboard(godID, queueID string) ([]models.GodLeader

// GetLeagueLeaderboard returns the top players for a particular league.
func (a *APIClient) GetLeagueLeaderboard(queueID, tier, round string) ([]models.LeagueLeaderboardEntry, error) {
if !IsSmitePath(a.BasePath) {
return nil, fmt.Errorf("GetLeageLeaderboard() %s", notSmiteErrMsg)
if !utils.IsSmitePath(a.BasePath) {
return nil, fmt.Errorf("GetLeageLeaderboard() %s", utils.NotSmiteErrMsg)
}
if IsNotRanked(queueID) {
return nil, fmt.Errorf("GetLeagueLeaderboard() %s", notRankedErrMsg)
if utils.IsNotRanked(queueID) {
return nil, fmt.Errorf("GetLeagueLeaderboard() %s", utils.NotRankedErrMsg)
}
path := fmt.Sprintf("%s/%s/%s", queueID, tier, round)
resp, err := a.makeRequest("getleagueleaderboard", path)
Expand All @@ -71,11 +72,11 @@ func (a *APIClient) GetLeagueLeaderboard(queueID, tier, round string) ([]models.

// GetLeageSeasons returns a list of seasons for a match queue.
func (a *APIClient) GetLeagueSeasons(queueID string) ([]models.Season, error) {
if !IsSmitePath(a.BasePath) {
return nil, fmt.Errorf("GetLeageSeasons() %s", notSmiteErrMsg)
if !utils.IsSmitePath(a.BasePath) {
return nil, fmt.Errorf("GetLeageSeasons() %s", utils.NotSmiteErrMsg)
}
if IsNotRanked(queueID) {
return nil, fmt.Errorf("GetLeagueSeasons() %s", notRankedErrMsg)
if utils.IsNotRanked(queueID) {
return nil, fmt.Errorf("GetLeagueSeasons() %s", utils.NotRankedErrMsg)
}
resp, err := a.makeRequest("getleagueseasons", queueID)
if err != nil {
Expand Down
Loading

0 comments on commit c575af5

Please sign in to comment.