Skip to content

Commit

Permalink
Implement getting channel mods and VIPs in GraphQL
Browse files Browse the repository at this point in the history
  • Loading branch information
adeithe committed Feb 13, 2021
1 parent 35b96ba commit bbb4520
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 85 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# go-twitch [![GoDoc](https://godoc.org/github.com/adeithe/go-twitch?status.svg)](https://godoc.org/github.com/adeithe/go-twitch) [![Go Report Card](https://goreportcard.com/badge/github.com/adeithe/go-twitch)](https://goreportcard.com/report/github.com/adeithe/go-twitch) [![CircleCI](https://circleci.com/gh/Adeithe/go-twitch/tree/master.svg?style=svg)](https://circleci.com/gh/Adeithe/go-twitch/tree/master)
# go-twitch [![GoDoc](https://godoc.org/github.com/Adeithe/go-twitch?status.svg)](https://godoc.org/github.com/Adeithe/go-twitch) [![Go Report Card](https://goreportcard.com/badge/github.com/Adeithe/go-twitch)](https://goreportcard.com/report/github.com/Adeithe/go-twitch) [![CircleCI](https://circleci.com/gh/Adeithe/go-twitch/tree/master.svg?style=svg)](https://circleci.com/gh/Adeithe/go-twitch/tree/master)

A complete interface for Twitch services.

