Error serializing `something` returned from getServerSideProps in `some page` - reactjs

I'm working on a project using next.js. it has a dynamic route using getServerSideProps. You can pass query to this page. folder structure is category/[title]. So it accepts category/[title]?{some query} URL. But when I type it in address bar I receive this error:
This is getServersideProps function (getLotsInCategory() and getCategories() are data fetcher of firebase. They're working in the other pages perfectly):
export async function getServerSideProps(context:any) {
let category:any=[]
let query:any
if(context.query!=undefined){
query=context.query
}
let title=context.params.title;
let lotsInCategory:any=[]
try{
console.log(query)
lotsInCategory=await getLotsInCategory(title)
if(query.subCategory!=undefined){
lotsInCategory=lotsInCategory.filter((el:any)=>query.subCategory.includes(el.subCategory)==true)
}
const categories:any=await getCategories();
category=categories.filter((el:any)=>el.categoryTitle==title)
category=category[0]
lotsInCategory= JSON.stringify(lotsInCategory)
category=JSON.stringify(category)
query=JSON.stringify(query)
}
catch(er){
console.log(er)
}
return {
props: {query,lotsInCategory,category} // will be passed to the page component as props
}
}
I've tried .json() instead of JSON.stringify(), but I received the same error.

At last, I found the real problem. I saw the real error in the terminal in vs code and it was denying permission from firebase. getLotsInCategory and getCategories are my firebase method that works in static pages prefect, But when I use dynamic pages I can't get data from the fire base . so this error solve by changing firebase configs!

Related

Fetching data with Supabase js and Next.js 13 returns an object (rather than array)

I am trying to fetch data from a Supabase table called "profiles" with Next.js 13 and the app directory. I am trying to take advantage of the new next.js fetching methods, my code looks as follows:
export const revalidate = 0;
export default async function getData() {
const { data: profiles } = await supabase
.from("profiles")
.select("*")
.eq("is_host", true);
console.log(profiles);
return { profiles };
if (!profiles) {
return <p>No hosts found</p>
}
The problem is that this code seems to be wrapping the array returned from Supabase in an object.
The data returned looks like this:
{data:
[
{
"id":"feef56d9-cb61-4c4d-88c6-8a8d7c9493d9",
"updated_at":null,
"username":"username",
"full_name":"Full Name",
"avatar_url":"URL",
"website":null,
"is_host":true,
"bio":null,
"languages":6
}
]
}
When I use useState and useEffect instead, the data is returned as expected, and I can map through it.
Does anybody have an idea why, and how I can prevent that?
Thanks in advance.
I worked it out, through a subsequent error, which I as able to solve thanks to the question I asked here and the helpful hints I got from there.
return { profiles };
Returns the array inside an object.
By removing the {} I was able to fetch the array inside of it.

Getting 500 | Internal Server Error when using getServerSideProps only on host (not local)

I know it's an old question but I couldn't resolve this issue. I have a dynamic page using ssr (getServerSidePros). It is working perfectly on my localhost (both of development and production mode), but when I publish it ,I see 500|Internal Server Error. In my console window I see this:
main-50de763069eba4b2.js:1 A client-side exception has occurred, see here for more info: https://nextjs.org/docs/messages/client-side-exception-occurred and I don't get any details.
This is my code
export async function getServerSideProps(context:any) {
var id:number=context.params.id
console.log(context.params.id)
var data:any={}
const getData=async()=>{
const response:any= await axios.get(`http://localhost:99/api/v1/Blog/${id}`)
data=response.data
return data
}
data=await getData();
data=JSON.parse(JSON.stringify(data))
return {
props: {data}, // will be passed to the page component as props
}
}
Some solutions I've tried:
1-adding "main":"index.js"
2-adding axios.defaults.httpsAgent=new https.Agent({rejectUnauthorized:false,})
3-using .json() instead of JSON.stringify()

SvelteKit - /routes/a/+page.server.ts fetch('/b/') url confusion, version #sveltejs/kit#1.0.0-next.512

When I try to fetch('/b/') within the load function of /routes/a/+page.server.ts it refuses to accept local URL references.
Instead of being able to do
/b/
I have to use url:
http://localhost:3000/b/
Because the fetch() call refuses to accept the url (error: "Failed to parse URL"). I'm trying to consume my own api to reuse code. I thought SvelteKit fetch was supposed to support these local routes for api calls?
The example in documentation: https://kit.svelte.dev/docs/routing
Shows +page.svelte calling url '/api/add/' from fetch(), but not from within +page.server.ts - is there some reason they would not allow the same convention?
Thank you.
SvelteKit developers got back to me and indicated that there are two choices of fetch(url) function.
// /src/routes/test/[param0]/[param1]/+page.server.ts
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ params }) => {
// ERROR: this will fail with URL parsing
let fetchResult = fetch('/api/target/');
}
SvelteKit aware fetch passed as load function parameter:
export const load: PageServerLoad = async ({ params, fetch }) => {
// NOTE: fetch was passed in as a parameter to this function
let fetchResult = fetch('/api/target/');
}
Confusing!
When I have an internal API route I want to hit within my sveltekit application, I structure it as so:
├src
|├routes
||├api
|||├example
||||├+server.js
Now, elsewhere in the app, you can hit the route like so using the fetch api:
let res = await fetch("/api/example")
refer to this section of the SvelteKit docs for a better understanding:
https://kit.svelte.dev/docs/routing

