|
| 1 | +--- |
| 2 | +title: "Spotify" |
| 3 | +description: "Show what you're listening to." |
| 4 | +logo: "spotify.png" |
| 5 | +--- |
| 6 | + |
| 7 | +```js |
| 8 | +import { getNowPlaying } from "../../lib/spotify"; |
| 9 | + |
| 10 | +export default async (_, res) => { |
| 11 | + const response = await getNowPlaying(); |
| 12 | + |
| 13 | + if (response.status === 204 || response.status > 400) { |
| 14 | + return res.status(200).json({ isPlaying: false }); |
| 15 | + } |
| 16 | + |
| 17 | + const song = await response.json(); |
| 18 | + const isPlaying = song.is_playing; |
| 19 | + const title = song.item.name; |
| 20 | + const artist = song.item.artists.map((_artist) => _artist.name).join(", "); |
| 21 | + const album = song.item.album.name; |
| 22 | + const albumImageUrl = song.item.album.images[0].url; |
| 23 | + const songUrl = song.item.external_urls.spotify; |
| 24 | + |
| 25 | + return res.status(200).json({ |
| 26 | + album, |
| 27 | + albumImageUrl, |
| 28 | + artist, |
| 29 | + isPlaying, |
| 30 | + songUrl, |
| 31 | + title, |
| 32 | + }); |
| 33 | +}; |
| 34 | +``` |
| 35 | + |
| 36 | +```js |
| 37 | +// lib/spotify.js |
| 38 | + |
| 39 | +import fetch from "isomorphic-unfetch"; |
| 40 | +import querystring from "querystring"; |
| 41 | + |
| 42 | +const { |
| 43 | + SPOTIFY_CLIENT_ID: client_id, |
| 44 | + SPOTIFY_CLIENT_SECRET: client_secret, |
| 45 | + SPOTIFY_REFRESH_TOKEN: refresh_token, |
| 46 | +} = process.env; |
| 47 | + |
| 48 | +const basic = Buffer.from(`${client_id}:${client_secret}`).toString("base64"); |
| 49 | +const NOW_PLAYING_ENDPOINT = `https://api.spotify.com/v1/me/player/currently-playing`; |
| 50 | +const TOKEN_ENDPOINT = `https://accounts.spotify.com/api/token`; |
| 51 | + |
| 52 | +const getAccessToken = async () => { |
| 53 | + const response = await fetch(TOKEN_ENDPOINT, { |
| 54 | + method: "POST", |
| 55 | + headers: { |
| 56 | + Authorization: `Basic ${basic}`, |
| 57 | + "Content-Type": "application/x-www-form-urlencoded", |
| 58 | + }, |
| 59 | + body: querystring.stringify({ |
| 60 | + grant_type: "refresh_token", |
| 61 | + refresh_token, |
| 62 | + }), |
| 63 | + }); |
| 64 | + |
| 65 | + return response.json(); |
| 66 | +}; |
| 67 | + |
| 68 | +export const getNowPlaying = async () => { |
| 69 | + const { access_token } = await getAccessToken(); |
| 70 | + |
| 71 | + return fetch(NOW_PLAYING_ENDPOINT, { |
| 72 | + headers: { |
| 73 | + Authorization: `Bearer ${access_token}`, |
| 74 | + }, |
| 75 | + }); |
| 76 | +}; |
| 77 | +``` |
| 78 | + |
| 79 | +## Usage |
| 80 | + |
| 81 | +<Step number={1} title="Create Spotify Application" /> |
| 82 | + |
| 83 | +First, we need to create a Spotify application to give us credentials to authenticate with the API. |
| 84 | + |
| 85 | +- Go to your [Spotify Developer Dashboard](https://developer.spotify.com/dashboard/) and log in. |
| 86 | +- Click **Create an App**. |
| 87 | +- Fill out the name and description and click **create**. |
| 88 | +- Click **Show Client Secret**. |
| 89 | +- Save your Client ID and Secret. You'll need these soon. |
| 90 | +- Click **Edit Settings**. |
| 91 | +- Add `http://localhost:3000` as a redirect URI. |
| 92 | + |
| 93 | +All done! You now have a properly configured Spotify application and the correct credentials to make requests. |
| 94 | + |
| 95 | +<Step number={2} title="Authentication" /> |
| 96 | + |
| 97 | +There are a variety of ways to authenticate with the Spotify API, depending on your application. Since we only need permission granted _once_, we'll use the [Authorization Code Flow](https://developer.spotify.com/documentation/general/guides/authorization-guide/#authorization-code-flow). |
| 98 | + |
| 99 | +First, we'll have our application request authorization by logging in with whatever [scopes](https://developer.spotify.com/documentation/general/guides/authorization-guide/#list-of-scopes) we need. |
| 100 | +Here's an example of what the URL might look like. |
| 101 | +Swap out the `client_id` and scopes for your own. |
| 102 | + |
| 103 | +```bash |
| 104 | +https://accounts.spotify.com/authorize?client_id=8e94bde7dd |
| 105 | +b84a1f7a0e51bf3bc95be8&response_type=code&redirect_uri=http |
| 106 | +%3A%2F%2Flocalhost:3000&scope=user-read-currently-playing%20 |
| 107 | +user-top-read |
| 108 | +``` |
| 109 | + |
| 110 | +After authorizing, you'll be redirected back to your `redirect_uri`. |
| 111 | +In the URL, there's a `code` query parameter. Save this value. |
| 112 | + |
| 113 | +```bash |
| 114 | +http://localhost:3000/callback?code=NApCCg..BkWtQ |
| 115 | +``` |
| 116 | + |
| 117 | +Next, we'll need to retrieve the refresh token. You'll need to generate a Base 64 encoded string containing the client ID and secret from earlier. You can use [this tool](https://www.base64encode.org/) to encode it online. The format should be `client_id:client_secret`. |
| 118 | + |
| 119 | +```bash |
| 120 | +curl -H "Authorization: Basic <base64 encoded client_id:client_secret>" |
| 121 | +-d grant_type=authorization_code -d code=<code> -d redirect_uri=http%3A |
| 122 | +%2F%2Flocalhost:3000 https://accounts.spotify.com/api/token |
| 123 | +``` |
| 124 | + |
| 125 | +This will return a JSON response containing a `refresh_token`. This token is [valid indefinitely](https://github.com/spotify/web-api/issues/374) unless you revoke access, so we'll want to save this in an environment variable. |
| 126 | + |
| 127 | +<Step number={3} title="Add Environment Variables" /> |
| 128 | + |
| 129 | +To securely access the API, we need to include the secret with each request. |
| 130 | +We also _do not_ want to commit secrets to git. Thus, we should use an environment variable. |
| 131 | +Learn how to add [environment variables in Vercel](https://vercel.com/docs/environment-variables). |
0 commit comments