Expand Down
158 changes: 116 additions & 42 deletions graphql/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,151 +50,225 @@ func (client Client) CustomMutation(mutation interface{}, vars map[string]interf

// IsUsernameAvailable returns true if the provided username is not taken on Twitch
func (client *Client) IsUsernameAvailable(username string) (bool, error) {
user := GQLUsernameAvailabilityQuery{}
query := GQLUsernameAvailabilityQuery{}
vars := map[string]interface{}{"username": graphql.String(username)}
err := client.CustomQuery(&user, vars)
return user.IsAvailable, err
err := client.CustomQuery(&query, vars)
return query.IsAvailable, err
}

// GetCurrentUser retrieves the current user based on the clients authentication token
func (client Client) GetCurrentUser() (*User, error) {
if len(client.bearer) < 1 {
return nil, ErrTokenNotSet
}
user := GQLCurrentUserQuery{}
err := client.CustomQuery(&user, nil)
return user.Data, err
query := GQLCurrentUserQuery{}
err := client.CustomQuery(&query, nil)
return query.Data, err
}

// GetUsersByID retrieves an array of users from Twitch based on their User IDs
func (client Client) GetUsersByID(ids ...string) ([]User, error) {
if len(ids) > 100 {
return []User{}, ErrTooManyArguments
}
users := GQLUserIDsQuery{}
query := GQLUserIDsQuery{}
vars := map[string]interface{}{"ids": toIDs(ids...)}
err := client.CustomQuery(&users, vars)
return users.Data, err
err := client.CustomQuery(&query, vars)
return query.Data, err
}

// GetUsersByLogin retrieves an array of users from Twitch based on their usernames
func (client Client) GetUsersByLogin(logins ...string) ([]User, error) {
if len(logins) > 100 {
return []User{}, ErrTooManyArguments
}
users := GQLUserLoginsQuery{}
query := GQLUserLoginsQuery{}
vars := map[string]interface{}{"logins": toStrings(logins...)}
err := client.CustomQuery(&users, vars)
return users.Data, err
err := client.CustomQuery(&query, vars)
return query.Data, err
}

// GetChannelsByID retrieves an array of channels from Twitch based on their IDs
func (client Client) GetChannelsByID(ids ...string) ([]Channel, error) {
if len(ids) > 100 {
return []Channel{}, ErrTooManyArguments
}
channels := GQLChannelIDsQuery{}
query := GQLChannelIDsQuery{}
vars := map[string]interface{}{"ids": toIDs(ids...)}
err := client.CustomQuery(&channels, vars)
return channels.Data, err
err := client.CustomQuery(&query, vars)
return query.Data, err
}

// GetChannelsByName retrieves an array of channels from Twitch based on their names
func (client Client) GetChannelsByName(names ...string) ([]Channel, error) {
if len(names) > 100 {
return []Channel{}, ErrTooManyArguments
}
channels := GQLChannelNamesQuery{}
query := GQLChannelNamesQuery{}
vars := map[string]interface{}{"names": toStrings(names...)}
err := client.CustomQuery(&channels, vars)
return channels.Data, err
err := client.CustomQuery(&query, vars)
return query.Data, err
}

// GetStreams retrieves data about streams available on Twitch
func (client Client) GetStreams(opts StreamQueryOpts) (*StreamsQuery, error) {
if opts.First < 1 || opts.First > 100 {
opts.First = 25
}
streams := GQLStreamsQuery{}
query := GQLStreamsQuery{}
vars := map[string]interface{}{
"first": graphql.Int(opts.First),
"after": opts.After,
"options": opts.Options,
}
err := client.CustomQuery(&streams, vars)
return streams.Data, err
err := client.CustomQuery(&query, vars)
return query.Data, err
}

// GetVideosByUser retrieves videos
func (client Client) GetVideosByUser(user User, opts VideoQueryOpts) (*UserVideosQuery, error) {
// GetVideos retrieves videos on Twitch
func (client Client) GetVideos(opts VideoQueryOpts) (*VideosQuery, error) {
if opts.First < 1 || opts.First > 100 {
opts.First = 25
}
videos := GQLUserVideosQuery{}
query := GQLVideosQuery{}
vars := map[string]interface{}{
"first": graphql.Int(opts.First),
"after": opts.After,
}
err := client.CustomQuery(&query, vars)
return query.Data, err
}

// GetVideosByChannel retrieves videos on Twitch based on the provided channel
func (client Client) GetVideosByChannel(channel Channel, opts VideoQueryOpts) (*VideosQuery, error) {
return client.GetVideosByUser(User{ID: channel.ID}, opts)
}

// GetVideosByUser retrieves videos on Twitch based on the provided user
func (client Client) GetVideosByUser(user User, opts VideoQueryOpts) (*VideosQuery, error) {
if opts.First < 1 || opts.First > 100 {
opts.First = 25
}
query := GQLUserVideosQuery{}
vars := map[string]interface{}{
"id": user.ID,
"first": graphql.Int(opts.First),
"after": opts.After,
}
err := client.CustomQuery(&videos, vars)
return videos.Data, err
err := client.CustomQuery(&query, vars)
if query.Data == nil {
return nil, err
}
return query.Data.Videos, err
}

// GetClip retrieves data about a clip available on Twitch
func (client Client) GetClip(slug string) (*Clip, error) {
clip := GQLClipQuery{}
// GetClipBySlug retrieves data about a clip available on Twitch by its slug
func (client Client) GetClipBySlug(slug string) (*Clip, error) {
query := GQLClipQuery{}
vars := map[string]interface{}{"slug": slug}
err := client.CustomQuery(&clip, vars)
return clip.Data, err
err := client.CustomQuery(&query, vars)
return query.Data, err
}

// GetGames retrieves data about games available on Twitch
func (client Client) GetGames(opts GameQueryOpts) (*GamesQuery, error) {
if opts.First < 1 || opts.First > 100 {
opts.First = 25
}
games := GQLGamesQuery{}
query := GQLGamesQuery{}
vars := map[string]interface{}{
"first": graphql.Int(opts.First),
"after": opts.After,
"options": opts.Options,
}
err := client.CustomQuery(&games, vars)
return games.Data, err
err := client.CustomQuery(&query, vars)
return query.Data, err
}

// GetFollowersForUser retrieves data about who follows the provided user on Twitch
func (client Client) GetFollowersForUser(user User, opts FollowOpts) (*FollowersQuery, error) {
func (client Client) GetFollowersForUser(user User, opts FollowQueryOpts) (*FollowersQuery, error) {
if user.ID == nil || len(fmt.Sprint(user.ID)) < 1 {
return nil, ErrInvalidArgument
}
if opts.First < 1 || opts.First > 100 {
opts.First = 25
}
followers := GQLFollowersQuery{}
query := GQLFollowersQuery{}
vars := map[string]interface{}{
"id": user.ID,
"first": graphql.Int(opts.First),
"after": opts.After,
}
err := client.CustomQuery(&followers, vars)
return followers.Data, err
err := client.CustomQuery(&query, vars)
if query.Data == nil {
return nil, err
}
return query.Data.Followers, err
}

// GetFollowersForChannel retrieves data about who follows the provided channel on Twitch
func (client Client) GetFollowersForChannel(channel Channel, opts FollowOpts) (*FollowersQuery, error) {
func (client Client) GetFollowersForChannel(channel Channel, opts FollowQueryOpts) (*FollowersQuery, error) {
if channel.ID == nil || len(fmt.Sprint(channel.ID)) < 1 {
return nil, ErrInvalidArgument
}
if opts.First < 1 || opts.First > 100 {
opts.First = 25
}
followers := GQLFollowersQuery{}
query := GQLFollowersQuery{}
vars := map[string]interface{}{
"id": channel.ID,
"first": graphql.Int(opts.First),
"after": opts.After,
}
err := client.CustomQuery(&followers, vars)
return followers.Data, err
err := client.CustomQuery(&query, vars)
if query.Data == nil {
return nil, err
}
return query.Data.Followers, err
}

// GetModsForChannel retrieves data about who is a moderator for the provided channel on Twitch
func (client Client) GetModsForChannel(channel Channel, opts ModsQueryOpts) (*ModsQuery, error) {
return client.GetModsForUser(User{ID: channel.ID}, opts)
}

// GetVIPsForChannel retrieves data about who is a VIP for the provided channel on Twitch
func (client Client) GetVIPsForChannel(channel Channel, opts VIPsQueryOpts) (*VIPsQuery, error) {
return client.GetVIPsForUser(User{ID: channel.ID}, opts)
}

// GetModsForUser retrieves data about who is a moderator for the provided user on Twitch
func (client Client) GetModsForUser(user User, opts ModsQueryOpts) (*ModsQuery, error) {
if user.ID == nil || len(fmt.Sprint(user.ID)) < 1 {
return nil, ErrInvalidArgument
}
if opts.First < 1 || opts.First > 100 {
opts.First = 25
}
query := GQLModsQuery{}
vars := map[string]interface{}{
"id": user.ID,
"first": graphql.Int(opts.First),
"after": opts.After,
}
err := client.CustomQuery(&query, vars)
return query.Data.Mods, err
}

// GetVIPsForUser retrieves data about who is a VIP for the provided user on Twitch
func (client Client) GetVIPsForUser(user User, opts VIPsQueryOpts) (*VIPsQuery, error) {
if user.ID == nil || len(fmt.Sprint(user.ID)) < 1 {
return nil, ErrInvalidArgument
}
if opts.First < 1 || opts.First > 100 {
opts.First = 25
}
query := GQLVIPsQuery{}
vars := map[string]interface{}{
"id": user.ID,
"first": graphql.Int(opts.First),
"after": opts.After,
}
err := client.CustomQuery(&query, vars)
return query.Data.VIPs, err
}
28 changes: 14 additions & 14 deletions graphql/graphql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func TestIsUsernameAvailable(t *testing.T) {

func TestQueryUsers(t *testing.T) {
gql := New()
if _, err := gql.GetFollowersForUser(User{}, FollowOpts{}); err == nil {
if _, err := gql.GetFollowersForUser(User{}, FollowQueryOpts{}); err == nil {
t.Fatalf("expected error did not occur")
}
users, err := gql.GetUsersByID("44322889")
Expand All @@ -92,14 +92,14 @@ func TestQueryUsers(t *testing.T) {
if len(users) != 1 {
t.Fatalf("expected: 1 got: %d", len(users))
}
if _, err := gql.GetFollowersForUser(users[0], FollowOpts{}); err != nil {
if _, err := gql.GetFollowersForUser(users[0], FollowQueryOpts{}); err != nil {
t.Fatal(err)
}
}

func TestQueryChannels(t *testing.T) {
gql := New()
if _, err := gql.GetFollowersForChannel(Channel{}, FollowOpts{}); err == nil {
if _, err := gql.GetFollowersForChannel(Channel{}, FollowQueryOpts{}); err == nil {
t.Fatalf("expected error did not occur")
}
channels, err := gql.GetChannelsByID("44322889")
Expand All @@ -116,39 +116,39 @@ func TestQueryChannels(t *testing.T) {
if len(channels) != 1 {
t.Fatalf("expected: 1 got: %d", len(channels))
}
if _, err := gql.GetFollowersForChannel(channels[0], FollowOpts{}); err != nil {
if _, err := gql.GetFollowersForChannel(channels[0], FollowQueryOpts{}); err != nil {
t.Fatal(err)
}
}

func TestQueryStreams(t *testing.T) {
gql := New()
streams, err := gql.GetStreams(StreamQueryOpts{})
data, err := gql.GetStreams(StreamQueryOpts{})
if err != nil {
t.Fatal(err)
}
if streams == nil {
if data == nil {
t.Fatal("streams query returned nil")
}
if len(streams.Data) < 1 {
t.Fatalf("expected at least 1 stream got %d", len(streams.Data))
if len(data.Streams) < 1 {
t.Fatalf("expected at least 1 stream got %d", len(data.Streams))
}
t.Logf("got %d streams", len(streams.Data))
t.Logf("got %d streams", len(data.Streams))
}

func TestQueryGames(t *testing.T) {
gql := New()
games, err := gql.GetGames(GameQueryOpts{})
data, err := gql.GetGames(GameQueryOpts{})
if err != nil {
t.Fatal(err)
}
if games == nil {
if data == nil {
t.Fatal("games query returned nil")
}
if len(games.Data) < 1 {
t.Fatalf("expected at least 1 game got %d", len(games.Data))
if len(data.Games) < 1 {
t.Fatalf("expected at least 1 game got %d", len(data.Games))
}
t.Logf("got %d games", len(games.Data))
t.Logf("got %d games", len(data.Games))
}

func TestAuthenticated(t *testing.T) {
Expand Down
16 changes: 14 additions & 2 deletions graphql/opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,20 @@ type GameOptions struct {
Tags []string
}

// FollowOpts stores various options for querying followers on Twitch
type FollowOpts struct {
// FollowQueryOpts stores various options for querying followers on Twitch
type FollowQueryOpts struct {
First int32
After Cursor
}

// ModsQueryOpts stores various options for querying mods on Twitch
type ModsQueryOpts struct {
First int32
After Cursor
}

// VIPsQueryOpts stores various options for querying vips on Twitch
type VIPsQueryOpts struct {
First int32
After Cursor
}
Loading

0 comments on commit bbb4520

Please sign in to comment.