Axios instance/function not receiving argument? - javascript

I have a next.js App which has a working axios call, which I am trying to refactor. I have it mostly working, but I can't get my new function to receive arguments.
This problem has two components to it, my next.js page, and the external custom module where I am writing my functions to use axios to call the YouTube API to retrieve info.
My next.js getStaticProps call looks like this. I know this is working. Note the function where I am trying to pass in the video ID. (The 'const = video' line)
export async function getStaticProps(context: any) {
// It's important to default the slug so that it doesn't return "undefined"
const { slug = "" } = context.params;
const film = await client.fetch(query, { slug });
const video = await youtube.grabVideoInfo(film.VideoID);
return {
props: {
film,
video,
},
revalidate: 10,
};
}
I have tried writing the axios call in two ways, trying to pass in the video ID as an argument. Neither of which work, and fail to call from the API, stating an invalid video ID, which means it isn't being passed in.
The first way:
const grabVideoInfo = async (videoId) => {
const videoGrab = axios.create({
baseURL: "https://www.googleapis.com/youtube/v3/videos?",
params: {
headers: { "Access-Control-Allow-Origin": "*" },
part: "snippet",
id: videoId,
key: KEY,
},
});
const query = await videoGrab.get().then(
(response) => {
return response.data.items[0];
},
(error) => {
return error.toJSON();
}
);
return query;
};
The second way:
const grabVideoInfo = async (videoId) => {
const videoGrab = axios.create({
baseURL: "https://www.googleapis.com/youtube/v3/videos?",
params: {
headers: { "Access-Control-Allow-Origin": "*" },
part: "snippet",
key: KEY,
},
});
const query = await videoGrab.get({ params: { id: videoId } }).then(
(response) => {
return response.data.items[0];
},
(error) => {
return error.toJSON();
}
);
return query;
};
And this is the fully working version that I am trying to rewrite, which is live on the app currently. This demonstrates that the getStaticProps client call is working.
export async function getStaticProps(context: any) {
// It's important to default the slug so that it doesn't return "undefined"
const { slug = "" } = context.params;
const film = await client.fetch(query, { slug });
const KEY = process.env.YOUTUBE_API_KEY;
const conn = axios.create({
baseURL: "https://www.googleapis.com/youtube/v3/",
params: {
headers: { "Access-Control-Allow-Origin": "*" },
part: "snippet",
id: film.videoID,
key: KEY,
},
});
const video = await (await conn.get("videos?")).data.items[0];
return {
props: {
film,
video,
},
revalidate: 10,
};
}
Any help is greatly appreciated. I'm really scratching my head with this one.

Ok so your refactor is accessing film.VideoId where the original uses film.videoId.

Related

req.query is undefined in Next.js API route

I'm trying to do a delete request. I can fetch the API route through pages/api/people/[something].js.
And this is the response I got from the browser's console.
DELETE - http://localhost:3000/api/people/6348053cad300ba679e8449c -
500 (Internal Server Error)
6348053cad300ba679e8449c is from the GET request at the start of the app.
In the Next.js docs, for example, the API route pages/api/post/[pid].js has the following code:
export default function handler(req, res) {
const { pid } = req.query
res.end(Post: ${pid})
}
Now, a request to /api/post/abc will respond with the text: Post: abc.
But from my API route pages/api/people/[something].js, something is undefined.
const { something } = req.query
UPDATED POST:
React component
export default function DatabaseTableContent(props) {
const id = props.item._id; // FROM A GET REQUEST
const hide = useWindowSize(639);
const [deletePeople] = useDeletePeopleMutation();
async function deleteHandler() {
await deletePeople(id);
}
return <Somecodes />;
}
apiSlice.js
export const apiSlice = createApi({
// reducerPath: "api",
baseQuery: fetchBaseQuery({ baseUrl: url }),
tagTypes: ["People"],
endpoints: (builder) => ({
getPeople: builder.query({
query: (people_id) => `/api/people/${people_id}`,
providesTags: ["People"],
}),
deletePeople: builder.mutation({
query: (studentInfo) => ({
url: `api/people/people-data/student-info/${studentInfo}`,
method: "DELETE",
headers: {
accept: "application/json",
},
}),
invalidatesTags: ["People"],
}),
}),
});
export const {
useGetPeopleQuery,
useDeletePeopleMutation,
} = apiSlice;
pages/api/people/people-data/student-info/[studentInfo].js
import { ObjectId, MongoClient } from "mongodb";
async function handler(res, req) {
const { studentInfo } = req.query; // the code stops here because "studentInfo" is undefined
const client = await MongoClient.connect(process.env.MONGODB_URI.toString());
const db = client.db("people-info");
if (req.method === "DELETE") {
try {
const deleteData = await db
.collection("student_info")
.deleteOne({ _id: ObjectId(studentInfo) });
const result = await res.json(deleteData);
client.close();
} catch (error) {
return res.status(500).json({ message: error });
}
}
}
export default handler;
The order of params passed to your handler functions needs to be reversed.
For NextJS API routes the req is the first param passed to the handler and the res param is second.
Example handler function from NextJS documentation:
export default function handler(req, res) {
res.status(200).json({ name: 'John Doe' })
}

