next.js getStaticProps Serialize issue - javascript

I'm using next.js for a project where axios fetch in getStaticProps doesnot seem to work even though the URL is serialised in configuration.I tried serializing again by passing the response to JSON.parse but still cant find a solution.
import axios from "axios";
import Qs from "qs";
My axios config code below:
const axiosTmdbApi = axios.create({
baseURL: "https://api.themoviedb.org/3",
headers: { "content-Type": "application/json/" },
paramsSerializer: {
serialize: (params) =>
Qs.stringify({ ...params, api_key: apiKey }, { arrayFormat: "brackets" }),
},
});```
**My category which is passed as a parameter to invoke getTvList or getMovieList data below:**
import axiosTmdbApi from "./axiosTmdbApi";
export const category = {
movie: "movie",
tv: "tv",
};
export const type = {
top_rated: "top_rated",
popular: "popular",
};
const tmdbApi = {
getTvList: (tvType, params) => {
const url = "tv/" + type[tvType];
return axiosTmdbApi.get(url, params);
},
getMovielist: (movieType, params) => {
const url = "movie/" + type[movieType];
return axiosTmdbApi.get(url, params);
},
};
export default tmdbApi;```
Using getStaticProps to fetch my API
import tmdbApi from "../../api/tmdbApi";
import { type, category } from "../../api/tmdbApi";
const Movies = ({ data }) => {
console.log(data);
return (
<>
<h1 className="bg-success">Movies</h1>
</>
);
};
export default Movies;
export async function getStaticProps() {
let params = {};
let response;
response = await tmdbApi.getMovielist(type.popular, {
params,
});
const data = JSON.parse(JSON.stringify(response));
return {
props: { data },
};
}```
**Error :index.js?46cb:602 Uncaught TypeError: Converting circular structure to JSON
--> starting at object with constructor 'ClientRequest'
| property 'socket' -> object with constructor 'TLSSocket'
--- property '_httpMessage' closes the circle **

Try adding console.log and see what values are being handled at each stage. Instead of const data = JSON.parse(JSON.stringify(response)), you should be doing const data = response.data.
and change return statement to
return {
props: { data: data || [] },
};

Related

Dual nested dynamic routing in experimental app directory

I am using NextJS 13 and performing the following inside the app folder.
I am trying to use generateStaticParams function to achieve static generation pages on build.
This is the route: subpage/[categoryName]/[gifId]
So the route could be like following examples.
/subpage/fashion/1
/subpage/fashion/2
/subpage/fashion/3
/subpage/technology/1
/subpage/technology/2
/subpage/technology/3
/subpage/technology/4
... and so on.
The route subpage/[categoryName] won't have anything there. Might show an error or redirect some place.
The full path subpage/[categoryName]/[gifId] including the [gifId] is a must.
I need to perform REST requests to get the data for the pages.
How could I set this up inside my page.tsx file which will be located at: subpage/[categoryName]/[gifId]/page.tsx ?
If it was a single dynamic path, would be straight forward. See my implementation below for that.
But since is nested with 2 dynamic paths [categoryName] and [gifId] back to back, bit confused how to achieve this. Pls assist.
import MyComponent from "../../../components/MyComponent";
import { PartialGifProps, TagType} from "../../../utils/typings";
import axios from "axios";
import {apiDomain, defaultHeaders} from "../../../utils/constants";
const perPage = 40;
type Props = {
params: {
gifId: string,
},
}
export const generateStaticParams = async () => {
const url = `${apiDomain}/get_gif_count`; // I have access to modify the backend for this if it should contain category.
const fetchGifs = await axios.get(url, { headers: defaultHeaders });
const { total_count: totalCount } : TagType = fetchGifs.data;
const totalPages = Math.ceil(totalCount / perPage);
let paramsList = [];
for (let i = 1; i <= totalPages; i++) {
paramsList.push({ gifId: i.toString() })
}
// this paramsList would look like:
// [
// { gifId: '1', },
// { gifId: '2', },
// { gifId: '3', },
// .......
// ]
return paramsList;
}
const MyPage = async ({params: {gifId}}: Props) => {
const url = `${apiDomain}/get_partial?page=${gifId}&per_page=${perPage}`;
const fetchGifs = await axios.get(url, { headers: defaultHeaders });
const { gifs } : PartialGifProps = fetchGifs.data;
return (
<div className='text-white'>
<MyComponent gifs={gifs}/>
</div>
);
};
export default MyPage;
You can get categoryName in the same way you get gifId, through the params prop
type Props = {
params: {
gifId: string,
categoryName: string,
},
}
const MyPage = async ({params: {gifId, categoryName}}: Props) => {
console.log('categoryName =', categoryName);
const url = `${apiDomain}/get_partial?page=${gifId}&per_page=${perPage}`;
const fetchGifs = await axios.get(url, { headers: defaultHeaders });
const { gifs } : PartialGifProps = fetchGifs.data;
return (
<div className='text-white'>
<MyComponent gifs={gifs}/>
</div>
);
};

Error: A required parameter (slug) was not provided as an array in getStaticPaths for /posts/[...slug]

I have a problem with the 'getStaticPaths' function. When I try to get a dynamic display with a parameter it shows me as error: Error: A required parameter (slug) was not provided as an array in getStaticPaths for /posts/[...slug]
In My utils.js file got this function read the files
export function getPostsFiles() {
const postsDirectory = path.join(process.cwd(), "posts");
return fs.readdirSync(postsDirectory);
}
In my page [...slug]
export function getStaticProps(context) {
const { params } = context;
const { slug } = params;
const postData = getPostData(slug);
return {
props: {
post: postData,
},
revalidate: 600,
};
}
export function getStaticPaths() {
const postFilenames = getPostsFiles();
const slugs = postFilenames.map((fileName) => fileName.replace(/\.md$/, ""));
const parameters = slugs.map((slug) => ({ params: { slug: slug } }));
return {
paths: parameters,
fallback: true,
};
}

Next.js GetStaticPaths: ReferenceError: Cannot access 'getAllPostIds' before initialization

I am making a simple next js blog type of application using graphql as a data fetching backend to render text. Using getStaticPaths, I'm running into the following error when I try to fetch data for my page.
ReferenceError: Cannot access 'getAllPostIds' before initialization
Here is my code:
pages/posts/[id].tsx
import { getAllPostIds } from '../../../lib/posts'
const Post = ({ postData }) => {
... code.....
}
export const getStaticPaths = async () => {
const paths = getAllPostIds('aws');
return {
paths,
fallback: false
}
}
export default Post;
And here is my posts.ts where I use graphql to fetch data.
import { useQuery } from "react-query";
import { GraphQLClient } from "graphql-request";
const GET_POST_IDS = gql`
query($folder: String!) {
repository(owner: "assembleinc", name: "documentation") {
object(expression: $folder) {
... on Tree {
entries {
name
}
}
}
}
}`
;
const graphQLClient = new GraphQLClient('https://api.github.com/graphql', {
headers: {
Authorization: `Bearer ${process.env.GITHUB_ACCESS_TOKEN}`
}
});
export const getAllPostIds = (folder: String) => {
return useQuery(folder, async () => {
... fetch data ...
});
}
Essentially, before I can even get the data through graphql, next js is complaining that getAllPostIds can't be initialized even though I import it at the top. Is there some next.js magic that I am not seeing?

Getting "A required parameter (id) was not provided as a string in getStaticPaths" error in Next.js

I have a problem with the getStaticPaths function.
When I try to get a dynamic display with a parameter it shows me as error: A required parameter (id) was not provided as a string in getStaticPaths for / movies / [id] but if I use the other way above it works. Above all I am the documentation.
import fetch from 'node-fetch';
function MovieSelect({movie}){
return(
<div>
<h1>Test: {movie.name}</h1>
<p>{movie.summary.replace(/<[/]?[pb]>/g, '')}</p>
{movie.image ? <img src={movie.image.medium} /> : null}
</div>
)
}
export async function getStaticPaths(){
const request = await fetch('https://api.tvmaze.com/search/shows?q=batman')
const movies = await request.json()
//const paths = movies.map(movie =>`/movies/${movie.show.id}`)
const paths = movies.map(movie =>({
params: {id: movie.show.id},
}))
return {
paths,
fallback: false
}
}
export async function getStaticProps({params}){
const request = await fetch(`https://api.tvmaze.com/shows/${params.id}`)
const movie = await request.json()
return{
props:{
movie
}
}
}
export default MovieSelect
A required parameter (id) was not provided as a string in getStaticPaths for / movies / [id]
id should be a string as suggested by the error. Upon hitting the api from your browser, you can see that the id is not a string but a number. You need to convert it to string.
params: {id: movie.show.id.toString()},
My problem generated the same error, but I had a different bug.
TL;DR: The name of my file needed to match the key of the slug used in the params object.
In my case, my file name was [postSlug].js. Therefore, the key should have been postSlug inside of getStaticPaths().
// In [postSlug].js
const pathsWithParams = slugs.map((slugs) => ({ params: { postSlug: slug } })); // <-- postSlug is right
const pathsWithParams = slugs.map((slugs) => ({ params: { id: slug } })); // <--- id is wrong
My entire function then looked like this
export async function getStaticPaths() {
const slugs = await getAllBlogSlugs();
const pathsWithParams = slugs.map((slug) => ({ params: { postSlug: slug } }));
return {
paths: pathsWithParams,
fallback: "blocking",
};
}
References:
NextJS.org Get Static Paths
export async function getServerSideProps({ query, locale }) {
const { id } = query;
if (!id) return { notFound: true };
return {
props: {
fallback: true,
query,
locale,
...(await serverSideTranslations(
locale,
["common", "header", "footer"],
nextI18nextConfig
)),
},
};
}

