I made a musical quizz using the spotify API without user auth, just the API access token (it uses the tracks preview).
I kinda make it simple with just a service file where I put my API calls, it was as long as it was in dev.
When I deployed it on vercel, I realized I kinda forget to handle the client key and secret as it should,.
I need to be able to read them directly as env variables.
So I found out I can achieve that on next 14 by using route handlers.
Problem is, it's a new feature and all the examples I've found are not that helpful for my special case, like it's quite theoretical, they're not a lot of it calling functions, it's directly fetch, etc... Cause I still want to use my service functions and such to handle and modify my data on the server side.
I tried to understand how it works, my only problem is I'm not sure how am I supposed to get my accessToken. I found something that works, but it's a bit odd. I've messed around a lot, so I came to understand that in my POST function maybe all I need to do is to declare which header my post request on this route should have? Then on the same route I've got a GET function that call a getPlaylist in which I call the getAccessToken, and it's when I guess it took the header I declare in my route handler?
I still need to declare the headers in getAccessToken, that's one of the think that makes me thing my solution is a bit odd, but I think I'm close to the real solution?
Here is my code (I'm also thinking about moving the getShuffledPlaylist in a controller file?) :
#Next 14 route handler and spotify access token
1 messages · Page 1 of 1 (latest)
the service file :
const getAccessToken = async () => {
return fetch("https://accounts.spotify.com/api/token", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${btoa(
`${process.env.REACT_APP_CLIENT_KEY}:${process.env.REACT_APP_CLIENT_SECRET}`
)}`,
},
body: new URLSearchParams({
grant_type: "client_credentials",
}),
})
.then((response) => {
if (!response.ok) {
return response.json().then((data) => {
throw new Error(data.error || "Failed to get access token");
});
}
return response.json();
})
.then((data) => {
return data.access_token;
})
.catch((error) => {
console.error("Error getting access token:", error);
throw error;
});
};
const getPlaylist = async (offsetNumber: string) => {
return getAccessToken()
.then((accessToken) =>
fetch(
`https://api.spotify.com/v1/playlists/niubn67898YHBUI8O9J8HJ9H/tracks?offset=${offsetNumber}`,
{
method: "GET",
headers: {
Authorization: `Bearer ${accessToken}`,
},
}
)
)
.then((response) => response.json())
.then((data) => {
return data.items;
})
.catch((error) => console.error("Error getting track infos", error));
};
const getShuffledPlaylist = async () => {
return Promise.all([getPlaylist("0"), getPlaylist("100")])
.then(([playlist1, playlist2]) => {
const combinedPlaylists = [...playlist1, ...playlist2];
const shuffledPlaylist = shuffle(combinedPlaylists);
return shuffledPlaylist;
})
.catch((error) => {
console.error(error);
});
};```
and here the route handler file :
export async function POST(request: NextRequest, response: NextResponse) {
const req = new Request("", {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization: `Basic ${btoa(
`${process.env.REACT_APP_CLIENT_KEY}:${process.env.REACT_APP_CLIENT_SECRET}`
)}`,
},
});
}
export async function GET(request: NextRequest, response: NextResponse) {
const playlist = await getShuffledPlaylist();
return Response.json({ playlist });
}