Unable to invoke "btoa" and "item.slice" method in my script for retrieving the playlist

Whenever I am trying to invoke the "btoa" method, I am not able to use this within my script. I created a variable to store the client id: client_secret in base64. The id and secrets are being retrieved from the ".env" file.
I have also tried to use the Buffer method, but unable to use this as well. I am getting the error "invalid from" in Buffer.
can someone help me?
Please look at the full code,
const client_id = process.env.SPOTIFY_CLIENT_ID;
const client_secret = process.env.SPOTIFY_CLIENT_SECRET;
const refresh_token = process.env.SPOTIFY_REFRESH_TOKEN;
const basic = btoa(`${client_id}:${client_secret}`);
const NOW_PLAYING_ENDPOINT = `https://api.spotify.com/v1/me/player/currently-playing`;
const TOP_TRACKS_ENDPOINT = `https://api.spotify.com/v1/me/top/tracks`;
const TOKEN_ENDPOINT = `https://accounts.spotify.com/api/token`;
const getAccessToken = async () => {
const response = await fetch(TOKEN_ENDPOINT, {
method: 'POST',
headers: {
Authorization: `Basic ${basic}`,
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token
})
});
return response.json();
};
export const getNowPlaying = async () => {
const { access_token } = await getAccessToken();
return fetch(NOW_PLAYING_ENDPOINT, {
headers: {
Authorization: `Bearer ${access_token}`
}
});
};
export const getTopTracks = async () => {
const { access_token } = await getAccessToken();
return fetch(TOP_TRACKS_ENDPOINT, {
headers: {
Authorization: `Bearer ${access_token}`
}
});
};
Using the above script I am trying to embed the customized Spotify play on my site. This wrapper is intended to display the top track as well.
Also, whenever I am trying to run the wrapper used to display the top tracks, it displays the following error,
Full code for displaying the top tracks:
import { type NextRequest } from 'next/server';
import { getTopTracks } from 'lib/spotify';
export const config = {
runtime: 'experimental-edge'
};
export default async function handler(req: NextRequest) {
const response = await getTopTracks();
const { items } = await response.json();
const tracks = items.slice(0, 10).map((track) => ({
artist: track.artists.map((_artist) => _artist.name).join(', '),
songUrl: track.external_urls.spotify,
title: track.name
}));
return new Response(JSON.stringify({ tracks }), {
status: 200,
headers: {
'content-type': 'application/json',
'cache-control': 'public, s-maxage=86400, stale-while-revalidate=43200'
}
});
}
The problem is that you misspelled the Bytes to ASCII function, it is btoa, not btao.
If you are looking to do it the other way around, spell it atob.

Dynamic router and page with Next.js and Prisma