ReactJS: Axios' async request is returning 'undefined'

I'm doing a little project using the movie DB API is ReactJs, and I have problems to use async functions, i'm making the api calls in many parts of projects an worked in all of them, but now it's not working.
My axios config:
export default axios.create({
baseURL: 'https://api.themoviedb.org/3/',
params: {
api_key: process.env.REACT_APP_API,
},
});
In my container I have this
const { setMenuSelected } = useContext(MovieContext);
const [movie, setMovie] = useState({})
const [recommendations, setRecommendations] = useState([]);
const [isLoading, setIsLoading] = useState(true)
useEffect(() => {
animateScroll.scrollToTop({ smooth: true });
setMenuSelected('');
getMovieRecommendations(setRecommendations, match.params.id, setIsLoading);
setMovie(getMovieDetails(match.params.id, setMovie));
}, [match.params.id, recommendations, isLoading]);
I'm fetching the data in other file just to organize the project
export const getMovieRecommendations = async (
setRecommendations,
movieId,
setIsLoading) => {
const res = await api.get(`/movie/${movieId}/recommendations`);
setRecommendations(res.results);
setIsLoading(false);
}
And to render the movie list I'm passing the recommendations to my component that only use map to render each movie,
<MovieList header={'Recommentadion'} movieList={recommendations} />
But the app allways crash saying "Cannot read property 'map' of undefined", i looked in the network properties in the chrome and my request is finishing with no erros.
Update:
return of console.log(JSON.stringify(res)) I removed the results itens so it wouldn't get too big
{
"data":{
"page":1,
"results":[
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{},
{}
],
"total_pages":2,
"total_results":40
},
"status":200,
"statusText":"",
"headers":{
"cache-control":"public, max-age=14400",
"content-type":"application/json;charset=utf-8",
"etag":"W/\"56ca661f28e43dc3dd2ce41816b517c5\""
},
"config":{
"transformRequest":{
},
"transformResponse":{
},
"timeout":0,
"xsrfCookieName":"XSRF-TOKEN",
"xsrfHeaderName":"X-XSRF-TOKEN",
"maxContentLength":-1,
"headers":{
"Accept":"application/json, text/plain, */*"
},
"method":"get",
"baseURL":"https://api.themoviedb.org/3/",
"params":{
"api_key":"fe5b485ed12153ca357c3275cfad6c5c"
},
"url":"https://api.themoviedb.org/3/movie/399121/recommendations"
},
"request":{
}
}
Try doing:
const res = await api.get(`/movie/${movieId}/recommendations`);
console.log(JSON.stringify(res));
This will print the whole JSON object into a string in the console. Since you're getting undefined and no error, you are most likely accessing the JSON object incorrectly. By printing out the contents this will show you what your JSON object looks like so you can get to the 'results' property successfully.
Explain axios.create & Example
axios.create is for initial.. (config)
const axios = Axios.create({ withCredentials: false/true });
Now, create a function using axios like that:
function get(...args) {
return axios.get(...args)
}
and call as you write:
const res = await get(`/movie/${movieId}/recommendations`);
I think this help you.
you should export your axios config like this:
const APIClient = axios.create({
baseURL: 'https://api.themoviedb.org/3/',
params: {
api_key: process.env.REACT_APP_API,
}
});
export default APIClient;
and then import it to fetch data in another file:
import APIClient from "YOUR AXIOS CONFIG FILE";
export const getMovieRecommendations = async (movieId) => {
const { data } = await APIClient.get(`/movie/${movieId}/recommendations`);
return data;
}
In your container set this:
const { setMenuSelected } = useContext(MovieContext);
const [movie, setMovie] = useState({})
const [recommendations, setRecommendations] = useState([]);
const [isLoading, setIsLoading] = useState(true)
const getList=async(movieId)=>{
const res = await getMovieRecommendations(movieId);
setRecommendations(res.results);
setIsLoading(false);
}
useEffect(() => {
animateScroll.scrollToTop({ smooth: true });
setMenuSelected('');
getList(match.params.id);
setMovie(getMovieDetails(match.params.id, setMovie));
}, [match.params.id, recommendations, isLoading]);

Categories

Resources