A Golang client for the Challonge web API.
package main
import (
"fmt"
"time""
"github.com/claytonfinney/challonge-go"
)
func main() {
// Provide your API creds (use env variables!)
u := "YOUR_USERNAME"
k := "YOUR_API_KEY"
// Initialize the client
c := challonge.NewChallongeClient(u, k)
// Give the tournament a starting time
tme, err := time.Parse(time.RFC3339, "2020-05-13T19:45:07.000Z")
if err != nil {
panic(err)
}
trn := challonge.Tournament{challonge.TournamentKey{
Name: "challonge go api mock",
TournamentType: "single elimination",
Url: "challonge_go_api_mock",
Description: "testing a new api client for golang",
OpenSignup: false,
HoldThirdPlaceMatch: true,
Private: false,
StartAt: tme,
AcceptAttachments: true,
}}
ct, err := c.CreateTournament(&trn)
if err != nil {
panic(err)
}
fmt.Println(ct.Name) // challonge go api mock
}
The structure of Challonge's API responses are best served with promoted struct fields in Go. In the case of any GETs, you don't need to worry about the promoted fields.
t, _ := c.GetTournament("my_test_tournament")
// access the URL with t.Url instead of something like t.Tournament.Url,
// which would correspond to the json payload's t.tournament.url
fmt.Println(t.Url)
But when you create a new Go struct to send via POST or PUT, you need to use a nested struct that looks like the following:
trn := challonge.Tournament{challonge.TournamentKey{
Name: "My Test Tournament",
Url: "my_test_tournament",
}}
Time has to be formatted according to RFC3339. Challonge responses use a format of 2020-05-26T14:34:55.806-04:00
, so use this too with time.Parse()
!
Another small "quirk", is that everything is CamelCase for struct fields. Url
, not URL
.
Each nested struct is the name of the resource with Key
appended to the end. For Tournament
, TournamentKey
. For Match
, MatchKey
.
I dreaded making this package because the documentation for the Challonge API is a bit lacking, and it seems like any key in a response could be null at any given time. A commonly suggested way to tackle nullable JSON values in Go is to use pointers in the response. In my opinion, requiring the user to first check if the value is nil for each struct field they wish to process seemed ridiculous. Using omitempty seemed fine, but empty string and null are two different things, and Go doesn't really provide a way to differentiate between the two.
Thus, this package implements custom types with their own Unmarshal and Marshal functions implemented. When null JSON values are unmarshalled, they take on the value of its type constant defined in types.go
. For example, a JSON value that is null, but would otherwise be an integer, would be unmarshalled with the value -16487502. Obviously this leaves rooms for collisions, and this approach may not be suitable for more robust production code. But in the case of the Challonge API, you will effectively never be dealing with negative numbers in the first place. If you, or someone else inputs a score with a value of -16487502, I am no longer responsible for that field marshalling or unmarshalling as null
:).
This allows for easy null checks:
package main
import (
"fmt"
"github.com/claytonfinney/challonge-go"
)
func main() {
u := "YOUR_USERNAME"
k := "YOUR_API_KEY"
c := challonge.NewChallongeClient(u, k)
t, _ := c.GetTournament("my_test_tournament")
if challonge.IsNull(t.StartedAt) {
fmt.Println("A start time has not yet been set for this tournament.")
}
}
For the best examples of how to use all the various functions, refer to the example program provided in examples/, then the unit tests.
- You cannot add an actual file via the Match Attachments API, but you can still update the URL and description. Challonge throws a 500 when you try via curl or anything else.