I have cards with product information in my database, I display them successfully on the user's page. Now I want to add a more details button on each card to go to a new page from it (/pages/card/[id]). But I don't really understand how I can pull out the card value by clicking through my API.
const res = await fetch('/api/cards/' + id, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ id: id })
})
if (res.ok) {
const result = await (await res).json()
if (result.redirectUrl) {
router.push(result.redirectUrl as string)
}
}
}
API
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { id } = req.query
if (req.method === 'GET') {
if (typeof id === 'string') {
const moreDetail= await db.sales.findUnique({
where: {
id: id },
})
res.send({ redirectUrl: '/card'+[id] })
}
}
My card in schema
id String #id #default(cuid())
title String
description String
active Boolean #default(true)
My suggestion would be to introduce another API endpoint that returns an array of all of the available cards, or at least an array of all of the available card ids. After that, create a new page matching your URL format /pages/card/[id].tsx and inside that file, create your page like normal, but also export 2 functions:
getStaticPaths
getStaticProps
These let Next know what paths are available and how to load data for them during the build process.
export async function getStaticPaths() {
const cardIds = await fetch('/api/cards', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
});
return {
paths: cardIds.map((id) => (
{
params: { id }
},
)),
fallback: false, // setting to false will throw a 404 if none match
};
}
This lets Next know all of the available dynamic routes to generate pages for.
export async function getStaticProps({ params: { id } }) {
const card = await fetch(`/api/cards/${id}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
});
return {
props: {
card,
},
}
}
This actually loads the data from your API given a card id and passes it into your component to display more details for.
Hopefully that gives you a good jumping off point.

Vue how to display response from backend API

Sorry for such noob question but I'm a simply gave up. I've got below code which creates a POST request to the BE part of the app - user provides input (productCodes) and push submit button. That part works well, Vue sends request to BE but in the response FE should have received JSON with result: { id: 1234 }
How do I get this response and display it inside the app? I've got below:
imports.js
const createProductsRequest = (self, products) => {
const jwtToken = self.$store.state.idToken;
const payload = JSON.stringify({ product_codes: products['product_codes'].split(',') })
return axios
.post(`/api/v1/imports/products/`, payload,{
headers: {
Authorization: `Bearer ${jwtToken}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
.then(response => response.data)
};
export {
createProductsRequest
};
sync_product.vue
<script>
import {
createProductsRequest
} from '../../api/imports'
import ModalController from '../general/modal_controller'
export default {
name: 'BackboneSyncProducts',
data() {
return {
styleCodes: [],
}
},
computed: {
productsToSyncAmount () {
return this.styleCodes.length
},
},
methods: {
async syncProducts() {
let confirmationText = `Do you want to ${this.productsToSyncAmount} sync products?`
if (this.productsToSyncAmount === 0) {
ModalController.showToast('', 'Type product codes for sync first, please!', 'warning')
}
else if (await ModalController.showConfirmation('Confirmation', confirmationText)) {
try {
ModalController.showLoader()
await createProductsRequest(this, this.styleCodes)
const successMessage = `${this.productsToSyncAmount} products have been queued for sync`
await ModalController.showToast('', successMessage)
} catch (data) {
const errorMessage = `Error occurred during queueing products to sync - `
ModalController.showToast('', errorMessage + data?.message, 'error')
} finally {
this.styleCodes = []
ModalController.hideLoader()
}
}
},
}
}
</script>
That's all what I have.
Instead of calling your request without getting the return value:
await createProductsRequest(this, this.styleCodes)
You can get the return value which is the result of the request :
const data = await createProductsRequest(this, this.styleCodes)
By doing that, data must contain the result of the request, as you mentionned { id: 1234 }.
--
If you want to use this result in your component, you can create a reactive value in data()
data() {
return {
styleCodes: [],
data: null
}
},
And store the result like this :
this.data = await createProductsRequest(this, this.styleCodes)
With that you can display it in your template for example :
<template>
<!-- There is a v-if because before doing the request, data is null -->
<div v-if="data">{{ data.id }}</div>
</template>

NextJS - Get dynamic variable in getStaticProps

So I have getStaticProps and need to do some data fetching based on a variable here is an example
export async function getStaticProps() {
const res = await fetch(localWordpressUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
query: `
query AllPostsQuery {
posts(where: {categoryName: "blog"}) {
nodes {
slug
content
title
}
}
}
`,
})
});
const json = await res.json();
return {
props: {
posts: json.data.posts,
}
};
}
Where categoryName: "blog" needs to be a variable instead of hard coded. I know you can get the slug, but what I need is before the slug. i.e. site.com/blog/slug. Any suggestions on this?
You're actually really close. What you need is to grab the context out of your getStaticProps function. Add this to your getStaticProps function, and look at the console log to see what's happening.
export async function getStaticProps(context) {
console.log(JSON.stringify(context, null, 3));
const { asPath, req, res, pathname, query } = context;
if (req) {
let localWordpressURL = req.headers.host;
console.log(localWordpressURL);
}
}

Categories

Resources