API caching for next JS

I'm building an app with Next.js... we have 100k+ pages and content changes daily, so using SSR and getServerSideProps.
Some of our data is coming from a headless CMS provider that charges by the request. I'd like to cache the API responses from this server for 24hrs.
What is the best way of going about this?
Is there a common library most folks use to do this?
Just looking for suggestions of approaches I should investigate (or great examples of how to do this).
I used this npm package:
https://www.npmjs.com/package/memory-cache
And then something like this:
import cacheData from "memory-cache";
async function fetchWithCache(url, options) {
const value = cacheData.get(url);
if (value) {
return value;
} else {
const hours = 24;
const res = await fetch(url, options);
const data = await res.json();
cacheData.put(url, data, hours * 1000 * 60 * 60);
return data;
}
}
Then if you want to fetch something with using the cache just call this function. Or it can be used as a midware in the requests. It checks if the data is already in the cache and returns it, or if not - it puts the data into the cache under the key. The key can be anything, I am using the url for instance.
In addition to Tobias Lins' answer:
At least if deploying on Vercel, you can use set Cache-Control headers in getStaticProps, getServerSideProps, API routes, etc to cache responses on Vercel's edge network. This solution does not require any additional dependencies and very minimal code.
api route example - source Vercel
// pages/api/user.js
export default function handler(req, res) {
res.setHeader('Cache-Control', 's-maxage=86400');
res.status(200).json({ name: 'John Doe' });
}
Example in getServerSideProps - Source NextJS
// This value is considered fresh for ten seconds (s-maxage=10).
// If a request is repeated within the next 10 seconds, the previously
// cached value will still be fresh. If the request is repeated before 59 seconds,
// the cached value will be stale but still render (stale-while-revalidate=59).
//
// In the background, a revalidation request will be made to populate the cache
// with a fresh value. If you refresh the page, you will see the new value.
export async function getServerSideProps({ req, res }) {
res.setHeader(
'Cache-Control',
'public, s-maxage=10, stale-while-revalidate=59'
)
return {
props: {},
}
}
I believe you'd want to use:
res.setHeader('Cache-Control', 's-maxage=1440000')
Here are some other useful links for caching on Vercel:
https://vercel.com/docs/concepts/functions/edge-caching
https://vercel.com/docs/concepts/edge-network/overview
https://vercel.com/docs/concepts/edge-network/caching
https://vercel.com/docs/concepts/edge-network/headers
For your specific case, you also may want to look into using getStaticPaths with getStaticProps. You can use fallback: true on getStaticPaths to only build pages when they're visited (you can still build your post popular pages at initial build time).
https://nextjs.org/docs/basic-features/data-fetching#the-fallback-key-required
I know this is an old post, but for others googling (at least those deploying on Vercel), these solutions should help where revalidate in getStaticProps does not.
You could use getStaticProps from Next.js for SSG
They currently have a revalidate property that you can return, that defines how often the content should be re-fetched.
Take a look here:
https://nextjs.org/blog/next-9-5#stable-incremental-static-regeneration
This is how we did it without any 3rd party libraries, as in our use-case we only had to cache a relatively smaller amount of global data(header/footer menus) which was shared across the site.
The data was coming from a CMS via GraphQL.
We ran an async method getGlobalData on each page from on getStaticProps method and then returned the cached data to the page component via props.
import fs from 'fs';
import path from 'path';
// Cache files are stored inside ./next folder
const CACHE_PATH = path.join(__dirname, 'globalData.json');
export default async function getGlobalData() {
let cachedData;
// #1 - Look for cached data first
try {
cachedData = JSON.parse(fs.readFileSync(CACHE_PATH, 'utf8'));
} catch (error) {
console.log('❌ CACHE NOT INITIALIZED');
}
// #2 - Create Cache file if it doesn't exist
if (!cachedData) {
// Call your APIs to-be-cached here
const data = await fetchGlobalData();
// Store data in cache files
// this always rewrites/overwrites the previous file
try {
await fs.writeFileSync(
CACHE_PATH,
JSON.stringify(data),
err =>throw err
);
console.log('💾 CACHE FILE WRITTEN SUCCESSFULLY');
} catch (error) {
console.log('❌ ERROR WRITING MEMBERS CACHE TO FILE\n', error);
}
cachedData = data;
}
return cachedData;
}
Call getGlobalData method from getStaticProps.
export async function getStaticProps({ preview = false }) {
const globalData = await getGlobalData();
// call other page-specific/non-shared APIs here
// ...
return { props: { globalData } };
}
References
https://flaviocopes.com/nextjs-cache-data-globally/
Note if you get an error saying fs or path is unknown or invalid, then please understand that, the above code is supposed to be running or referenced "serverside" i.e only inside getStaticProps or getServerSideProps. If you import and reference it "browser-side", say somewhere inside your components or on the page (other than methods mentioned above), then you will get an error, as there is no filesystem(fs) or path modules on browser. They are only available on node.

Meteor + Reactjs: Incoming Token Parameter

My application has functionality to send an invitation to create an account.
The link is created and sent using a server side method, the invitationId stored in a collection.
> ${Meteor.absoluteUrl(`accept-invite/${invitationId}`)}
> http://myapp.com/accept-invite/emwwKwZkjhWE5KrYs
This works good. Navigation to the accept-invite page is successful (React Router v4)
My error says params is undefined as I can not seem to grab invitiationId "emwwKwZkjhWE5KrYs" or token upon loading the accept-invite/:token
My accept-invite page withTracker
export default withTracker(({ params }) => {
const invitationId = params.token;
const subscription = Meteor.subscribe('invitations.accept', invitationId);
return{
loading: !subscription.ready(),
invitation: Invitations.findOne(invitationId),
};
})(AcceptInvitation);
my error is params is undefined, invitation_id / token value is not being assigned any upon loading my accept-invite page, stumping myself because I feel I am missing a piece of logic!
The above and first comment worked for me.
export default withTracker(({match}) => {
const invitationId = match.params.token.replace('=','');
this let me take incoming parameter defined as a :/token in React Router v4 (Meteor)
example http://maddog.com/accept-invite/:=youthebest
invitation id is equal to youthebest

Resources