Cannot map results from API - json

I'm trying to dynamically generate routes in my next.js application. I have an api called getUsers that returns something like this:
{"users":[{"_id":"639a87ae8a128118cecae85b","username":"STCollier","image":"https://storage.googleapis.com/replit/images/1641322468533_db666b7453a6efdb886f0625aa9ea987.jpeg","admin":false,"likedPosts":["639e34c5991ecaea52ace9e4","639e34c7991ecaea52ace9e7","639e34c7991ecaea52ace9ea","639e39a216a642f686a28036","639e39a216a642f686a28037","639e3b3d8cdebd89d9691f97","639e3b3d8cdebd89d9691f98","639e3b3e8cdebd89d9691f9d","639e3b5a8cdebd89d9691fa0","639e3b5c8cdebd89d9691fa3","639e3b5c8cdebd89d9691fa6"],"dislikedPosts":[""]},{"_id":"639a88abc4274fba4e775cbe","username":"IcemasterEric","image":"https://storage.googleapis.com/replit/images/1646785533195_169db2a072ad275cfd18a9c2a9cd78a1.jpeg","admin":false,"likedPosts":[],"dislikedPosts":[]}
So I know the API works succesfully, but when trying to get these api results and generate a page for each username, I get an error stating:
TypeError: users.map is not a function
Here's my code for generating the routes:
//pages/user/[username].js
const Get = async (url) => {
return await fetch(url).then(r => r.json());
}
export async function getStaticPaths() {
const users = Get('/api/getUsers')
return {
paths: users.map(u => {
const username = u.users.username
return {
params: {
username
}
}
}),
fallback: false
}
}
What is wrong with my getStaticPaths() code? I know that the API is working, so why can't I map the results?
And if anyone needs the code for api/getUsers, here is that:
import clientPromise from "../../lib/mongodb";
import nc from "next-connect";
const app = nc()
app.get(async function getUsers(req, res) {
const client = await clientPromise;
const db = client.db("the-quotes-place");
let users = []
try {
const dbUsers = await db
.collection("users")
.find({})
.toArray();
users = dbUsers
return res.json({
users: JSON.parse(JSON.stringify(users)),
success: true
})
} catch(e) {
return res.json({
message: new Error(e).message,
success: false,
});
}
})
export default app
Thanks for any help!!

Modify Get method to return an async value instead of Promise.
As Get is an async method, you need the await in getStaticPaths method.
const Get = async (url) => {
let response = await fetch(url);
return await response.json();
}
export async function getStaticPaths() {
const users = await Get('/api/getUsers');
...
}

Related

How to pass updated set State value in axios request as params

I'm a beginner in react native, I'm trying to get user information from mysql database through an axios API get request.
Once logged in, I stored email address in AsyncStorage and later want to use that email address from AsyncStorage as params or parameters to get the user details.
I wrote a code which set initial state of the setState as 'na'. Please help me how I can pass the email address from AsyncStorage as params or parameters.
Here is my code.
// to load email address
const [SessionEmail, setSessionEmail] = useState('na');
// to load users info
const [users, setUsers] = useState([]);
useFocusEffect(
React.useCallback(() => {
getUsername();
getUsersInfoFromAPI();
}, [])
);
// to get the session username from localstorage
const getUsername = async () => {
try {
const username = await AsyncStorage.getItem('Username')
if (username !== null) {
setSessionEmail(username);
}
} catch (e) {
console.log(e);
}
}
// API Calling user details
const getUsersInfoFromAPI = async () => {
await axios.get(`https://myapi.co.in/api/user/?email=${SessionEmail}`)
.then(response => {
setUser(response.data);
})
.catch(error => {
console.log(error);
});
}
After the page is rendered, and I load page from metro, I can see the parameters have been sent to server.
Update your code in this way:
useFocusEffect(
React.useCallback(() => {
getUsername();
}, [])
);
Instead of saving your email to state, sent it to function directly but if you are using it for other reason you can still save it but call function while getting username from AsyncStorage with username parameter like below.
// to get the session username from localstorage
const getUsername = async () => {
try {
const username = await AsyncStorage.getItem('Username')
if (username !== null) {
getUsersInfoFromAPI(username);
}
} catch (e) {
console.log(e);
}
}
// API Calling user details
const getUsersInfoFromAPI = async (email) => {
await axios.get(`https://myapi.co.in/api/user/?email=${email}`)
.then(response => {
setUser(response.data);
})
.catch(error => {
console.log(error);
});
}
const [users, setUsers] = useState([]);
here you can use like this
const [users, setUsers] = useState();
hope this will help you

Getting empty {} from mysql table, on React and node.js

For some reason am getting empty object back from mysql table, the table is filled in with some vacation detail. And i want to display them with map in my react app.
On the client side am doing the request with useEffect state and axios.
useEffect(() => {
axios.get("http://localhost:3001/vacations")
.then((response) => {
let vacationsResponse = response.data;
dispatch({ type: ActionType.GetAllVacations, payload: vacationsResponse })
}).catch(err => {
console.log("Failed to get data" + err)
})
}, [dispatch])
this is the server side:
const vacationsControllers = require("./Controllers/vacationsControllers");
const cors = require("cors");
server.use(cors({ origin: "http://localhost:3000" }));
server.use("/users", usersController);
server.use("/vacations", vacationsControllers);
server.listen(3001, () => console.log("Listening on http://localhost:3001"));
this is the vacationsControllers folder:
router.get("/", async (request, response) => {
let vacationsData = request.body;
try {
await vacationsDao.getAllVacations(vacationsData);
response.json();
console.log(vacationsData) *get this empty in the node terminal*
} catch (e) {
console.error(e);
response.status(600).json();
}
});
module.exports = router;
The sql execute (the vacationDao folder):
let connection = require("./connection-wrapper");
async function getAllVacations(vacationsData) {
const sql = `SELECT * FROM current_deals`;
await connection.executeWithParameters(sql);
return vacationsData;
}
module.exports = {
getAllVacations,
};

invalid json response body at http://localhost:3000/api/user/[object%20Object] reason: Unexpected token < in JSON at position 0

I'm using this example to create a simple authentication with Nextjs https://github.com/vvo/next-iron-session/tree/master/examples/next.js
but instead of fetching the user JSON object from Github (as the example does) im trying to do it from my mongodb database where i have some users.
I did this on my login.js file:
import fetchJson from "../../lib/fetchJson";
import withSession from "../../lib/session";
import { withIronSession } from "next-iron-session";
import { connectToDatabase } from "../../util/mongodb";
export default withSession(async (req, res) => {
const { db } = await connectToDatabase();
const { username } = await req.body;
const foundUser = await db.collection("users").findOne({"userName": username});
console.log(foundUser) // <--- this returns the user object on console just fine
const url = `http://localhost:3000/api/user/${foundUser}`;
try {
const { userName, email } = await fetchJson(url);
const user = { isLoggedIn: true, userName, email }
req.session.set("user", user);
await req.session.save();
res.json(user);
} catch (error) {
const { response: fetchResponse } = error;
res.status(fetchResponse?.status || 500).json(error.data);
}
});
And i have this code on my /api/user.js file:
import withSession from "../../lib/session";
import { connectToDatabase } from "../../util/mongodb";
export default withSession(async (req, res) => {
const user = req.session.get("user");
if (user) {
const { db } = await connectToDatabase();
const foundUser = await db.collection("users").findOne({"userName": user.userName, "email": user.email});
console.log("useri pi te user.js " + foundUser)
// in a real world application you might read the user id from the session and then do a database request
// to get more information on the user if needed
res.json({
isLoggedIn: true,
...user,
});
} else {
res.json({
isLoggedIn: false,
});
}
});
But i get "invalid json response body at http://localhost:3000/api/user/[object%20Object] reason: Unexpected token < in JSON at position 0" error even though i get the user object printed in the console just fine.
Any help would be appreciated!

Unable to fetch data from server due to serialization problem using NextJS?

I'm currently using axios and NextJS.
I currently have this code in my component:
export async function getServerSideProps(context) {
const data = await getVideo(context.query.id);
console.log('data: ', data);
// console.log('context: ', context);
console.log('context params: ', context.params);
console.log('context query: ', context.query);
if (!data) {
return { notFound: true };
}
return {
props: {
videoId: context.params.id,
videoSlug: context.params.slug,
videoContent: data
}
};
}
This getserverSideProps call the function of getVideo which looks exactly like this:
export const getVideo = (id) => async (dispatch) => {
dispatch({ type: CLEAR_VIDEO });
try {
console.log('Action file: ', id);
const res = await api.get(`/videos/${id}`);
return dispatch({
type: GET_VIDEO,
payload: res.data
});
} catch (err) {
dispatch({
type: VIDEO_ERROR,
payload: { msg: err.response?.statusText, status: err.response?.status }
});
}
};
Said function goes through my api function to make requests to backend:
import axios from 'axios';
import { LOGOUT } from '../actions/types';
import { API_URL } from '../config';
const api = axios.create({
baseURL: `${API_URL}/api/v1`,
headers: {
'Content-Type': `application/json`
}
});
/**
intercept any error responses from the api
and check if the token is no longer valid.
ie. Token has expired
logout the user if the token has expired
**/
api.interceptors.response.use(
(res) => {
res;
console.log('Res: ', res.data);
},
(err) => {
if (err?.response?.status === 401) {
typeof window !== 'undefined' &&
window.__NEXT_REDUX_WRAPPER_STORE__.dispatch({ type: LOGOUT });
}
return Promise.reject(err);
}
);
export default api;
It works great when doing POST, PUT,PATCH requests.
As you can see, I'm doing a console.log('data: ',data) but it returns [AsyncFunction (anonymous)] whenever I read the terminal; on the other hand, the front-end returns this error:
Server Error Error: Error serializing .videoContent returned from
getServerSideProps in "/videos/[id]/[slug]". Reason: function
cannot be serialized as JSON. Please only return JSON serializable
data types.
Does anyone knows how to solve this?
NOTE: I'm using react-redux, redux and next-redux-wrapper.
That is because your getVideo function returns another function. The right way to call it would be:
const data = await getVideo(context.query.id)()//<- pass in the dispatch here
But you should not use redux in the backend like that. I think you can completely remove it.
export const getVideo async (id) => {
try {
console.log('Action file: ', id);
const res = await api.get(`/videos/${id}`);
return res.data
});
} catch (err) {
return { msg: err.response?.statusText, status: err.response?.status }
}
};
// call
const data = await getVideo(context.query.id)

