I built an Harry Potter⚡ API, so you dont have to
Tags: nextjs, webdev, api, tutorial
Published: 2023-06-16 12:29:38

Hello World!

Now before you scoff and say, "What on Earth would you need a Harry Potter API for?" hear me out. We Potterheads love the intricate tapestry of spells, characters, houses, books, and movies. So, naturally, it got me thinking, "Wouldn't it be amazing to have an API that provides all this enchanting data?!"

3 days and almost 10 coffees later I have everything ready.

## What we're building 🤔

Let's create an API that sends data about the following from the franchise:

- Characters
- Spells
- Houses
- Books
- Movies

At the end I'll also tell you why I had to bang my head on wall for a mistake 🤏 this big, that caused a bug on production.

## Setting up the project

I used [NextJS](https://nextjs.org/) for this because that is my goto for every web development project.

Almost everyone knows how to setup a Nextjs project so I'm not explaining it however you can follow [this](https://nextjs.org/docs/getting-started/installation) if you don't know how to.

Next I ~~stole~~ **open sourced** data from [KostaSav](https://github.com/KostaSav/hp-api) and [Daniel](https://github.com/danielschuster-muc/potter-db). And put them inside a folder called `db` inside project root.

## Creating API Routes

In NextJS 13 the way API works has completely changed. In order to get APIs working follow the below steps:

1. Inside the `app` dir create a folder called `api`. Not necessarily `api` you can also use your name for the folder and it will still work, unlike Next 12. But for simplicity we will use `api`.
2. Create a folder called `characters` and finally inside it create a file called `route.ts`. The `route.ts` will be the entry to the `/api/characters` path. It is similar to what `index.html` is (entry point).
3. Inside `characters` folder create another folder called `[characters]` followed by another `route.ts`. This will catch all dynamic routes. e.g. `/api/characters/harry%20potter`
4. Repeat the above steps for `houses`, `spells`, `books`, `movies`.

## Next 13 APIs (Important)

For an API to work in Next 13 we need to follow this syntax:

```javascript
// For GET requests
export async function GET() {
  return new Response("Hello");
}

// For POST requests
export async function POST() {
  return new Response("World");
}

// To get slug follow this
export async function GET(
	{ params }: { params: { character: string } }
) {
  const { character } = params;
  return new Response(character);
}
```

Check out their documentation [here](https://nextjs.org/docs/app/building-your-application/routing/router-handlers).

## Setting up the APIs

- `/api/characters` 

This route sends json containing data about characters from the Franchise. So we need to read the data from `db/characters.json`, convert into a [JSON string](https://www.w3schools.com/js/js_json_stringify.asp) and send it.

```javascript
import characters from "@/db/characters.json";

export async function GET() {
  return new Response(JSON.stringify(characters), {
    headers: { "content-type": "application/json" },
  });
}
```

- `/api/characters/[character]` 

This is a bit complicated.

**Dynamic Route** which will send data about an individual character.
For this we need to [get the slug](https://nextjs.org/docs/app/api-reference/file-conventions/page) from URL. 

So if your folder is named `[character]`, inside the `GET` method you need to pass the following parameter:

```typescript
import characters from "@/db/characters.json";

export async function GET(
  { params }: { params: { character: string } }
  // I totally understand this line I swear

  const { character } = params; // Ah finally the slug
)
```

Next we need to find the character from the slug in our JOSN file.

```typescript
if (character) {
    const characterString = characters.find(
      (c) => c.name.toLowerCase() === character.toLowerCase()
    );
    
    if (characterString) {
      return new Response(JSON.stringify(characterString), {
        headers: { "content-type": "application/json" },
      });
    }
  }
```

Finally if no such character exists in the database, return a message saying the same.

```typescript
return new Response(`No character with name ${character}`);
```

So at the end your code will look somewhat like this:

```typescript
import characters from "@/db/characters.json";

export async function GET(
  request: Request,
  { params }: { params: { character: string } }
) {
  const { character } = params;

  if (character) {
    const characterString = characters.find(
      (c) => c.name.toLowerCase() === character.toLowerCase()
    );

    if (characterString) {
      return new Response(JSON.stringify(characterString), {
        headers: { "content-type": "application/json" },
      });
    }
  }
  return new Response(`No character with name ${character}`);
}
```

- Repeat the above steps for `houses`, `spells`, `books`, `movies`.

## The Error

And about the error I talked about in the first part...

So I used TailwindCSS for the frontend and for some reason it just wasn't working when pushed on Vercel. So I had to spend a good part of my day just to find out that my tailwind config had a misconfiguration. So basically I wrote `components` instead of `Components` 😑. 
Just **1** letter caused me so much trouble.

## Finally...

This is just a quick rundown of a 4 days journey and around 10 cups coffee. 

Please checkout the [Live Demo](https://potterhead-api.vercel.app/) and here is the [Github Repo](https://github.com/AcidOP/potterhead-api)


![Like](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cyb5bz9t0461gonp82bk.jpg)

If you enjoyed the API please give a 💖 and 🌟 the Github repo.