getServerSideProps is not updating data with import - javascript

I'm having a problem with getServerSideProps in NextJS not updating values on page load. It seems to be having the same effect as using getStaticProps when calling from data that is an imported JSON file.
Here's the applicable code:
/update/[...id].js
import { hasPermission, getPermissions } from '../../lib/permissions'
...
//in the page function I use the ternary to check permission of the user
{ (hasPermission(session.user.email, `${params.id[0]}-edit`, permissions)) ? <HasPerm /> : <NoPerm /> }
...
export async function getServerSideProps(context) {
const params = context.query
const permissions = getPermissions()
return {
props: { params, permissions }
}
}
/lib/permissions.js
import permissions from '../db/users.json'
export function hasPermission(username, group, perm = false) {
if (!perm)
perm = permissions
if (username in perm && perm[username].groups.includes(group)) {
return true
}
if (perm.all.groups.includes(group)) {
return true
}
return false
}
export function getPermissions() {
return permissions
}
For SSR pages that were understandably doing this to begin with, I pass in the permissions to the page in getStaticProps and pass those values into my hasPermission() function in those pages so that they are revalidated on permissions change. Yet there is no revalidation option in getServerSideProps so the data is not revalidated at all. I was using getInitialProps before but pretty much everyone discourages that because it disables ASO.
How do I use getServerSideProps such that my imported json is at least revalidated?

I ended up not using the json import and used fs instead for other reasons but the issue is resolved by using dynamic imports in the getServerSideProps:
export async function getServerSideProps(context) {
const permissions = await import('../db/users.json')
}
Also don't make my same mistake of passing the whole permissions database to every user as was being done by using a function like getPermissions in getStaticProps to get the data to the hasPermission function in the page. Instead, only serve data with getServerSideProps if the user has permission. In other words, ensure you're holding the data back from the server-side. Then you can also pass through an individual's permissions to the page if you need to, like for displaying a message saying you don't have permission.

Related

Routing to page A or Page B based on API response

I am stuck on an issue. Let's say I have a home page. From this home page, I want to route to either page A or page B.
I have a list of items on the home page and what I need to do is when I click on any item in the list, it makes a GET API call, and based on one field in the response which is a boolean, I either need to redirect to page A or page B.
Basically, I need to call an API on the click of the item and get the response before it is routed to either Page A or Page B.
Many thanks in advance
if you're using Next.JS, use useRouter prop to achieve this.
for example
import {useRouter} from "next/router";
export default function Page() {
const router = useRouter()
async function route() {
let res = await apiFunctionCall();
if (res) {
await router.replace({
pathname: '/page1'
})
} else {
await router.replace({
pathname: 'page2'
})
}
}
}
The closest solution I could get is to create a Lazy loaded component which calls the API and then based on the response, routes to either page A or Page B.
Before routing to the correct page based on the data that has been returned, the data first needs to be stored in a variable. The data will be stored in the res variable. The if else statement will then route to either page A or B based on the data.
<code>const Response = res.data;
if(Response.type === 'A'){
this.props.history.push('/page-a');
} else {
this.props.history.push('/page-b');
}
</code>

How to show error page without changing current URL

I have a custom 500 error page called 500.tsx and I want to able to show this page when request from client fails with status of 500, but keeping client on old url (for example /auth/register). I have a axios listener on error which should do all the work. But could not find a way to do this using next/router. Any help appreciated
Didn't realize OP wanted to show 500 page at first.
You could look into router.isFallback but I am not entirely sure if that's appropriate for this.
It's supposed to be for Page Loading Indicators, but in your case, since the page will never load, it could work.
https://nextjs.org/docs/basic-features/data-fetching#fallback-true
return router?.isFallback
? <Custom500Page/>
: <RegularPage/>
You can set this variable from getStaticPaths method, which runs during build time and is usually used for [slug] pages.
// This function gets called at build time
export async function getStaticPaths() {
// Fetch paths to your slug pages here
return {
// paths,
fallback: true
}
}
Showing 404 page is quite straight forward & This is how we do.
Rendering 404 page
You can conditionally export a variable called notFound as true from getStaticProps method.
If the URL is invalid and you don't data to render the page, you simply pass that notFound prop as true and then the default or custom 404 page will show up automatically preserving your invalid url.
// This function gets called at build time
export async function getStaticProps({ params, preview = false }) {
let pageData
try {
// fetch pageData from API here
} catch (error) {
// catch errors
}
// check validity or emptyness of data
// invalid URL (slug) -> empty data from API
// valid URL (slug) -> valid data from API
return isObjectEmpty(pageData)
? { notFound: true }
: {
props: {
pageData
// pass other props to the page
}
}
}
NextJS Docs on getStaticProps & not-found
https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation

NextJS - Can I build a system that would be using the path or the query parameter?

For legacy reason, I need to support a blog link that would look like /blog?article=id-of-article. I would like to support pre-rendering using NextJS and have blog url being /blog/id-of-article.
What would be the best way to support this use case ? I could do a permanent redirect or make sure both URLs render the same page. I am new with NextJS and not sure how to proceed.
Thank you !
Here is my solution.
//blog/index.js
export async function getServerSideProps(context) {
const { query } = context;
console.log(query);
if (query.article) {
return {
redirect: {
destination: `blog/${query.article}`
}
}
}
// normal action
return { props: {} }
}
By using this code, if there is no query parameter named article, this route would run normally. But if there is, this would redirect the page to /blog/:article_id

Nextjs: render page or show 404 page based on user data

We are currently working on a Nextjs project which includes a number of dynamic pages. We have come to a stage where we are defining the dynamic paths using getStaticProps and getStaticPaths. So far we managed to define 404 pages in dynamic pages with a similar structure to the below:
export async function getStaticProps(context) {
const { id } = context.params
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
const user = await response.json()
return {
props: { user },
notFound: Object.keys(user).length === 0
}
}
export function getStaticPaths() {
return {
paths: [],
fallback: 'blocking'
}
}
Using version 10's notFound value and fallback: blocking allows us to have the page return a 404 status code (for some reason fallback: true returns a 200 status code).
The issue we currently have is to display a 404 page to pages that depend on user data such as username or user locale. One way we thought we could solve this is by having those pages as Server Side generated rather than Static Site generated by using getServerSideProps:
export async function getServerSideProps(context) {
const userId = getCookie('user_id')
const response = await fetch(`___/checkUserAccess/${userId}`)
const access = await response.json()
return {
props: { ... },
notFound: !access.userAllowed
}
}
I suppose I am answering my own question here as going for Server Side for these pages to show 404 pages based on user data seems logical. However the concern is the impact it may have on the website as a whole. These pages could easily end up being hundreds of pages.
Should we be concerned about this? Or maybe there's another way to go about solving this?

How to call a serverless function in Next.js getStaticPaths [duplicate]

This question already has an answer here:
Fetch error when building Next.js static website in production
(1 answer)
Closed 11 months ago.
I am using Next.js with the Vercel deployment workflow, I am following this guide to try and setup page generation at buildtime. The specific section shows the following example to generate pages based on an external API's response:
// This function gets called at build time
export async function getStaticPaths() {
// Call an external API endpoint to get posts
const res = await fetch('https://.../posts')
const posts = await res.json()
// Get the paths we want to pre-render based on posts
const paths = posts.map(post => ({
params: { id: post.id },
}))
// We'll pre-render only these paths at build time.
// { fallback: false } means other routes should 404.
return { paths, fallback: false }
}
// This also gets called at build time
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
// Pass post data to the page via props
return { props: { post } }
}
I want to do this exactly, however I wrote my API as a Node.js serverless function within the same code repository, it is not an external api.
I tried to do the following to call on my api:
// This function gets called at build time
export async function getStaticPaths() {
const res = await fetch('/api/get-designs');
const designs = await res.json();
// Get the paths we want to pre-render based on posts
const paths = designs.map(design => ({
params: { id: design.id },
}))
return {
// Only posts returned by api are generated at build time
paths: paths,
// Enable statically generating additional pages
fallback: true,
}
}
However I get an error that the fetch api url must be absolute. Because of the way Vercel deploys, I won't always have the same deployment URL, so I don't think I can just use a hardcoded value here. Also, I am suspecting that because this function runs at buildtime, that my function is not running yet, therefore can not be called. I am still trying to wrap my head around this Next.js statically generated site workflow, but basically I am confused because they seem to encourage using serverless functions, and this getStaticPaths method for page generation, but they don't seem to work together unless I am missing something.
Is there a way I can run my api to get these results at build time? Any guidance would be much appreciated!
Thanks!
In this case, we can extract the server logic into a function and that function can be used directly inside your api route file. So, for CR we can use /api/whateverRoute and inside getStaticPaths we can use that function itself directly.

Categories