cloud function for sending fcm notifications to a collection of tokens

I am trying to send a notification whenever a new update to my database takes place. I have the onUpdate side working but I am new to FCM and I am stuck at the sending the notification.
The structure of the devices collection is:
+devices/
+tokenId/
-tokenId:njurhvnlkdnvlksnvlñaksnvlkak
-userId:nkjnjfnwjfnwlknlkdwqkwdkqwdd
The function that I have right now that gets stuck with an empty value of token is:
const functions = require('firebase-functions');
const admin = require("firebase-admin");
admin.initializeApp();
const db = admin.firestore();
const settings = { timestampsInSnapshots: true };
db.settings(settings);
.....
exports.fcmSend = functions.firestore
.document(`chats/{chatId}`).onUpdate((change, context) => {
const messageArray = change.after.data().messages;
const message = messageArray[(messageArray.length-1)].content
if (!change.after.data()) {
return console.log('nothing new');
}
const payload = {
notification: {
title: "nuevo co-lab",
body: message,
}
};
return admin.database().ref(`/devices`)
.once('value')
.then(token => token.val())
.then(userFcmToken => {
console.log("Sending...", userFcmToken);
return admin.messaging().sendToDevice(userFcmToken, payload)
})
.then(res => {
console.log("Sent Successfully", res);
})
.catch(err => {
console.log("Error: ", err);
});
});
I am not able to get the token from the database. It is null or undefined. Can anyone help me with this second part of the function?
Thanks a lot in advance!
Thanks Frank for the tip!
I managed to solve the problem with this code in case anybody needs it:
const payload = {
notification: {
title: "nuevo mensaje de co-lab",
body: message,
}
};
// Get the list of device tokens.
const allTokens = await admin.firestore().collection('devices').get();
const tokens = [];
allTokens.forEach((tokenDoc) => {
tokens.push(tokenDoc.id);
});
if (tokens.length > 0) {
// Send notifications to all tokens.
return await admin.messaging().sendToDevice(tokens, payload);
}else {
return null;
}