I am not getting any error when browsing page or url but when trying to npm run build getting this error Generating static pages (0/8)TypeError: Cannot read properties of undefined (reading 'blog_slug')
here is my full code:
I aslo want to show 404 page if dynamic url not exits. Right now I am getting this error for invalid url . I also set
if (res != 200) {
return {
notFound: true,
};
}
but didn't work. here is my full code:
export async function getStaticPaths() {
const search_url = "https://backendapi.mydomain.com/blog-list/";
const search_result = await fetch(search_url);
const search_data = await search_result.json(search_result);
const paths = search_data.map((data) => {
return {
params: {
id: data.blog_slug,
},
};
});
return {
paths,
fallback: true, // false or 'blocking'
};
}
export async function getStaticProps(context) {
const id = context.params.id;
const res = await fetch(`https://mydomain/blog-api/${id}`);
const Blog = await res.json();
const search_url = "https:/mydomain/blog-list/";
const search_result = await fetch(search_url);
const search_data = await search_result.json(search_result);
if (res != 200) {
return {
notFound: true,
};
}
return {
props: {
data: Blog,
search_data: search_data,
},
};
}
here is my jsx look like:
function blog_details({ data, search_data }) {
return (<h1>data.blog_slug<h1/)
}
Related
i am initializing a node js app with crucial data for the app to work from a database in index.js.
index.ts
import {getInitialData} from 'initData.ts';
export let APP_DATA: AppData;
export const initializeAppData = async () => {
try {
APP_DATA = (await getInitialData()) as AppData;
if (process.env.NODE_ENV !== 'test') {
initializeMongoose();
startServer();
}
} catch (error) {
console.log(error);
}
};
initData.ts
let dbName: string = 'initialData';
if (process.env.NODE_ENV === 'test') {
dbName = 'testDb';
}
const uri = `${process.env.MONGODB_URI}/?maxPoolSize=20&w=majority`;
export async function getInitialData() {
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db(dbName);
const configCursor = database
.collection('config')
.find({}, { projection: { _id: 0 } });
const config = await configCursor.toArray();
const aaoCursor = database
.collection('aao')
.find({}, { projection: { _id: 0 } });
const aao = await aaoCursor.toArray();
return { config, aao };
} catch {
(err: Error) => console.log(err);
} finally {
await client.close();
}
}
I'm using this array in another file and import it there.
missionCreateHandler
import { APP_DATA } from '../index';
export const addMissionResources = (
alarmKeyword: AlarmKeyword,
newMission: MissionDocument
) => {
const alarmKeywordObject = APP_DATA?.aao.find(
(el) => Object.keys(el)[0] === alarmKeyword
);
const resourceCommand = Object.values(alarmKeywordObject!);
resourceCommand.forEach((el) => {
Object.entries(el).forEach(([key, value]) => {
for (let ii = 1; ii <= value; ii++) {
newMission.resources?.push({
initialType: key,
status: 'unarranged',
});
}
});
});
};
I'm setting up a mongodb-memory-server in globalSetup.ts for Jest and copy the relevant data to the database from json-files.
globalSetup.ts
export = async function globalSetup() {
const instance = await MongoMemoryServer.create({
instance: { dbName: 'testDb' },
});
const uri = instance.getUri();
(global as any).__MONGOINSTANCE = instance;
process.env.MONGODB_URI = uri.slice(0, uri.lastIndexOf('/'));
process.env.JWT_SECRET = 'testSECRET';
const client = new MongoClient(
`${process.env.MONGODB_URI}/?maxPoolSize=20&w=majority`
);
try {
await client.connect();
const database = client.db('testDb');
database.createCollection('aao');
//#ts-ignore
await database.collection('aao').insertMany(aao['default']);
} catch (error) {
console.log(error);
} finally {
await client.close();
}
};
missionCreateHandler.test.ts
test('it adds the correct mission resources to the array', async () => {
const newMission = await Mission.create({
address: {
street: 'test',
houseNr: 23,
},
alarmKeyword: 'R1',
});
const expected = {
initialType: 'rtw',
status: 'unarranged',
};
addMissionResources('R1', newMission);
expect(newMission.resources[0].initialType).toEqual(expected.initialType);
expect(newMission.resources[0].status).toEqual(expected.status);
});
When runing the test, i get an 'TypeError: Cannot convert undefined or null to object at Function.values ()'. So it seems that the APP_DATA object is not set. I checked that the mongodb-memory-server is set up correctly and feed with the needed data.
When i hardcode the content of APP_DATA in index.ts, the test runs without problems.
So my questions are: How is the best practice to set up initial data in a node js app and where to store it (global object, simple variable and import it in the files where needed)? How can the test successfully run, or is my code just untestable?
Thank you!
I am trying to go to /users/0 from /users page.
In /users/[id].js
export async function getStaticProps(context) {
const { params } = context;
const { id } = params.id;
const transformedUsers = await getData();
const foundUser = transformedUsers.find((user) => user.id === id);
if (transformedUsers.length === 0) {
return {
notFound: true,
};
}
return {
props: {
user: foundUser,
},
};
}
export async function getStaticPaths() {
const transformedUsers = await getData();
const ids = transformedUsers.map((user) => user.id);
const pathsWithParams = ids.map((id) => ({ params: { id } }));
return {
paths: pathsWithParams,
fallback: false,
};
}
After I run the commands npm run build
└ ● /users/[id] 298 B 82.4 kB
I am getting this in the console. But when I start the server with npm start and go to /users/0 i am getting 404 not found.
How to provide paths with getStaticPaths?
I am trying to set up a dynamic page in Next.js with getStaticPaths(). I have it 90% of the way there, but I can't get the getStaticProps() function to reference the URL query so that it loads the proper info.
My code is:
//Get Static Paths
export async function getStaticPaths() {
const paths = await (
await youtube.get("search?")
).data.items.map((video: any) => {
const id = video.id.videoId;
return { params: { id } };
});
return {
paths: paths.map((path: any) => path),
fallback: false,
};
}
//Get Static Props
export async function getStaticProps(context: any) {
const { query = "" } = context.params.query;
const videos = await (await youtube.get("search?")).data.items;
const video = videos.find((vid: any) => {
return vid.id.videoId === query;
});
return {
props: {
video,
},
revalidate: 10,
};
}
I am receiving the error:
Error: Error serializing `.video` returned from `getStaticProps` in "/media/videos/[id]".
Reason: `undefined` cannot be serialized as JSON. Please use `null` or omit this value.
If I replace the 'query' variable in the getStaticProps() function with the actual ID of the video I am trying to load, everything goes through fine and the page loads. But then this is not dynamic, and is not using the url query to match with the proper video like I want.
Here is the working, non-dynamic code with a manually typed in ID to force a match.
//Get Static Props
export async function getStaticProps(context: any) {
// It's important to default the slug so that it doesn't return "undefined"
const { query = "" } = context.params;
const videos = await (await youtube.get("search?")).data.items;
const video = videos.find((vid: any) => {
return vid.id.videoId === "_TACZtT1irI";
});
return {
props: {
video,
},
revalidate: 10,
};
}
How can I make sure that the 'video' variable is accessing the url query? It should be grabbing it with context.params, but that is not working, what am I doing wrong?
I figured it out. This is working.
//Get Static Props
export async function getStaticProps(context: any) {
// It's important to default the slug so that it doesn't return "undefined"
const { query = "" } = context.params;
const videos = await (await youtube.get("search?")).data.items;
const video = videos.find((vid: any) => {
return vid.id.videoId === context.params.id;
});
return {
props: {
video,
},
revalidate: 10,
};
}
I have a bit of code here that keeps failing due to Error: Fixture "activityLogPage" has unknown parameter "TestRailController", I am sure this is user error on my end but I cant quite figure it out. Below this is the TestRailController I am trying to call.
activitylogpage.ts --->
import { ActivityLogSelectors } from '../../specs/types/activityLog.type';
import { Page } from '#playwright/test';
import test from '../../common/testrail/fixtures';
export const activityLogSelectors: ActivityLogSelectors = {
datasource_id: 'label[for^=datasource_id]',
categories: 'label:has-text("Access Control: Authentication")',
policy: 'input[id^=downshift]',
};
type ActivityLogFixtures = {
activityLogPage: Page;
};
const activityLogTest = test.extend<ActivityLogFixtures>({
activityLogPage: async ({ page, TestRailController }, use) => {
TestRailController.startNewTest('1');
await page.goto('/');
await page.waitForURL(/risk-posture/i);
await page.click('a:has-text("Activity Log")');
await page.waitForSelector('text=Clear');
await use(page);
},
});
export default activityLogTest;
fixtures.js. --->
const base = require('#playwright/test');
const TestRailController = require('./testrail.interface.js');
module.exports = base.test.extend({
// https://playwright.dev/docs/test-advanced/#testinfo-object
testrailController: async ({ browser }, use, testInfo) => {
const testrailController = new TestRailController();
await use(testrailController);
for (const context of browser.contexts()) {
// eslint-disable-next-line no-await-in-loop
await context.close();
}
// only update testrail when process.env.APP_VERSION is valid string
// testInfo is needed here because this below part will be run before test started while testInfo is null
// use testrail feature for saving test-result
if (appVersion && testInfo) {
await testrailController.updateAllTests(testInfo);
} else {
console.log('Env var APP_VERSION or testInfo is not available, will not update testrail case');
}
},
});
I have a page with a list of objects called stories that displays all my stories in an array. I also have a detail page with displays an individual story.
I want to click on a link on any given story on the list, then it will navigate me to the individual story. I want to use _id as my dynamic part of the URL, as shown in the GraphQL below.
My Graphql
export const listAllStories = () => {
const query = gql`
query StoryEntries($size: Int) {
storyEntries(_size: $size) {
data {
_id
_ts
name
premises{
data{
_id
content
}
}
createdAt
}
}
}
`
return graphQLClient
.request(query, { size: 999 })
.then(({ storyEntries: { data } }) => data)
}
IN MY PAGES API I HAVE
export default async function handler(req, res) {
const handlers = {
GET: async () => {
const storyEntries = await listAllStories()
res.json(storyEntries)
},
}
if (!handlers[req.method]) {
return res.status(405).end()
}
await handlers[req.method]()
}
ON THE STORY LIST PAGE I HAVE
const ENTRIES_PATH = '/api/entries/allStories'
const useEntriesFlow = ({ initialEntries }) => {
const { data: entries } = useSWR(ENTRIES_PATH, {
initialData: initialEntries,
})
const EntryItem = ({ entry }) => (
<>
{entries?.map((entry) => (
{entry.name}
<Link href="/story/[storyId]" as={`/story/${entry._id}`}>
<a>Go</a>
</Link>
))}
</>
)
export const getStaticProps = async () => ({
props: {
initialEntries: await listAllStories(),
},
revalidate: 1,
})
This is fine and works.
**AND THEN ON THE DETAIL PAGE FOR EACH INDIVIDUAL STORY [storyId].js I HAVE **
export default function Story({story}) {
const router = useRouter()
const storyId = router.query.storyId
return(
<>
<h5>hello {story._id}</h5>
</>
)
}
export const getStaticPaths = async () => {
const res = await fetch(`${server}/api/entries/allStories/`);
const { data } = await res.json();
const paths = data.map(story => {
return {
params: { id: story._id.toString() }
}
// trying to get the _id from each story
})
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const { storyId } = context.query; // Your dynamic page is [storyId].js
const server = "http://localhost:3000";
const res = await fetch(`${server}/api/entries/allStories/${storyId}`);
// trying to get the params._id from each story
console.log(res)
const { data } = await res.json();
return {
props: { story: data }
}
}
ERROR
TypeError: Cannot read properties of undefined (reading 'map')
QUESTION
All I want to do is click on any story link, then it takes me to the details page, via the _id. I have tried a few things but I'm doing something (or some things) wrong.
Any help will be greatly appreciated.
EDIT AFTER. ERROR I'M GETTING. I'm not able to map my results on getStaticPaths
export const getStaticProps = async (context) => {
const { storyId } = context.query; // Your dynamic page is [storyId].js
const server = "YOUR SERVER VARIABLE";
const res = await fetch(`${server}/api/entries/allStories/${storyId}`);
// trying to get the params._id from each story
const { data } = await res.json();
return {
props: { story: data }
}
}
uncomment
const router = useRouter()
const storyId = router.query.storyId
// some helpful links
// https://nextjs.org/docs/basic-features/data-fetching#the-paths-key-required
// https://stackoverflow.com/questions/65783199/error-getstaticpaths-is-required-for-dynamic-ssg-pages-and-is-missing-for-xxx
export const getStaticPaths = async () => {
const server = "http://localhost:3000";
const data = await fetch(`${server}/api/entries/allStories/`).then(res => res.json() )
const paths = data.map(({_id}) => ({
params: { storyId: _id },
}))
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const storyId = context.params.storyId; // Your dynamic page is [storyId].js
const server = "http://localhost:3000";
// const res = await fetch(`${server}/api/entries/allStories/${storyId}`);
// trying to get the params._id from each story
// single api call (here)
const res = await fetch(`${server}/api/entries/allStories/`);
// removing const { data } because the data will be returned when calling res.json()
const data = await res.json();
// instead of the calling the single api (just a fix not recommended to access [0] directly )
return {
props: { story: data.filter(story => story._id === storyId)[0] }
}
}