DEV Community

Cover image for I built an Harry Potter⚡ API, so you dont have to
Zeeshan 🎖
Zeeshan 🎖

Posted on

I built an Harry Potter⚡ API, so you dont have to

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 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 if you don't know how to.

Next I stole open sourced data from KostaSav and Daniel. 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:

// 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);
}
Enter fullscreen mode Exit fullscreen mode

Check out their documentation here.

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 and send it.

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

export async function GET() {
  return new Response(JSON.stringify(characters), {
    headers: { "content-type": "application/json" },
  });
}
Enter fullscreen mode Exit fullscreen mode
  • /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 from URL.

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

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
)
Enter fullscreen mode Exit fullscreen mode

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

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" },
      });
    }
  }
Enter fullscreen mode Exit fullscreen mode

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

return new Response(`No character with name ${character}`);
Enter fullscreen mode Exit fullscreen mode

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

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}`);
}
Enter fullscreen mode Exit fullscreen mode
  • 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 and here is the Github Repo

Like

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

Top comments (10)

Collapse
 
lionelrowe profile image
lionel-rowe
  return new Response(`No character with name ${character}`);

Seems like a classic 404 Not Found error. You can specify a status code for Response objects like this:

  return new Response(`No character with name ${character}`, {
    status: 404,
  });
Enter fullscreen mode Exit fullscreen mode

If you don't specify a status code, it defaults to 200 OK, so consumers of your API won't be able to determine whether the request actually succeeded without parsing the response body (or worse, they'll have no way of determining success at all, in the case of a HEAD request).

Collapse
 
acidop profile image
Zeeshan 🎖

Thanks for your input. I was in a hurry to just complete this project so I missed on these small details 😅.

I will update it for sure! Thanks!

Collapse
 
zee914 profile image
zee914 • Edited

hey you have done such a great work i am die heart fan of harry potter me and my dog with a cup of tea enjoyed this master piece alote.

Collapse
 
acidop profile image
Zeeshan 🎖

glad to know! 😄

Collapse
 
femi_akinyemi profile image
Femi Akinyemi

Thanks for building this and sharing👍🏾

Collapse
 
acidop profile image
Zeeshan 🎖

Thanks for giving it a read 😀

Collapse
 
aaronmccollum profile image
Aaron McCollum

This is awesome. This caught my eye as I really enjoy Harry Potter. Just 10 coffees though?!? Impressive haha

Collapse
 
acidop profile image
Zeeshan 🎖

Haha thanks for giving it a read 💖

Collapse
 
ashishk1331 profile image
Ashish Khare😎

Thanks for the outline. Also, I've once also faced the same error.
Npm doesn't allow uppercase as naming convention.
Now I'm of to make an API for naruto.
Datte-byo!

Collapse
 
acidop profile image
Zeeshan 🎖

Best of luck!