feat: init client

This commit is contained in:
2025-08-12 18:38:22 +02:00
commit a145da0d2d
24 changed files with 713 additions and 0 deletions

43
.golangci.yml Normal file
View File

@@ -0,0 +1,43 @@
version: "2"
linters:
default: all
disable:
- wsl # Disable the default wsl linter due to deprecated status
- exhaustruct
- gochecknoglobals
- godox
- gomoddirectives
- ireturn
- testpackage
- wrapcheck
enable:
- wsl_v5
settings:
depguard:
rules:
main:
allow:
- tcgdex-golang
list-mode: lax
wsl_v5:
allow-first-in-block: true
allow-whole-block: false
branch-max-lines: 2
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gci
- gofmt
- gofumpt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$

19
Makefile Normal file
View File

@@ -0,0 +1,19 @@
.PHONY: vendor
vendor:
go mod tidy -v
go mod vendor
.PHONY: test
test:
go test -mod vendor -race -coverprofile coverage.out -gcflags=-l -v ./...
.PHONY: fmt
fmt:
gofumpt -l -w .
.PHONY: lint
lint:
golangci-lint run
.PHONY: check-all
check-all: vendor fmt lint test

40
client/cards.go Normal file
View File

@@ -0,0 +1,40 @@
package client
import (
"context"
"net/http"
"github.com/kratisto/tcgdex-golang/models"
)
// GetCard retrieves a specific card by its ID.
// This function is used to get detailed information about a specific card.
func (s *tcgDexClient) GetCard(ctx context.Context, id string) (*models.Card, error) {
request, err := http.NewRequestWithContext(ctx, http.MethodGet, s.baseURL+"/cards/"+id, nil)
if err != nil {
return nil, err
}
card, err := doRequest[*models.Card](s.httpClient, request)
if err != nil {
return nil, err
}
return card, nil
}
// Cards retrieves all cards.
// This function returns a list of all cards available in the Pokémon TCG database.
func (s *tcgDexClient) Cards(ctx context.Context) ([]*models.Card, error) {
request, err := http.NewRequestWithContext(ctx, http.MethodGet, s.baseURL+"/cards", nil)
if err != nil {
return nil, err
}
cards, err := doRequest[[]*models.Card](s.httpClient, request)
if err != nil {
return nil, err
}
return cards, nil
}

95
client/client.go Normal file
View File

@@ -0,0 +1,95 @@
// Package client provides a client for interacting with the Pokémon TCG database.
package client
import (
"context"
"encoding/json"
"net/http"
"github.com/kratisto/tcgdex-golang/models"
)
const (
defaultURL = "https://api.tcgdex.net/v2/fr"
defaultLanguage = "en"
)
// TCGDexClient is the interface for interacting with the Pokémon TCG database.
type TCGDexClient interface {
CardsClient
SeriesClient
SetsClient
}
// CardsClient is the interface for card-related operations.
type CardsClient interface {
GetCard(ctx context.Context, id string) (*models.Card, error)
Cards(ctx context.Context) ([]*models.Card, error)
}
// SeriesClient is the interface for series-related operations.
type SeriesClient interface {
Series(ctx context.Context) ([]*models.Serie, error)
GetSerie(ctx context.Context, seriesID string) (*models.Serie, error)
}
// SetsClient is the interface for set-related operations.
type SetsClient interface {
Sets(ctx context.Context) ([]*models.Set, error)
GetSet(ctx context.Context, setID string) (*models.Set, error)
GetCardOfSet(ctx context.Context, setID string, cardID string) (*models.Card, error)
}
type tcgDexClient struct {
CardsClient
SeriesClient
SetsClient
baseURL string
language string
httpClient *http.Client
}
// NewClient creates a new TCGDexClient with the default http client.
func NewClient(baseURL string, language string) TCGDexClient {
return &tcgDexClient{
baseURL: baseURL,
language: language,
httpClient: http.DefaultClient,
}
}
// NewClientWithCustomHTTPClient creates a new TCGDexClient with a custom HTTP client.
// This allows for more control over the HTTP requests, such as setting timeouts or custom headers.
func NewClientWithCustomHTTPClient(url string, language string, client *http.Client) TCGDexClient {
return &tcgDexClient{
baseURL: url,
language: language,
httpClient: client,
}
}
func doRequest[T any](client *http.Client, request *http.Request) (T, error) {
var result T
resp, err := client.Do(request)
if err != nil {
return result, err
}
defer func() {
err := resp.Body.Close()
if err != nil {
panic(err)
}
}()
jsonDecoder := json.NewDecoder(resp.Body)
err = jsonDecoder.Decode(&result)
if err != nil {
return result, err
}
return result, nil
}

