How to create an app that shows using Spotify API and Next.js ?
Published: 2022-07-06 20:07:17

# How to create an app that shows using Spotify API and Next.js ? 

## Target audience

I've aimed this article at people who want to learn about Next.js, Tailwind.

## Learning Objectives

After completing this article, you will know how to do the following:
- Create a Next.js application
- Setup tailwind CSS framework for Next.js application
- Make API call to fetch data
- Write Restful API's in Next.js
- Use Context for state management


## What is Next.js ?

[Next.js](https://nextjs.org/learn/foundations/about-nextjs/what-is-nextjs) is a flexible **React framework** that gives you building blocks to create fast **web applications**.

## Why Did I Choose Next.js for this project ?

There are many reasons why we can choose Next.js over other react frameworks. For this simple demo I choose Next.js because it comes with features such as authorization, routing that we don't have to resolve.

## Middleware in Next.js ? 

[Middleware](https://nextjs.org/docs/advanced-features/middleware) allows you to run code before a request is completed, then based on the incoming request, you can modify the response by rewriting, redirecting, adding headers, or setting cookies.

By using the middleware feature in next.js we can get the information about the user's location. Using this location information, we can redirect the user to a certain page with localized information. So we don't have to use a reverse proxy server (ngnix, haproxy etc.) to determine the user's location in the backend and then redirect the user. We can handle the authorization process in the middleware to determine the user has a permission to access to a certain page or the user is a blacklisted or not to handle security cases. Most companies today still use a reverse proxy sever to handle these situations.


## Rest API in Next.js ?

We can create our restful APIs in next.js. Any file inside the folder `pages/api` is mapped to `/api/*` and will be treated as an API endpoint instead of a `page`.

You can check out the official [documentation](https://nextjs.org/learn/basics/api-routes). Here is the simple example of implementation of an endpoint:

```js
// Fake users data
// pages/api/users
const users = [{ id: 1 }, { id: 2 }, { id: 3 }]

export default function handler(req, res) {
  // Get data from your database
  res.status(200).json(users)
}
```

This feature allows us to create restful API's, so we can create web applications using full-stack. 


## What is tailwind ? 

Tailwind CSS framework helps us to create user interfaces quickly.

Here are the few advantages of using tailwind CSS:
- Minimum lines of code in CSS file
- Quick UI prototyping
- Predefined class names

To setup tailwind in Next.js you can follow the instructions in their [official website.](https://tailwindcss.com/docs/guides/nextjs)



---

You can check out the usage of Spotify API using Node.js [here](https://eminvergil.netlify.app/blog/spotify-api).

---

## Creating the application

Take the following steps to create this application:

### 1 - Create a Next.js Application

To create Next.js application, you can type the following command to the terminal:

```bash
yarn create next-app --typescript
```

### 2 - Add tailwind CSS following the instruction from [doc](https://tailwindcss.com/docs/guides/nextjs).
### 3 - Create the basic structure of application

In this demo, we will create a show listing application. So we will need 3 components for this demo:
	1 - A button to make request to Spotify API
	2 - An Input for filtering or searching in the list
	3 - List component to display the `show` list

You can see the general structure of application in the image below:

![[structure-2.png]]


### 4 - Create a `components` folder
 And add the 3 components named: GetAlbums, List. After you create these components, your `index.tsx` file should look like this:
 
 ```tsx
import type { NextPage } from "next";
import GetAlbums from "./components/GetAlbums";
import List from "./components/List";

const Home: NextPage = () => {
	return (
		<div className="container">
			<GetAlbums />
			<List />
		</div>
	);
};
export default Home;
```

### 5 - Create the global context for Albums

We have basically two components, but these components have different logic. GetAlbums component is responsible only for fetching data, and the List component is only responsible for displaying the data. So we want to make sure that these components access the same state. 

We could pass the data or state to these components using props, and for this demo props could be enough. But when an application goes bigger, using props to communicate between components isn't scalable(e.g.: [props drilling](https://www.geeksforgeeks.org/what-is-prop-drilling-and-how-to-avoid-it/)). So for this problem we use state management libraries. In this demo, I will use [Context](https://tr.reactjs.org/docs/context.html).

Here is the implementation for albumsContext:

```ts
import { createContext, useState } from "react";

export const AlbumContext = createContext();

export default function AlbumProvider({ children }) {
  const [albums, setAlbums] = useState([]);
  return (
    <AlbumContext.Provider value={{ albums, setAlbums }}>
      {children}
    </AlbumContext.Provider>
  );
}

```


### 6 - Implement the GetAlbums component

This component is only responsible for making an API request and storing that data in a context, so other components can access it.

To make an API call to the other enpoints, we should first get the access token from Spotify.

Take the following steps to implement GetShows component:
1. Create `spotify.tsx` in `pages/api/` folder.
	1. We will call this endpoint to get token.
2. Make an API request to the Spotify from this endpoint.

Here is the implementation for `spotify.tsx`:

```ts
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from "next";

type Data = {
  res: any;
};

export default async function handler(
  req: NextApiRequest,

  res: NextApiResponse<Data>
) {
  const client_id = process.env.SPOTIFY_CLIENT_ID;

  const client_secret = process.env.SPOTIFY_CLIENT_SECRET;

  if (req.method === "POST" && req.query.token == "true") {
    // make an api call to https://accounts.spotify.com/api/token using fetch

    var token = await fetch("https://accounts.spotify.com/api/token", {
      method: "POST",

      headers: {
        "Content-Type": "application/x-www-form-urlencoded",

        Accept: "application/json",

        Authorization:
          "Basic " +
          new Buffer(client_id + ":" + client_secret).toString("base64"),
      },

      body: "grant_type=client_credentials",
    }).then((res) => res.json());

    // return this token

    res.status(200).json({
      res: token,
    });
  }
}

```


If we make an API call to this endpoint, we can see the requested URL in the network tab. As you can see the image below when we make an API call to external service Next.js masks this API call.

![[api-call.png]]


Here is the implementation for GetAlbums component.

```ts
import React, { useContext, useState } from "react";
import { AlbumContext } from "../context/albumContext";

export default function GetAlbums() {
  const [artist, setArtist] = useState("");
  const { setAlbums } = useContext(AlbumContext);

  let GetAlbums = async () => {
    let tokenres = await fetch("/api/spotify?token=true", {
      method: "POST",
    });

    let tokenResponse = await tokenres.json();

    let response = await fetch(
      `https://api.spotify.com/v1/search?type=album&include_external=audio&q=${artist}`,
      {
        headers: {
          Authorization: "Bearer " + tokenResponse.res.access_token,
          "Content-type": "application/json",
        },
      }
    );
    let data = await response.json();
    setAlbums(data.albums.items);
  };
  return (
    <div className="flex flex-col gap-10  p-5 justify-center items-center mx-auto">
      <input
        placeholder="artist name"
        value={artist}
        onChange={(e) => setArtist(e.target.value)}
        className="w-full p-2 border border-gray-300 rounded-lg"
      />
      <button
        className="mx-3 my-2 p-2 rounded-xl bg-gray-700 hover:bg-gray-500 text-white text-xl"
        onClick={() => GetAlbums()}
      >
        Get Shows
      </button>
    </div>
  );
}

```


### 7 - Implement the List component to show the albums.

After we successfully get the albums from Spotify. We will list the album image, name.

Here is the full implementation for List component:

```ts
import React, { useContext } from "react";
import { AlbumContext } from "../context/albumContext";

export default function List() {
  const { albums } = useContext(AlbumContext);
  return (
    <div className="grid lg:grid-cols-4 md:grid-cols-2 grid-cols-1 gap-10  p-5 justify-center items-center mx-auto">
      {albums.map((album: any) => (
        <div className="flex flex-col gap-10  p-5 justify-center items-center mx-auto shadow-sm hover:shadow-2xl transition-shadow duration-500 ease-in-out">
          <img src={album.images[0].url} alt="album" />
          <h3>{album.name}</h3>
          <p>{album.artists[0].name}</p>
        </div>
      ))}
    </div>
  );
}

```


You can see the full project implementation [here](https://github.com/eminvergil/shopify-list).

Live demo: https://remarkable-pixie-2bf944.netlify.app/