diff --git a/internal/api/pokeapi/types.go b/internal/api/pokeapi/locationarea.go similarity index 84% rename from internal/api/pokeapi/types.go rename to internal/api/pokeapi/locationarea.go index bd3985c..c5e9c3c 100644 --- a/internal/api/pokeapi/types.go +++ b/internal/api/pokeapi/locationarea.go @@ -45,15 +45,3 @@ type Encounter struct { Chance int `json:"chance"` Method NamedAPIResource `json:"method"` } - -type NamedAPIResourceList struct { - Count int `json:"count"` - Next *string `json:"next"` - Previous *string `json:"previous"` - Results []NamedAPIResource `json:"results"` -} - -type NamedAPIResource struct { - Name string `json:"name"` - URL string `json:"url"` -} diff --git a/internal/api/pokeapi/namedapiresourcelist.go b/internal/api/pokeapi/namedapiresourcelist.go new file mode 100644 index 0000000..5526854 --- /dev/null +++ b/internal/api/pokeapi/namedapiresourcelist.go @@ -0,0 +1,13 @@ +package pokeapi + +type NamedAPIResourceList struct { + Count int `json:"count"` + Next *string `json:"next"` + Previous *string `json:"previous"` + Results []NamedAPIResource `json:"results"` +} + +type NamedAPIResource struct { + Name string `json:"name"` + URL string `json:"url"` +} diff --git a/internal/api/pokeapi/pokemon.go b/internal/api/pokeapi/pokemon.go new file mode 100644 index 0000000..de04240 --- /dev/null +++ b/internal/api/pokeapi/pokemon.go @@ -0,0 +1,87 @@ +package pokeapi + +type Pokemon struct { + ID int `json:"id"` + Name string `json:"name"` + BaseExperience int `json:"base_experience"` + Height int `json:"height"` + IsDefault bool `json:"is_default"` + Order int `json:"order"` + Weight int `json:"weight"` + Abilities []PokemonAbility `json:"abilities"` + Forms []NamedAPIResource `json:"forms"` + GameIndices []VersionGameIndex `json:"game_indices"` + HeldItems []PokemonHeldItems `json:"held_items"` + LocationAreaEncounters string `json:"location_area_encounters"` + Moves []PokemonMoves `json:"moves"` + PastTypes []PokemonTypePast `json:"past_types"` + Sprites PokemonSprites `json:"sprites"` + Cries PokemonCries `json:"cries"` + Species NamedAPIResource `json:"species"` + Stats []PokemonStat `json:"stats"` + Types []PokemonType `json:"types"` +} + +type PokemonAbility struct { + IsHidden bool `json:"is_hidden"` + Slot int `json:"slot"` + Ability NamedAPIResource `json:"ability"` +} + +type VersionGameIndex struct { + GameIndex int `json:"game_index"` + Version NamedAPIResource `json:"version"` +} + +type PokemonHeldItems struct { + Item NamedAPIResource `json:"item"` + VersionDetails []PokemonHeldItemVersion `json:"version_details"` +} + +type PokemonHeldItemVersion struct { + Version NamedAPIResource `json:"version"` + Rarity int `json:"rarity"` +} + +type PokemonMoves struct { + Move NamedAPIResource `json:"move"` + VersionGroupDetails []PokemonMoveVersion `json:"version_group_details"` +} + +type PokemonMoveVersion struct { + MoveLearnMethod NamedAPIResource `json:"move_learn_method"` + VersionGroup NamedAPIResource `json:"version_group"` + LevelLearnedAt int +} + +type PokemonTypePast struct { + Generation NamedAPIResource `json:"generation"` + Types PokemonType `json:"types"` +} + +type PokemonSprites struct { + FrontDefault string `json:"front_default"` + FrontShiny string `json:"front_shiny"` + FrontFemale string `json:"front_female"` + FrontShinyFemale string `json:"front_shiny_female"` + BackDefault string `json:"back_default"` + BackShiny string `json:"back_shiny"` + BackFemale string `json:"back_female"` + BackShinyFemale string `json:"back_shiny_female"` +} + +type PokemonCries struct { + Latest string `json:"latest"` + Legacy string `json:"legacy"` +} + +type PokemonStat struct { + Stat NamedAPIResource `json:"stat"` + Effort int `json:"effort"` + BaseStat int `json:"base_stat"` +} + +type PokemonType struct { + Slot int `json:"slot"` + Type NamedAPIResource `json:"type"` +} diff --git a/internal/pokeclient/pokeclient.go b/internal/pokeclient/pokeclient.go index 936ca40..9bbacb5 100644 --- a/internal/pokeclient/pokeclient.go +++ b/internal/pokeclient/pokeclient.go @@ -15,7 +15,8 @@ import ( const ( baseURL string = "https://pokeapi.co/api/v2" - LocationAreaEndpoint = baseURL + "/location-area" + LocationAreaPath = baseURL + "/location-area" + PokemonPath = baseURL + "/pokemon" ) type Client struct { @@ -93,7 +94,7 @@ func (c *Client) GetNamedAPIResourceList(url string) (pokeapi.NamedAPIResourceLi func (c *Client) GetLocationArea(location string) (pokeapi.LocationArea, error) { var locationArea pokeapi.LocationArea - url := LocationAreaEndpoint + "/" + location + "/" + url := LocationAreaPath + "/" + location + "/" dataFromCache, exists := c.cache.Get(url) if exists { @@ -146,6 +147,62 @@ func (c *Client) GetLocationArea(location string) (pokeapi.LocationArea, error) return locationArea, nil } +func (c *Client) GetPokemon(pokemonName string) (pokeapi.Pokemon, error) { + var pokemon pokeapi.Pokemon + + url := PokemonPath + "/" + pokemonName + "/" + + dataFromCache, exists := c.cache.Get(url) + if exists { + fmt.Println("Using data from cache.") + + if err := decodeJSON(dataFromCache, &pokemon); err != nil { + return pokeapi.Pokemon{}, fmt.Errorf("unable to decode the data from the cache: %w", err) + } + + return pokemon, nil + } + + ctx, cancel := context.WithTimeout(context.Background(), c.timeout) + defer cancel() + + request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return pokeapi.Pokemon{}, fmt.Errorf("error creating the HTTP request: %w", err) + } + + resp, err := c.httpClient.Do(request) + if err != nil { + return pokeapi.Pokemon{}, fmt.Errorf("error getting the response from the server: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode >= 400 { + return pokeapi.Pokemon{}, fmt.Errorf( + "received a bad status from %s: (%d) %s", + url, + resp.StatusCode, + resp.Status, + ) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return pokeapi.Pokemon{}, fmt.Errorf( + "unable to read the response from the server: %w", + err, + ) + } + + if err := decodeJSON(body, &pokemon); err != nil { + return pokeapi.Pokemon{}, fmt.Errorf("unable to decode the data from the server: %w", err) + } + + c.cache.Add(url, body) + + return pokemon, nil +} + func decodeJSON(data []byte, value any) error { if err := json.Unmarshal(data, value); err != nil { return fmt.Errorf("unable to decode the JSON data: %w", err)