61
client/client_builder.go Normal file
View File

@@ -0,0 +1,61 @@
package client
import "net/http"
// Builder is a builder for creating a TCGDexClient with customizable options.
type Builder struct {
language *string
baseURL *string
httpClient *http.Client
}
// NewBuilder creates a new Builder instance.
// This allows for fluent configuration of the TCGDexClient.
func NewBuilder() *Builder {
return &Builder{}
}
// Language sets the language for the TCGDexClient.
func (b *Builder) Language(language string) *Builder {
b.language = &language
return b
}
// BaseURL sets the base URL for the TCGDexClient.
func (b *Builder) BaseURL(baseURL string) *Builder {
b.baseURL = &baseURL
return b
}
// HTTPClient sets the custom HTTP client for the TCGDexClient.
func (b *Builder) HTTPClient(client *http.Client) *Builder {
b.httpClient = client
return b
}
// Builder constructs the TCGDexClient with the specified options.
func (b *Builder) Builder() TCGDexClient {
httpClient := b.httpClient
if httpClient == nil {
httpClient = http.DefaultClient
}
language := b.language
if language == nil {
language = ptr(defaultLanguage)
}
baseURL := b.baseURL
if baseURL == nil {
baseURL = ptr(defaultURL)
}
return NewClientWithCustomHTTPClient(*baseURL, *language, httpClient)
}
func ptr[T any](s T) *T {
return &s
}

40
client/series.go Normal file
View File

@@ -0,0 +1,40 @@
package client
import (
"context"
"net/http"
"github.com/kratisto/tcgdex-golang/models"
)
// Series retrieves all series.
// This function returns a list of all series available in the Pokémon TCG database.
func (s *tcgDexClient) Series(ctx context.Context) ([]*models.Serie, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, s.baseURL+"/series", nil)
if err != nil {
return nil, err
}
series, err := doRequest[[]*models.Serie](s.httpClient, req)
if err != nil {
return nil, err
}
return series, nil
}
// GetSerie retrieves a specific serie by its ID.
// This function is used to get detailed information about a specific series.
func (s *tcgDexClient) GetSerie(ctx context.Context, seriesID string) (*models.Serie, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, s.baseURL+"/series/"+seriesID, nil)
if err != nil {
return nil, err
}
serie, err := doRequest[*models.Serie](s.httpClient, req)
if err != nil {
return nil, err
}
return serie, nil
}

55
client/sets.go Normal file
View File

@@ -0,0 +1,55 @@
package client
import (
"context"
"net/http"
"github.com/kratisto/tcgdex-golang/models"
)
// Sets retrieves all sets.
// This function returns a list of all sets available in the Pokémon TCG database.
func (s *tcgDexClient) Sets(ctx context.Context) ([]*models.Set, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, s.baseURL+"/sets", nil)
if err != nil {
return nil, err
}
sets, err := doRequest[[]*models.Set](s.httpClient, req)
if err != nil {
return nil, err
}
return sets, nil
}
// GetSet retrieves a specific set by its ID.
func (s *tcgDexClient) GetSet(ctx context.Context, setID string) (*models.Set, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, s.baseURL+"/sets/"+setID, nil)
if err != nil {
return nil, err
}
set, err := doRequest[*models.Set](s.httpClient, req)
if err != nil {
return nil, err
}
return set, nil
}
// GetCardOfSet retrieves a specific card from a set by its ID.
// This function is used to get a card that belongs to a specific set.
func (s *tcgDexClient) GetCardOfSet(ctx context.Context, setID string, cardID string) (*models.Card, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, s.baseURL+"/sets/"+setID+"/cards/"+cardID, nil)
if err != nil {
return nil, err
}
card, err := doRequest[*models.Card](s.httpClient, req)
if err != nil {
return nil, err
}
return card, nil
}

58
coverage.out Normal file
View File

@@ -0,0 +1,58 @@
mode: atomic
github.com/kratisto/tcgdex-golang/client/cards.go:12.86,14.16 2 0
github.com/kratisto/tcgdex-golang/client/cards.go:14.16,16.3 1 0
github.com/kratisto/tcgdex-golang/client/cards.go:18.2,19.16 2 0
github.com/kratisto/tcgdex-golang/client/cards.go:19.16,21.3 1 0
github.com/kratisto/tcgdex-golang/client/cards.go:23.2,23.18 1 0
github.com/kratisto/tcgdex-golang/client/cards.go:28.75,30.16 2 0
github.com/kratisto/tcgdex-golang/client/cards.go:30.16,32.3 1 0
github.com/kratisto/tcgdex-golang/client/cards.go:34.2,35.16 2 0
github.com/kratisto/tcgdex-golang/client/cards.go:35.16,37.3 1 0
github.com/kratisto/tcgdex-golang/client/cards.go:39.2,39.19 1 0
github.com/kratisto/tcgdex-golang/client/client.go:54.62,60.2 1 0
github.com/kratisto/tcgdex-golang/client/client.go:64.99,70.2 1 0
github.com/kratisto/tcgdex-golang/client/client.go:72.78,76.16 3 0
github.com/kratisto/tcgdex-golang/client/client.go:76.16,78.3 1 0
github.com/kratisto/tcgdex-golang/client/client.go:80.2,80.15 1 0
github.com/kratisto/tcgdex-golang/client/client.go:80.15,82.17 2 0
github.com/kratisto/tcgdex-golang/client/client.go:82.17,83.14 1 0
github.com/kratisto/tcgdex-golang/client/client.go:87.2,90.16 3 0
github.com/kratisto/tcgdex-golang/client/client.go:90.16,92.3 1 0
github.com/kratisto/tcgdex-golang/client/client.go:94.2,94.20 1 0
github.com/kratisto/tcgdex-golang/client/client_builder.go:14.28,16.2 1 0
github.com/kratisto/tcgdex-golang/client/client_builder.go:19.54,23.2 2 0
github.com/kratisto/tcgdex-golang/client/client_builder.go:26.52,30.2 2 0
github.com/kratisto/tcgdex-golang/client/client_builder.go:33.60,37.2 2 0
github.com/kratisto/tcgdex-golang/client/client_builder.go:40.42,42.23 2 0
github.com/kratisto/tcgdex-golang/client/client_builder.go:42.23,44.3 1 0
github.com/kratisto/tcgdex-golang/client/client_builder.go:46.2,47.21 2 0
github.com/kratisto/tcgdex-golang/client/client_builder.go:47.21,49.3 1 0
github.com/kratisto/tcgdex-golang/client/client_builder.go:51.2,52.20 2 0
github.com/kratisto/tcgdex-golang/client/client_builder.go:52.20,54.3 1 0
github.com/kratisto/tcgdex-golang/client/client_builder.go:56.2,56.71 1 0
github.com/kratisto/tcgdex-golang/client/client_builder.go:59.25,61.2 1 0
github.com/kratisto/tcgdex-golang/client/series.go:12.77,14.16 2 0
github.com/kratisto/tcgdex-golang/client/series.go:14.16,16.3 1 0
github.com/kratisto/tcgdex-golang/client/series.go:18.2,19.16 2 0
github.com/kratisto/tcgdex-golang/client/series.go:19.16,21.3 1 0
github.com/kratisto/tcgdex-golang/client/series.go:23.2,23.20 1 0
github.com/kratisto/tcgdex-golang/client/series.go:28.94,30.16 2 0
github.com/kratisto/tcgdex-golang/client/series.go:30.16,32.3 1 0
github.com/kratisto/tcgdex-golang/client/series.go:34.2,35.16 2 0
github.com/kratisto/tcgdex-golang/client/series.go:35.16,37.3 1 0
github.com/kratisto/tcgdex-golang/client/series.go:39.2,39.19 1 0
github.com/kratisto/tcgdex-golang/client/sets.go:12.73,14.16 2 0
github.com/kratisto/tcgdex-golang/client/sets.go:14.16,16.3 1 0
github.com/kratisto/tcgdex-golang/client/sets.go:18.2,19.16 2 0
github.com/kratisto/tcgdex-golang/client/sets.go:19.16,21.3 1 0
github.com/kratisto/tcgdex-golang/client/sets.go:23.2,23.18 1 0
github.com/kratisto/tcgdex-golang/client/sets.go:27.87,29.16 2 0
github.com/kratisto/tcgdex-golang/client/sets.go:29.16,31.3 1 0
github.com/kratisto/tcgdex-golang/client/sets.go:33.2,34.16 2 0
github.com/kratisto/tcgdex-golang/client/sets.go:34.16,36.3 1 0
github.com/kratisto/tcgdex-golang/client/sets.go:38.2,38.17 1 0
github.com/kratisto/tcgdex-golang/client/sets.go:43.109,45.16 2 0
github.com/kratisto/tcgdex-golang/client/sets.go:45.16,47.3 1 0
github.com/kratisto/tcgdex-golang/client/sets.go:49.2,50.16 2 0
github.com/kratisto/tcgdex-golang/client/sets.go:50.16,52.3 1 0
github.com/kratisto/tcgdex-golang/client/sets.go:54.2,54.18 1 0

