Contributing to the Community: Hacktoberfest PR #4
Tags: opensource, typescript, hacktoberfest, python
Published: 2023-10-31 20:20:30

This is it, the final [issue](https://github.com/TheShiveshNetwork/Pokedex/issues/15) of Hacktoberfest 2023 and it's one that I made! So, since the last PR, I had a couple of ideas for the [repo](https://github.com/TheShiveshNetwork/Pokedex) that I was working on. Considering the last issue was all about the search functionality, I decided I wanted to create a more advanced search function. As noted in the issue I filed, I decided to add a generational filter for all the Pokemon, meaning Pokemon that appear in Generation 1 will only be visible, same with filtering by Generation 2, 3, etc... Which I figured would bring a lot more challenges this time around than the previous PR. So I got to work.

## Process

At first, I created a checkbox, but quickly realized checkboxes would not be nice if more filters were to ever be added. So I created a simple dropdown menu in `Home.jsx` and loaded it with the different Generations, 1-9. So now, I had to figure out a way of grabbing the Pokemon from all the different generations. I figured I would most likely have to use a req URL, so I began my implementation. While developing this feature I found out PokeAPI has a generations endpoint - `GET https://pokeapi.co/api/v2/generation/{id or name}/` - which displays the following data:

![GenEndpoint](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0c8pgvg7988hhj1doysi.png)

"This is great!" I thought, "This is just what I need to implement this!". As hindsight is 20/20 I know this is absolutely not the case for what I was going for. After countless nights of broken filters and multiple API calls, I was stuck. I decided to dial back my implementation, clearly what I was going for was too complex for the app to work flawlessly. So, I decided to create values for every dropdown item and make them the number of Pokemon added in that generation and the number of Pokemon that were previously available. After some simple filtering, it worked perfectly. A common problem of mine is trying to overcomplicate functional design which is why I was happy that the solution was so simple. 

## Wandering Mind

Then, my brain decided to wander off... "What if I added a filter that could sort Pokemon by each game and it would show the version exclusives present in each, the Pokemon added in that game including alternate forms, and the domestic Pokedex".

Well, I thought it would be really cool so I got to work. I once again added another dropdown this time filled with almost every mainline Pokemon game from red and blue to scarlet and violet. I also increased the API call from 1017 to 1292, which encompasses every single Pokemon that the PokeAPI has numbered which will come into play later. 

## Process Part 2

So after contemplating how something like this would be possible, I went to the documentation page for PokeAPI and went back to the generation endpoint. I noticed the version-group JSON object and figured this might be just what I needed to grab all the information about the Pokemon from each version. I realized at this point that I would most likely need to utilize Python in order to scrape the API for every single Pokedex, this is when I dug deeper and came across the region endpoint: 
`GET https://pokeapi.co/api/v2/region/{id or name}/`
which would produce `version-groups` of each game that features this pokedex entirely. 


![RegionEndpoint](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n2h4bi9ckenve0bwoc4t.png)

This was huge because it meant making an API scraper in Python would be so much easier, I would have to iterate a for loop 9 times grab the `version-group` data from the JSON response and add it to a JSON file. This also gave me an opportunity to use code from my 1st PR to test the runtime of my scraper! So after all was done, I had a `generations` folder that looked like this:


![GenFolder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s4steiqkjmez2qmy9a7w.png)

![GenJson](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jmmuoh1ewnmioh78i7iw.png)

the code used to gather the information was also rather simple.

```python
def get_data(url):
    response = requests.get(url)
    data = response.json()
    data = json.dumps(data, indent=4)
    return data
```

I would take the `data` and simply filter it out for the `version-endpoint` JSON object.

So with all that done, it was time to iterate through the generations. 

The version-groups endpoint luckily gave me references to Pokedex, though they're not as game-specific as they could be, but that's fine.

![PokeAPIEndpoint](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qkkko60jqnsx2w4tgdl6.png)

So, I ran through each game's Pokedex, grabbing all the Pokemon under `pokemon_species`. The data for that looked like this:

```python
# black-2-white-2.json
[
    {
        "entry_number": 0,
        "pokemon_species": {
            "name": "victini",
            "url": "https://pokeapi.co/api/v2/pokemon-species/494/"
        }
    },
    {
        "entry_number": 1,
        "pokemon_species": {
            "name": "snivy",
            "url": "https://pokeapi.co/api/v2/pokemon-species/495/"
        }
    },
...
```

And then further filtered everything to only grab the `name` and `url` split to only use it's dex number from `pokemon_species` until I had something a little more useable:

```Python
# unova.json
{
	"black-2-white-2": {
		"Pokemon": [
			{
				"name": "victini",
				"url": "494"
			},
			{
				"name": "snivy",
				"url": "495"
			},
```

I then separated each version into its own JSON object, meaning `black-2` and `white-2` were separated. Next is the fun part, the version exclusives. For the entire span of the mainline games, Pokemon has always released 2 versions together and sometimes a 3rd as a step up from the previous versions. the 2 versions often featured slightly different Pokemon to get people to trade with one another, or outright buy both versions, and the 3rd version would usually add a Pokemon unavailable in the previous versions but also have some Pokemon left out to once again, allow players to trade with others.

My best friend for this section was a website I've used extensively over the years, [seribii.net](https://www.serebii.net/) not only does it feature most of what you would need for the games, but it also gives you a nice list of version exclusive pokemon for each and every pokemon game. 

So I created a file called `exclu.py` and added each generational exclusive to an array and iterated the data in the regional files extracting certain Pokemon from the opposite versions


![KantoExclusives](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xq7w9tfksls6kt986x07.png)

which I ended up doing 20 or so times, adding some tweaks here and there for the additional Pokemon forms and regional variants that have been added over the years. Which finally gave me 8 files with every domestic pokedex from every single mainline Pokemon game, excluding BDSP, and their version-exclusive Pokemon including version-exclusive forms such as Mega-Mewtwo X and Y. I combined the files into one mega file and used that as a filter for the main web app, which ended up working flawlessly and was done with absolutely no additional API calls allowing for both filters to work at once. Here's an example:

![AdvancedFilters](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3n9t4h563is6oicsvr40.png)

The live site can be found [here](https://sprightly-marshmallow-70a015.netlify.app/)!

The final PR can be found [here](https://github.com/TheShiveshNetwork/Pokedex/pull/17), and with that, my first Hacktoberfest comes to a close!

## What would I do differently?

As I said earlier, I have a really bad habit of overcomplicating functionalities. It would be best if in the future I take a step back and find out the fastest way to implement something and break down the functionality to its most basic roots. Thank you for reading and I hope you have a fantastic Halloween!