// Package client provides a client for interacting with the Pokémon TCG database. package client import ( "context" "encoding/json" "errors" "net/http" "github.com/kratisto/tcgdex-golang/models" ) const ( defaultURL = "https://api.tcgdex.net/v2/fr" defaultLanguage = "en" ) var ( ErrNotFound = errors.New("not found") ) // FilterParams regroupe les paramètres de filtre pour les requêtes de ressources type FilterParams struct { Sort string Page int PageSize int } // TCGDexClient is the interface for interacting with the Pokémon TCG database. type TCGDexClient interface { CardsClient SeriesClient SetsClient CategoriesClient HPClient IllustratorsClient RaritiesClient RetreatsClient TypesClient DexIDsClient EnergyTypesClient RegulationMarksClient StagesClient } // CategoriesClient is the interface for category-related operations. type CategoriesClient interface { Categories(ctx context.Context) ([]string, error) GetCardsByCategory(ctx context.Context, category string, params *FilterParams) ([]models.Card, error) } // HPClient is the interface for HP-related operations. type HPClient interface { HPs(ctx context.Context) ([]string, error) GetCardsByHP(ctx context.Context, hp string, params *FilterParams) ([]models.Card, error) } // IllustratorsClient is the interface for illustrator-related operations. type IllustratorsClient interface { Illustrators(ctx context.Context) ([]string, error) GetCardsByIllustrator(ctx context.Context, illustrator string) ([]models.Card, error) } // RaritiesClient is the interface for rarity-related operations. type RaritiesClient interface { Rarities(ctx context.Context) ([]string, error) GetCardsByRarity(ctx context.Context, rarity string, params *FilterParams) ([]models.Card, error) } // RetreatsClient is the interface for retreat-related operations. type RetreatsClient interface { Retreats(ctx context.Context) ([]string, error) GetCardsByRetreat(ctx context.Context, retreat string, params *FilterParams) ([]models.Card, error) } // TypesClient is the interface for type-related operations. type TypesClient interface { Types(ctx context.Context) ([]string, error) GetCardsByType(ctx context.Context, typ string, params *FilterParams) ([]models.Card, error) } // DexIDsClient is the interface for dexid-related operations. type DexIDsClient interface { DexIDs(ctx context.Context) ([]int, error) GetCardsByDexID(ctx context.Context, dexID int) ([]models.Card, error) } // EnergyTypesClient is the interface for energy type-related operations. type EnergyTypesClient interface { EnergyTypes(ctx context.Context) ([]string, error) GetCardsByEnergyType(ctx context.Context, energyType string) ([]models.Card, error) } // RegulationMarksClient is the interface for regulation mark-related operations. type RegulationMarksClient interface { RegulationMarks(ctx context.Context) ([]string, error) GetCardsByRegulationMark(ctx context.Context, regulationMark string) ([]models.Card, error) } // StagesClient is the interface for stage-related operations. type StagesClient interface { Stages(ctx context.Context) ([]string, error) GetCardsByStage(ctx context.Context, stage string) ([]models.Card, error) } // 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 nil, err } defer func() { err := resp.Body.Close() if err != nil { panic(err) } }() if resp.StatusCode >= 400 && resp.StatusCode < 500 { if resp.StatusCode == http.StatusNotFound { return nil, ErrNotFound } return nil, errors.New(http.StatusText(resp.StatusCode)) } jsonDecoder := json.NewDecoder(resp.Body) err = jsonDecoder.Decode(&result) if err != nil { return nil, err } return &result, nil } func doRequestSlice[T any](client *http.Client, request *http.Request) ([]T, error) { var result []T resp, err := client.Do(request) if err != nil { return nil, err } defer func() { err := resp.Body.Close() if err != nil { panic(err) } }() if resp.StatusCode >= 400 && resp.StatusCode < 500 { if resp.StatusCode == http.StatusNotFound { return nil, ErrNotFound } return nil, errors.New(http.StatusText(resp.StatusCode)) } jsonDecoder := json.NewDecoder(resp.Body) err = jsonDecoder.Decode(&result) if err != nil { return nil, err } return result, nil }