3
go.mod Normal file
View File

@@ -0,0 +1,3 @@
module github.com/kratisto/tcgdex-golang
go 1.24

0
go.sum Normal file
View File

88
models/card.go Normal file
View File

@@ -0,0 +1,88 @@
package models
// Card contains every informations about a specific card.
type Card struct {
// ID Globally unique card ID based on the set ID and the cards ID within the set.
ID string `json:"id"`
// LocalID indexing this card within its set, usually just its number.
LocalID string `json:"localId"`
// Name is the card name
Name string `json:"name"`
// Image url without the extension and quality.
Image *string `json:"image"`
// Illustrator of the card.
Illustrator *string `json:"illustrator"`
// Rarity of the card.
Rarity string `json:"rarity"`
// Category of the card.
Category string `json:"category"`
// Variants possible card variants
Variants *CardVariant `json:"variants"`
// Set the card belongs to.
Set SetResume `json:"set"`
// DexID Pokémon Pokédex IDs (multiple if multiple pokémon appears on the card).
DexID []int `json:"dexId"`
// Hp of the pokemon
Hp int `json:"hp"`
// Types of the pokemon.
Types []string `json:"types"`
// EvolveFrom Name of the pokemon this one evolves from.
EvolveFrom *string `json:"evolveFrom"`
// Description of Pokémon like in Pokédex
Description *string `json:"description"`
// Level of the Pokémon.
Level *string `json:"level"`
// Stage of the Pokémon.
Stage *string `json:"stage"`
// Suffix of the Pokémon.
Suffix *string `json:"suffix"`
// Item the Pokémon have.
Item CardItem `json:"item"`
// Abilities of the card.
Abilities []CardAbility `json:"abilities"`
// Attacks of the card.
Attacks []CardAttack `json:"attacks"`
// Weaknesses of the card.
Weaknesses []CardWeakResistance `json:"weaknesses"`
// Resistances of the card.
Resistances []CardWeakResistance `json:"resistances"`
// Retreat cost of the card.
Retreat int `json:"retreat"`
// Effect of the card.
Effect *string `json:"effect"`
// TrainerType ???.
TrainerType *string `json:"trainerType"`
// EnergyType of the card.
EnergyType *string `json:"energyType"`
// RegulationMark of the card.
RegulationMark *string `json:"regulationMark"`
// Legal card ability to be played in tournaments.
Legal Legal `json:"legal"`
}

13
models/card_ability.go Normal file
View File

@@ -0,0 +1,13 @@
package models
// CardAbility Describes a single ability of a pokemon.
type CardAbility struct {
// Ability type (language dependant).
Type string `json:"type"`
// Name of the ability.
Name string `json:"name"`
// Effect of the ability.
Effect string `json:"effect"`
}

16
models/card_attack.go Normal file
View File

@@ -0,0 +1,16 @@
package models
// CardAttack describes a single attack of a pokemon, for example 'Confuse Ray'.
type CardAttack struct {
// Name of the attack
Name string `json:"name"`
// Costs of the attack in the same order as listed on the card.
Costs []string `json:"cost"`
// Effect/Description of the attack, may be null for attacks without text.
Effect *string `json:"effect"`
// Damage the attack deals. May just be a number like '30', but can also be a multiplier like 'x20'.
Damage string `json:"damage"`
}

10
models/card_item.go Normal file
View File

@@ -0,0 +1,10 @@
package models
// CardItem represents an item.
type CardItem struct {
// Name of the item.
Name string `json:"name"`
// Effect of the item.
Effect string `json:"effect"`
}

16
models/card_resume.go Normal file
View File

