Last active
March 1, 2019 22:25
-
-
Save gaucheph/5f269967b5b5383dababb41f429cbbc7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"github.com/imroc/req" | |
"log" | |
"os" | |
"time" | |
) | |
/* | |
# GOAL | |
Given a list of pokemon names, get that pokemon's details and details about | |
its first 3 abilities from the public Pokemon API at https://pokeapi.co/docs/. | |
- Individual pokemon details gathered from the /pokemon/:pokemonName endpoint | |
- Individual ability details gathered from the /abilities/:abilityName endpoint | |
These requests should be made in parallel with a final result being a | |
[]map[string]interface{} like: | |
[ | |
{ | |
"pokemon": { | |
"height": 123, | |
"name": "string" | |
... | |
}, | |
"abilities": [ | |
{ | |
"name": "string", | |
"type": "string", | |
"whatever": false | |
... | |
}, | |
... | |
] | |
}, | |
... | |
] | |
So it should kind of "fan out" per pokemon on their 3 abilities | |
/---> ability | |
pokemon ----> ability | |
\---> ability | |
/---> ability | |
pokemon ----> ability | |
\---> ability | |
/---> ability | |
pokemon ----> ability | |
\---> ability | |
Each of the 3 abilities for each pokemon should be gathered separately | |
so that only the abilities gleaned from each pokemon are included with | |
only that pokemon. | |
For example, if "bulbasaur" has an ability called "chlorophyll" that none | |
of the other pokemon have, it would be an error for the "chlorophyll" ability | |
to appear in another pokemon's "abilities" array. | |
*/ | |
type PokemonAbilities struct { | |
dataPokemon interface{} | |
dataAbilities []interface{} | |
} | |
func main() { | |
start := time.Now() | |
catchEmAll := []string{ | |
"incineroar", | |
"bulbasaur", | |
"ivysaur", | |
"pikachu", | |
"gengar", | |
"squirtle", | |
"charizard", | |
"psyduck", | |
"abra", | |
"pidgey", | |
} | |
cPokemonNeedingAbilities := make(chan interface{}) | |
totalPokemon := len(catchEmAll) | |
go func() { | |
for _, eachPokemon := range catchEmAll { | |
cPokemonNeedingAbilities <- getPokemon(eachPokemon) | |
} | |
}() | |
cPokemonAbilities := make(chan PokemonAbilities) | |
go func() { | |
for eachPokemonNeedingAbilities := range cPokemonNeedingAbilities { | |
abilitiesMapSlice := getPokemonAbilities(eachPokemonNeedingAbilities) | |
abilityNames := getPokemonAbilitiesNames(abilitiesMapSlice, 99) | |
totalNames := len(abilityNames) | |
cThisPokemonAbilitiesNames := make(chan string) | |
go func() { | |
for _, eachAbilityName := range abilityNames { | |
cThisPokemonAbilitiesNames <- eachAbilityName | |
} | |
}() | |
cThisPokemonAbilitiesMaps := make(chan interface{}) | |
go func() { | |
for eachAbilityName := range cThisPokemonAbilitiesNames { | |
cThisPokemonAbilitiesMaps <- getAbility(eachAbilityName) | |
} | |
}() | |
cAllAbilities := make(chan []interface{}) | |
go func() { | |
var allAbilities []interface{} | |
for len(allAbilities) != totalNames { | |
allAbilities = append(allAbilities, <-cThisPokemonAbilitiesMaps) | |
} | |
cAllAbilities <- allAbilities | |
}() | |
pokemonAbility := PokemonAbilities{ | |
eachPokemonNeedingAbilities, | |
<-cAllAbilities, | |
} | |
cPokemonAbilities <- pokemonAbility | |
} | |
}() | |
var pokemonAndAbilities []PokemonAbilities | |
for len(pokemonAndAbilities) != totalPokemon { | |
pokemonAndAbilities = append(pokemonAndAbilities, <-cPokemonAbilities) | |
} | |
fmt.Println(time.Since(start)) | |
fmt.Println(len(pokemonAndAbilities)) | |
for _, eachPokemonAbility := range pokemonAndAbilities { | |
fmt.Println("-----------------------------------------------") | |
fmt.Println("pokemon name: ") | |
fmt.Println("\t", eachPokemonAbility.dataPokemon.(map[string]interface{})["name"]) | |
fmt.Println("pokemon abilities: ") | |
for _, eachAbility := range eachPokemonAbility.dataAbilities { | |
abilityMap := eachAbility.(map[string]interface{}) | |
abilityId := abilityMap["id"] | |
abilityName := abilityMap["name"] | |
fmt.Println("\t", abilityId, abilityName) | |
} | |
fmt.Println("-----------------------------------------------") | |
} | |
} | |
// takes pokemon object returned by api and returns its "abilities" slice | |
func getPokemonAbilities(pokemon interface{}) []interface{} { | |
return pokemon.(map[string]interface{})["abilities"].([]interface{}) | |
} | |
// takes an abilities slice and returns a slice of their names | |
func getPokemonAbilitiesNames(pokemonAbilities []interface{}, limit int) []string { | |
// container for ability names | |
var pokemonAbilitiesNames []string | |
// determine if pokemon has less abilities than passed-in limit | |
var total int | |
if limit > len(pokemonAbilities) { | |
total = len(pokemonAbilities) | |
} else { | |
total = limit | |
} | |
// get abilities until desired total is reached | |
for i := 0; i < total; i++ { | |
abilityMap := pokemonAbilities[i].(map[string]interface{}) | |
abilityName := getAbilityNameFromAbilityMap(abilityMap) | |
pokemonAbilitiesNames = append(pokemonAbilitiesNames, abilityName) | |
} | |
// return array of ability names | |
return pokemonAbilitiesNames | |
} | |
// gets the name of an ability from an ability object | |
func getAbilityNameFromAbilityMap(abilityMap map[string]interface{}) string { | |
someAbilityIfc := abilityMap["ability"].(map[string]interface{}) | |
someAbilityName := someAbilityIfc["name"].(string) | |
log.Println("found ability name: " + someAbilityName) | |
return someAbilityName | |
} | |
// makes http requests and exits if any problems occur like timeouts or json decode errors | |
func jsonRequestHandler(url string) interface{} { | |
response, e := req.Get(url) | |
if e != nil { | |
// making request failed | |
log.Fatal(e) | |
os.Exit(1) | |
} | |
var bodyJson interface{} | |
notOk := response.ToJSON(&bodyJson) | |
if notOk != nil { | |
// decoding body content to JSON failed | |
log.Fatal(notOk) | |
os.Exit(1) | |
} | |
return bodyJson | |
} | |
const BaseUrl = "https://pokeapi.co/api/v2" | |
// gets a pokemon from the api using its name | |
func getPokemon(pokemonName string) interface{} { | |
log.Println("getting pokemon: " + pokemonName) | |
url := BaseUrl + "/pokemon/" + pokemonName | |
thisPokemon := jsonRequestHandler(url) | |
log.Println("got pokemon: " + pokemonName) | |
return thisPokemon | |
} | |
// gets an ability from the api using the ability's name | |
func getAbility(abilityName string) interface{} { | |
log.Println("getting ability: " + abilityName) | |
url := BaseUrl + "/ability/" + abilityName | |
thisAbility := jsonRequestHandler(url) | |
log.Println("got ability: " + abilityName) | |
return thisAbility | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment