NextJS: error in getServerSideProps function with axios - reactjs

On the main page (index.js file) I use the getServerSideProps function
export async function getServerSideProps(context) {
axios.defaults.headers.common['Lang'] = context.locale
try {
const response = await axios.get('/index?limit=8')
return {
props: {
data: response.data
},
};
} catch (error) {
return {
props: {
error: error
},
};
}
}
Everything used to work, but now it's starting to make a mistake
connect EADDRNOTAVAIL ip:443 - Local (ip:0)
Although if you make a request to the same address in useEffect () - everything works
Tried to upgrade next to version 12 - the error remained
Screenshot

try
const response = await axios.get(`https://yourserver.com/index?limit=8`)
and if works replace https://yourserver.com by your .env variable
Also, try to console.log your variable:
const response = await axios.get('/index?limit=8')
console.log(response)
And check if your API route has .get method

In getServerSideProps you have to type the whole url http://localhost:3000/api/my-end-point
So I have two instances of axios in nextjs.
import Axios from 'axios'
// Use in react component
const ClientAxios = Axios.create({
baseURL: '/api'
})
// Use in getServerSideProps
const SystemAxios = Axios.create({
baseURL: 'http://localhost:3000/api'
})

Related

NextJs 13(app dir) fetch data from build in api

I am using Nextjs 13 with /src and /app directory. Below I am trying to fetch data from nextjs api:
//src/app/page.tsx
const getProducts = async () => {
try {
const res = await fetch('/api/products');
const data = await res.json();
return data;
} catch (err) {
console.log(err);
}
}
export default async function Home() {
....
}
//src/pages/api/products
export default function handler(
req: NextApiRequest,
res: NextApiResponse<Product[]>
) {
res.status(200).json(products)
}
this doesn't work and instead show Failed to parse URL from /api/products and TypeError [ERR_INVALID_URL]: Invalid URL.
Note: When I fetch the same data using localhost:3000 with url that does work perfectly fine.
I even tried using `/pages/api/products' that doesn't work either.
please create index.js inside /api/products/index.js and then build your endpoint and call that from Component as you did above
e.g
export default function handler(req, res) {
res.status(200).json([{id:1, title:'T-Shirt'},{id:2,title:'Shoes'}]);
}

Why express server receives front end data as undefined?

I am currently working on social media mern stack react app. I am using node js and express as my backend services , also using mongoose to store my data and axios and redux thunk which connect the backend to the front end. Till now I had no issue recieving and sending data to the server. Right now I am trying to create search post get request ,base on a keyword the user entered. The issue with it, that when I am sending the keyword to the server instead of recieving the string it gets undefined value, like redux thunk not sending anything. I will be very thankful if someone could help me with that. I am watching the code over and over again and can't find out the reason for that.
My post controller class(I copied only the relevant function):
import express from "express";
const app = express();
import Post from "../model/PostModel.js";
import ErrorHandlng from "../utilities/ErrorHandling.js";
import bodyParser from "body-parser";
import catchAsync from "../utilities/CatchAsync.js";
import User from "../model/UserModel.js";
app.use(express.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
export const getPosts = catchAsync(async (req, res, next) => {
const data = req.body.keyword;
const page = parseInt(req.query.page || "0");
const PAGE_SIZE = 20;
const query = new RegExp(data, "i");
const total = await Post.countDocuments({});
const posts = await Post.find({ $or: [{ title: query }, { content: query }] })
.limit(PAGE_SIZE)
.skip(PAGE_SIZE * page);
if (!posts) {
return next(new ErrorHandlng("No posts were found", 400));
}
res.status(200).json({
status: "success",
data: {
totalPages: Math.ceil(total / PAGE_SIZE),
posts,
},
});
});
My api class(front end,copied only the calling for that specific get request):
import axios from "axios";
const baseURL = "http://localhost:8000";
axios.defaults.withCredentials = true;
const API = axios.create({
baseURL,
credentials: "include",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
});
export const getPostsByKeyword = (keyword, page) =>
API.get(`/post/getPostsByKey?page=${page}`, keyword);
Post slice class:
export const fetchPostsByKeyWord = createAsyncThunk(
"post/getKeyword",
async ({ keyword, page }, { fulfillWithValue, rejectWithValue }) => {
try {
const response = await api.getPostsByKeyword(keyword, page);
if (response.statusCode === "400") {
throw new Error("There are no available posts");
}
const fetchData = await response.data.data.posts;
const totalPages = await response.data.data.totalPages;
return fulfillWithValue({ fetchData, totalPages });
} catch (err) {
console.log(err.response.message);
}
}
);
const initialState = { status: "undefined" };
const PostSlice = createSlice({
name: "post",
initialState,
reducers: {},
extraReducers: {},
});
export const postActions = PostSlice.actions;
export default PostSlice;
Calling the backend:
dispatch(fetchPostsByKeyWord({ keyword, page }))
.unwrap()
.then((originalPromiseResults) => {
console.log("thte " + " " + originalPromiseResults.totalPages);
console.log("The data is" + originalPromiseResults.fetchData);
setTotalPages(originalPromiseResults.totalPages);
})
.catch((err) => {
console.log(err.message);
});
As you can see I have not copied the whole code, I copied only the parts that are relevants for the question.
Browsers cannot currently send GET requests with a request body. XMLHttpRequest (which Axios uses) will ignore it and fetch() will trigger an error.
See also HTTP GET with request body for extra discussion on why trying this might be a bad idea.
You should instead pass everything required in the query string, preferably via the params option so it is correctly encoded...
export const getPostsByKeyword = (keyword, page) =>
API.get("/post/getPostsByKey", { params: { page, keyword } });
and grab the data via req.query server-side.
const { page, keyword } = req.query;
With vanilla JS, you can use URLSearchParams to construct the query string...
const params = new URLSearchParams({ page, keyword });
// XHR
const xhr = new XMLHttpRequest();
xhr.open("GET", `/post/getPostsByKey?${params}`);
// Fetch
fetch(`/post/getPostsByKey?${params}`); // GET is the default method
Your Axios instance creation could also be a lot simpler...
Axios is usually quite good at setting the correct content-type header, you don't have to
Your Express app isn't doing any content-negotiation so you don't need to set the accept header
Unless you're actually using cookies (which it doesn't look like), you don't need credential support
const API = axios.create({ baseURL });

Easy way to append token key to request data for every request with React Query

I have to add a token that is created upon login and put in cookies into my request data to every fetch request I make. I'm currently doing it by using a custom hook that will add it every time so I don't have to add it multiple times. Is there an easier way? Maybe with axios?
Here is my custom hook:
import { useQuery as useBaseQuery } from 'react-query';
import axios from 'axios';
const fetcher = async (url, options) => {
const token = Cookies.get('TOKEN');
const { data } = await axios.get(url, {
data: { ...options, 'TOKEN': token },
});
return data;
};
const useQuery = (queryKey, query, options) => {
return useBaseQuery(queryKey, async () => {
return await fetcher(query, options);
});
};
export default useQuery;
and is used like this:
import useQuery from './useBaseQuery';
const requestData = {
method: 'GET',
path: pathToUrl,
};
export default function useGetActionAlerts() {
return useQuery('actionAlerts', '/bin/user', requestData);
}
You need to use interceptor, from documentation
You can intercept requests or responses before they are handled by then or catch.
https://axios-http.com/docs/interceptors

Requesting API data using getStaticProps() returns undefined object | Nextjs

I'm new to new to nextjs.
I'm making a real estate web using bayut API.
And got trouble requesting agencies data from the API. I want to show list of agencies on my page like so:
ss taken from bayut.com
index.js:
import { baseUrl, fetchApi } from "../utils/fetchApi";
export default function Agency({ agencyList }) {
console.log({ agencyList }); // <====I need this
return <div>aaa</div>;
}
export async function getStaticProps() {
//Fetch agencies list
const agencyList = await fetchApi(
`${baseUrl}/agencies/list?hitsPerPage=25&page=0&lang=en`
);
return {
props: {
agencyList: agencyList?.hits,
},
};
}
fetchApi.js:
import axios from "axios";
export const baseUrl = "https://bayut.p.rapidapi.com";
export const fetchApi = async (url) => {
const { data } = await axios.get(url, {
headers: {
"x-rapidapi-host": "bayut.p.rapidapi.com",
"x-rapidapi-key": process.env.NEXT_PUBLIC_RAPIDAPI_KEY,
},
});
return data;
};
In console returns:
{agencyList: undefined}agencyList:
undefined[[Prototype]]: Object
While It will return property object as it should if I change the url to:
/properties/list?locationExternalIDs=5002&purpose=for-sale&hitsPerPage=1
it will return:
agencyList: Array(1)}
agencyList: Array(1)
0: {id: 2828151, ownerID: 1101619, userExternalID: '1101619', sourceID: 1, state: 'active', …}
length: 1
I'm expecting to return similar kind of data as the property object. I also tried to copy the code from the API page but no luck:
2nd index.js:
import axios from "axios";
import React, { useState, useEffect } from "react";
const Agency = () => {
const [agentList, setAgentList] = useState([]);
const options = {
method: "GET",
url: "https://bayut.p.rapidapi.com/agencies/list",
params: { hitsPerPage: "25", page: "0", lang: "en" },
headers: {
"x-rapidapi-host": "bayut.p.rapidapi.com",
"x-rapidapi-key": process.env.NEXT_PUBLIC_RAPIDAPI_KEY,
},
};
const fetchAgentList = async () => {
const response = await axios.request(options);
setAgentList(response.data);
};
useEffect(() => {
fetchAgentList();
}, []);
useEffect(() => {
console.log(agentList);
}, [agentList]);
return <div>aaa</div>;
};
export default Agency;
It returns an empty array:
[]
length: 0
[Question 1]Any idea how to solve this? Am I missing any parameter? Also above code wont return any error message but, if I create a new page, named localhost:3000/agency, and copy the index.js code to agency.js, it will run to this error message:
Server Error
Error: Error serializing .agencyList returned from getStaticProps in "/agency".
Reason: undefined cannot be serialized as JSON. Please use null or omit this value.
Even requesting property object (which works on index.js) it won't work on agency.js page.[Question 2] Does it means I can only use getStaticProps() on / page only (why this happend)? or do I need to initialize something?
Sorry for messy post. first time posting. Thankyou!
tl;dr A real estate web requesting API data. getStaticProps() works on property object but not on agency object. what am I missing here?
Got it working, I just need to add query: '{some word}' into the parameter. It is stated on rapidApi page that the paramater is optional but I guess I couldn't make request without it.

How to pass open weather API data to React front-end with serverless function and axios

I'm currently attempting to call the openweather API in a serverless function, pass the response into a 'return' and then get the response with Axios and set my component state with the response.
However, every time it calls the JSON isn't being sent in the response. Instead, it's just the URL. The state is then updated to be the URL unsurprisingly.
When I call the API in Postman, it returns the data. So I don't understand what I'm doing wrong.
The serverless function is obviously wrong. But what do I need to change about my serverless function to return the data, and not just the URL?
Here's the function:
module.exports = (req, res) => {
const url = `https://api.openweathermap.org/data/2.5/weather?q=London&appid=${process.env.OPEN_WEATHER_API}`;
const weatherResponse = url;
return res.status(200).json(weatherResponse);
};
And then my Axios call in my component calling the serverless function:
this.state = {
weather: []
}
axios.get("/api/getCurrentWeather")
.then((response) => {
this.setState({
weather: response.data
})
console.log(this.state.weather)
})
.catch((error) => {
console.log(error)
})
}
Any pointers would be appreciated!
From your client you are calling server less function /api/getCurrentWeather
now in you serverless function you must call the openweather api using axios of http here
and then send error or success data to your client.
import axios from 'axios';
module.exports = async (req, res) => {
const url = `https://api.openweathermap.org/data/2.5/weather?q=London&appid=${process.env.OPEN_WEATHER_API}`;
const weatherResponse = await axios.get(url);
return res.status(200).json(weatherResponse.data);
};

Resources