@@ -0,0 +1,16 @@
package models
// CardResume contains basic informations about a specific card.
type CardResume struct {
// ID unique card ID based on the set ID and the cards ID within the set.
ID string `json:"id"`
// LocalID indexing this card within its set, usually just its number.
LocalID string `json:"localId"`
// Name of the card
Name string `json:"name"`
// Image url of the card without the extension and quality.
Image string `json:"image"`
}

19
models/card_variant.go Normal file
View File

@@ -0,0 +1,19 @@
package models
// CardVariant represents the possible variants of a card.
type CardVariant struct {
// Normal it's a basic card.
Normal bool `json:"normal"`
// Reverse the card have some shine behind colored content.
Reverse bool `json:"reverse"`
// Holo the card picture have some shine to it.
Holo bool `json:"holo"`
// FirstEdition the card contains a First Edition Stamp (only Base serie).
FirstEdition bool `json:"firstEdition"`
// WPromo The card has a wPromo stamp on it.
WPromo bool `json:"wPromo"`
}

View File

@@ -0,0 +1,10 @@
package models
// CardWeakResistance represent the weakeness or resistance of a card.
type CardWeakResistance struct {
// Type affected.
Type string `json:"type"`
// Value represents the multiplier but can be an number depending of the card.
Value string `json:"value"`
}

10
models/legal.go Normal file
View File

@@ -0,0 +1,10 @@
package models
// Legal informs about legality of the card in restricted tournament.
type Legal struct {
// Standard card usable is standard tournaments.
Standard bool `json:"standard"`
// Expanded card usable in expended tournament
Expanded bool `json:"expanded"`
}

19
models/serie.go Normal file
View File

@@ -0,0 +1,19 @@
// Package models defines the data structures used in the Pokémon TCG database.
package models
// Serie represent the Pokémon TCG serie.
type Serie struct {
/**
* the list of sets the Serie contains
*/
Sets []SetResume `json:"sets"`
// ID unique of the serie.
ID string `json:"id"`
// Name of the serie.
Name string `json:"name"`
// Logo of the Serie (basically also the first set logo).
Logo string `json:"logo"`
}

13
models/serie_resume.go Normal file
View File

@@ -0,0 +1,13 @@
package models
// SerieResume resume of the serie.
type SerieResume struct {
// ID of the serie.
ID string `json:"id"`
// Name of the serie.
Name string `json:"name"`
// Logo of the serie.
Logo string `json:"logo"`
}

34
models/set.go Normal file
View File

@@ -0,0 +1,34 @@
package models
// Set represents the set.
type Set struct {
// Id Globally unique set ID.
ID string `json:"id"`
// Name of the set.
Name string `json:"name"`
// Logo incomplete URL.
Logo string `json:"logo"`
// Symbol incomplete URL.
Symbol string `json:"symbol"`
// Serie which the set is a part.
Serie SerieResume `json:"serie"`
// TcgOnline code.
TcgOnline string `json:"tcgOnline"`
// ReleaseDate of the set (yyyy-mm-dd).
ReleaseDate string `json:"releaseDate"`
// Legal the set legality (won't indicate if a card is banned)
Legal Legal `json:"legal"`
// CardCount the number of card in the set
CardCount SetCardCount `json:"cardCount"`
// Cards contained in this set.
Cards []CardResume `json:"cards"`
}

22
models/set_card_count.go Normal file
View File

@@ -0,0 +1,22 @@
package models
// SetCardCount informations about the number of cards in the set.
type SetCardCount struct {
// Total of the number of cards.
Total int `json:"total"`
// Official is the number of cards officially (on the bottom of each cards).
Official int `json:"official"`
// Normal number of cards having a normal version.
Normal int `json:"normal"`
// Reverse number of cards having an reverse version.
Reverse int `json:"reverse"`
// Holo number of cards having an holo version.
Holo int `json:"holo"`
// FirstEd number of possible cards.
FirstEd int `json:"firstEd"`
}

View File

@@ -0,0 +1,10 @@
package models
// SetCardCountResume card count resume of the set.
type SetCardCountResume struct {
// Total of number of cards.
Total int `json:"total"`
// Official number of cards officially (on the bottom of each cards).
Official int `json:"official"`
}

19
models/set_resume.go Normal file
View File

@@ -0,0 +1,19 @@
package models
// SetResume resume of the set.
type SetResume struct {
// ID Globally unique set ID.
ID string
// Name of the set.
Name string
// Logo incomplete URL.
Logo string
// Symbol incomplete URL.
Symbol string
// CardCount number of card in the set.
CardCount SetCardCountResume
}