We will start by creating a NextJs app using the creat-next-app
command. I will be using npx
to create a new project called my-pokemon-app. For this tutorial, we will be making use of the Pokemon API(https://pokeapi.co/) to demonstrate how to consume external APIs using NextJs.
npx create-next-app@latest my-pokemon-app
Let’s navigate to our project and open the code in the editor of our choice.
cd my-pokemon-app
You can notice, the create-next-app
creates a bunch of folders and files necessary for us to run a NextJs project.
To check if everything is set up without any issues, we will run the next server using the npm run dev
command in the terminal. This should start the application on port 3000 by default http://localhost:3000/
.
The above content is displayed using the pages/index.js
file. For the purpose of this tutorial, we will be using this file to display some of the Pokemon characters using the Pokemon API. Let’s clean up this file and delete any code that we don’t require.
You can simply copy the below code into your pages/index.js
file.
import Head from "next/head";
import styles from "../styles/Home.module.css";
export default function Home() {
return (
<div className={styles.container}>
<Head>
<title>Pokemon App</title>
<meta name="description" content="Fetch api data using NextJs" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<h1 className={styles.title}>Pokemon App using Next.js!</h1>
</main>
</div>
);
}
The page should now look something like this:
Now that we have set up our NextJs app, we can now work on getting the data from the Pokemon API. NextJs provides three different functions to fetch data into our app. They are getStaticProps
, getServerSideProps
and getStaticPaths
. We will first look at the getStaticProps
method.
Fetching data using the getStaticProps
The getStaticProps
function is used when you want to pre-render the content at the build time. This function gets executed on the server side and pre-fetches all the content even before the user request’s the data.
We will pre-fetch some of the Pokemon characters using the getStaticProps
function and display it on our index page.
Let’s add the getStaticProps
function below the Home() function (you can also add it at the top, it does not matter).
import Head from "next/head";
import styles from "../styles/Home.module.css";
export default function Home() {
return (
<div className={styles.container}>
<Head>
<title>Pokemon App</title>
<meta name="description" content="Fetch api data using NextJs" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<h1 className={styles.title}>Pokemon App using Next.js!</h1>
</main>
</div>
);
}
export async function getStaticProps() {
return {
props: {
}
}
}
The getStaticProps
returns props
that contain the data fetched from the external API. We can use this data to display on the client side.
We will use the fetch
to call the pokemon API and store the result in pokemons
which can be used to pass as props to the client side.
export async function getStaticProps() {
const res = await fetch("https://pokeapi.co/api/v2/pokemon");
const pokemons = await res.json();
return {
props: {
pokemons
},
};
}
The props pokemons
can now be used in the Home() function to display the content.
export default function Home({ pokemons }) {
const { results } = pokemons;
return (
<div className={styles.container}>
<Head>
<title>Pokemon App</title>
<meta name="description" content="Fetch api data using NextJs" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<h1 className={styles.title}>Pokemon App using Next.js!</h1>
{results.map((result) => (
<div className={styles.grid} key={result.name}>
<a href="/" className={styles.card}>
<h2>{result.name} →</h2>
</a>
</div>
))}
</main>
</div>
);
}
The API response contains a results
array which contains the name of the 20 pokemons by default. We have destructured the results
array and looped through them using the map() method. If everything goes well your app should now display the names of pokemons from the API.
Fetching data using the getServerSideProps
The getServerSideProps
function uses a server-side rendering technique. If NextJs finds a getServerSideProps
function declared within a page, it will pre-render the page every time the request is made to that page with the data returned by getServerSideProps
. This function always runs on the server side.
To demonstrate getServerSideProps
function, we will create a dynamic page route which will list the details of individual Pokemon. In this case, we will fetch the data using getServerSideProps
.
We will start by creating a new folder within the pages
folder and name it pokemon
. Within the pokemon
folder we will create another folder [id]
which will help us with the dynamic routing. Lastly, we will create a file index.js
inside the [id]
folder that will call the getServerSideProps
function.
Let’s create a new function pokemon in the newly created index.js file.
export default function pokemon() {
return (
<>
<h1>Pokemon</h1>
</>
);
}
This should help us access the route like ‘/pokemon/xxx’
Next, we will update the link on the home page to point to the dynamic routes. We will use the name of the pokemon as the id. Open the /pages/index.js and replace the href value to point to the dynamic route.
{results.map((result) => (
<div className={styles.grid} key={result.name}>
<a href={"pokemon/" + result.name} className={styles.card}>
<h2>{result.name} →</h2>
</a>
</div>
))}
Let’s go ahead and add the getServerSideProps function in the pokemon/[id]/index.js
export default function pokemon() {
return (
<>
<h1>Pokemon</h1>
</>
);
}
export async function getServerSideProps(context) {
return {
props: {},
};
}
The getServerSideProps
takes a context parameter which is an object containing keys like params, req, res, query etc. Since we are using dynamic routing, we will make use of the params key to get the ‘id’.
Let’s call the URL to fetch the individual data as follows:
export async function getServerSideProps(context) {
const id = context.params.id;
const res = await fetch(`https://pokeapi.co/api/v2/pokemon/${id}`);
const pokemon = await res.json();
return {
props: { pokemon },
};
}
We can now use the pokemon props to display the content.
import styles from "../../../styles/Home.module.css";
export default function pokemon({ pokemon }) {
return (
<>
<main className={styles.main}>
<h1>Pokemon - {pokemon.name}</h1>
<div className={styles.card}>
<img
src={pokemon.sprites.other["official-artwork"].front_default}
alt={pokemon.name}
width="200"
height="200"
/>
<p>Height: {pokemon.height}</p>
<p>Weight: {pokemon.weight}</p>
</div>
</main>
</>
);
}