How can I change the status codes for my pages using the App Directory?
Answered
White-crowned Sparrow posted this in #help-forum
White-crowned SparrowOP
Before using the page directory, where getServerSideProps was allowed, I could set the status code easily for any page by returning
return {
statusCode:...,
props: {
.... }
};
But now using the App directory I cant find a way to do that. My Api returns the status code I should deliver to my page and I want to modify my status codes for every page.
I tried many things but still no success.
I am using this way to get my data for my page. But my api delivers the status code i should print, and I want to pass that status code to the response of the page.
How can I achieve that ?
I expect to change the status code and see it here in the network tab
return {
statusCode:...,
props: {
.... }
};
But now using the App directory I cant find a way to do that. My Api returns the status code I should deliver to my page and I want to modify my status codes for every page.
I tried many things but still no success.
async function getData() {
const res = await fetch('https://api.example.com/...')
return res.json()
}
export default async function Page() {
const data = await getData()
return <main data={data}></main>
}I am using this way to get my data for my page. But my api delivers the status code i should print, and I want to pass that status code to the response of the page.
How can I achieve that ?
I expect to change the status code and see it here in the network tab
Answered by White-crowned Sparrow
@Giant panda Please do so.
Well what I did is the following. I implemented a middleware.ts
This is my page.
This is my not-found
Well what I did is the following. I implemented a middleware.ts
import { NextResponse, NextRequest } from 'next/server';
import { getData } from './api/getData';
export async function middleware(request: NextRequest) {
const res = await getData(request.nextUrl.pathname);
if (res?.response.statusCode === 301) {
const redirectPath = new URL(res.response.responseHeaders.Location[0]);
return NextResponse.redirect(
new URL(
redirectPath.pathname + (request.nextUrl.searchParams ? `/?${request.nextUrl.searchParams}` : ''),
request.url
), 301
);
}
const headers = new Headers(request.headers);
headers.set('request-pathname', request.nextUrl.pathname);
return NextResponse.next({
request: {
headers,
},
});
}
export const config = {
matcher: '/((?!api|_next/static|_next/image|favicon.ico).*)',
};This is my page.
import type { Metadata } from 'next';
import { notFound } from 'next/navigation';
import { getData } from '../../api/getData';
import Partials from '../../components/partials/Partials';
export default async function Page() {
const data = await getData();
if (!data || data.response.statusCode === 404) notFound();
return <Partials context={data} />;
}This is my not-found
import Link from 'next/link';
import { getData } from '../../api/getData';
import Partials from '../../components/partials/Partials';
import { Typography } from '../../components/UI/Typography';
import styles from './layout.module.scss';
export default async function NotFound() {
const data = await getData();
return (
<>
<div>
<Typography as="h1" variant="2xl">
Blablabla
</Typography>
{data?.areas?.main?.map((widget) => (
<Partials key={widget.id} context={widget} />
))}
</>
);
}35 Replies
White-crowned SparrowOP
White-crowned SparrowOP
Anyoneeee ? ðŸ˜
jsut a question, why do you need the status code? what for?
@White-crowned Sparrow Before using the page directory, where getServerSideProps was allowed, I could set the status code easily for any page by returning
return {
**statusCode**:...,
props: {
.... }
};
But now using the App directory I cant find a way to do that. My Api returns the status code I should deliver to my page and I want to modify my status codes for every page.
I tried many things but still no success.
async function getData() {
const res = await fetch('https://api.example.com/...')
return res.json()
}
export default async function Page() {
const data = await getData()
return <main data={data}></main>
}
I am using this way to get my data for my page. But my api delivers the status code i should print, and I want to pass that status code to the response of the page.
How can I achieve that ?
I expect to change the status code and see it here in the network tab
Atlantic salmon
I am 99% sure that is not possible at all on pages, since everything is managed by NextJS and what goes under the hood is decently complex
@alfon jsut a question, why do you need the status code? what for?
White-crowned SparrowOP
I am building an application for a newspapper. My API delivers everything, even the 404 page, but with dynamic-data. What I mean is that when an article for example doesn't exist, I still get data (with teasers of top articles for example) that I want to print for the page.
Next13 - app directory gives me the choise of the notFound page. But this page doesn't accept any data, it can be only static. But It has to be dynamic in my case.
So all this time I am trying to change the status code - as it was POSSIBLE very easily using the getServerSideProps, in order not to use the notFound page.
So for the time being, I see 2 choices. The first one is to use the notFound page, which returns 404 but I cant use my API response. And the second choice is to use my actual data, but in that case I dont get a 404 but a 200, which is horrible for google.
Next13 - app directory gives me the choise of the notFound page. But this page doesn't accept any data, it can be only static. But It has to be dynamic in my case.
So all this time I am trying to change the status code - as it was POSSIBLE very easily using the getServerSideProps, in order not to use the notFound page.
So for the time being, I see 2 choices. The first one is to use the notFound page, which returns 404 but I cant use my API response. And the second choice is to use my actual data, but in that case I dont get a 404 but a 200, which is horrible for google.
White-crowned SparrowOP
@alfon because then, in the case of my not found page, i cannot have a 404, and i get a 200. Thats what i was trying the first place. But i cannot change the status code!
White-crowned SparrowOP
@alfon I also tried the middleware, and NextResponse.next({status:xxx}), but it doesnt work. The status code doesnt change.
@White-crowned Sparrow <@194128415954173952> because then, in the case of my not found page, i cannot have a 404, and i get a 200. Thats what i was trying the first place. But i cannot change the status code!
but in the end it still shows your notfound page no? why does the status code matter
White-crowned SparrowOP
It matters for the SEO people and google. At the end, this is what I am asked to do. Take this API response, and give me the page with those data, and this status code. Thats the task u know 🙂
right i forgot SEO is still your concern 🙃
hmmm have you tried parallel routes then?
but maybe perhaps it wouldn't give 404 error code nvm
does SEO cares if it returns 404 even if theres a page?
maybe instead of error you can display not-found here
White-crowned SparrowOP
Nooooo. whats that ?
* i just managed with a hacky way to have what I want, but i am not sure its the best approach. What I just did today is use a middleware, set in the headers the request.nextUrl.pathname, and consume it from the notFound page by making another call to my API and get the data and print them in the notFound page. Its a mess but it works. I dont understand why next13 app directory doesnt give me the possibility to easily change my status code. With getserversideProps we could easily do that.
* i just managed with a hacky way to have what I want, but i am not sure its the best approach. What I just did today is use a middleware, set in the headers the request.nextUrl.pathname, and consume it from the notFound page by making another call to my API and get the data and print them in the notFound page. Its a mess but it works. I dont understand why next13 app directory doesnt give me the possibility to easily change my status code. With getserversideProps we could easily do that.
@White-crowned Sparrow Nooooo. whats that ?
* i just managed with a hacky way to have what I want, but i am not sure its the best approach. What I just did today is use a middleware, set in the headers the request.nextUrl.pathname, and consume it from the notFound page by making another call to my API and get the data and print them in the notFound page. Its a mess but it works. I dont understand why next13 app directory doesnt give me the possibility to easily change my status code. With getserversideProps we could easily do that.
probably the reason why pages dir continues to work in nextjs13 :/
White-crowned SparrowOP
Thats true, but the app directory should give us more possibilities, not less.
Thanks for ur time, I will describe my solotution tomorrow to the thread, it would be super if u can give me feedback.
ðŸ™
Thanks for ur time, I will describe my solotution tomorrow to the thread, it would be super if u can give me feedback.
ðŸ™
White-crowned SparrowOP
@alfon The crazy thing is that using a middleware.ts and Nextresponse, u can do the following: return NextResponse.next({status.xxx})
It accepts the status property, but it does nothing!!! The status code remains 200
It accepts the status property, but it does nothing!!! The status code remains 200
White-crowned SparrowOP
yes but if you do nextResponse.redirect(redirect.url, request.url, 301) then u get 301 and not 307 for example
yes thats because that wont get through the filesystem routes
White-crowned SparrowOP
i see thx
Giant panda
Oh I have the very same problem also in a news website where SEO is everything for those people 🙂 and sure it's very important to return the correct statusCode. I'll post my solution on this thread in case it results useful
White-crowned SparrowOP
@Giant panda Please do so.
Well what I did is the following. I implemented a middleware.ts
This is my page.
This is my not-found
Well what I did is the following. I implemented a middleware.ts
import { NextResponse, NextRequest } from 'next/server';
import { getData } from './api/getData';
export async function middleware(request: NextRequest) {
const res = await getData(request.nextUrl.pathname);
if (res?.response.statusCode === 301) {
const redirectPath = new URL(res.response.responseHeaders.Location[0]);
return NextResponse.redirect(
new URL(
redirectPath.pathname + (request.nextUrl.searchParams ? `/?${request.nextUrl.searchParams}` : ''),
request.url
), 301
);
}
const headers = new Headers(request.headers);
headers.set('request-pathname', request.nextUrl.pathname);
return NextResponse.next({
request: {
headers,
},
});
}
export const config = {
matcher: '/((?!api|_next/static|_next/image|favicon.ico).*)',
};This is my page.
import type { Metadata } from 'next';
import { notFound } from 'next/navigation';
import { getData } from '../../api/getData';
import Partials from '../../components/partials/Partials';
export default async function Page() {
const data = await getData();
if (!data || data.response.statusCode === 404) notFound();
return <Partials context={data} />;
}This is my not-found
import Link from 'next/link';
import { getData } from '../../api/getData';
import Partials from '../../components/partials/Partials';
import { Typography } from '../../components/UI/Typography';
import styles from './layout.module.scss';
export default async function NotFound() {
const data = await getData();
return (
<>
<div>
<Typography as="h1" variant="2xl">
Blablabla
</Typography>
{data?.areas?.main?.map((widget) => (
<Partials key={widget.id} context={widget} />
))}
</>
);
}Answer
White-crowned SparrowOP
And this is my getData()
So I basically set a new header in the middleware, which is the original URL, so I can use it and make a call from inside the notFound page, which gives me the 404, and then consume the data inside the notFound page, which doesnt accept any props.
In the documentation it says:
'Good to know: For layouts, it's not possible to pass data between a parent layout and its children components. We recommend fetching data directly inside the layout that needs it, even if you're requesting the same data multiple times in a route. Behind the scenes, React and Next.js will cache and dedupe requests to avoid the same data being fetched more than once.'
So I guess its ok that I am calling the getData() multiple times.
import { headers } from 'next/headers';
import type { PageData } from '../types/cms';
export async function getData(middlewarePathname?: string): Promise<PageData | undefined> {
let requestPathname;
if (middlewarePathname) {
requestPathname = middlewarePathname;
} else {
const headersList = headers();
requestPathname = headersList.get('request-pathname');
}
const apiEndpoint = `${process.env.API_URL}${middlewarePathname ? middlewarePathname : requestPathname}`; const res = await fetch(apiEndpoint, { cache: 'no-store' });
if (!res.ok) {
console.log('An error occured while fetching data', { apiEndpoint, status: res.status });
return undefined;
}
const jsonResponse = await res.json();
return jsonResponse;
}So I basically set a new header in the middleware, which is the original URL, so I can use it and make a call from inside the notFound page, which gives me the 404, and then consume the data inside the notFound page, which doesnt accept any props.
In the documentation it says:
'Good to know: For layouts, it's not possible to pass data between a parent layout and its children components. We recommend fetching data directly inside the layout that needs it, even if you're requesting the same data multiple times in a route. Behind the scenes, React and Next.js will cache and dedupe requests to avoid the same data being fetched more than once.'
So I guess its ok that I am calling the getData() multiple times.
I've the same problem, I'm trying to serve a 401 for an Unauthorized page..
But i'm not really understanding your "solution" you're simply redirecting using the status code, like you're not resolving the initial problem ..
But i'm not really understanding your "solution" you're simply redirecting using the status code, like you're not resolving the initial problem ..
@Ninhache I've the same problem, I'm trying to serve a 401 for an Unauthorized page..
But i'm not really understanding your "solution" you're simply redirecting using the status code, like you're not resolving the initial problem ..
White-crowned SparrowOP
My solution handles redirects with 301, and when we have a notFound page, I serve the notFound() which delivers a 404. A 401 its impossible in my solution. And yes I am not resolving the initial problem about changing the status codes. I just found a way to get what I want. Next should provide a way to change and modify the Status Codes.
When we could use getServerSideProps we could easily do props.res.statusCode = .....
This is missing atm and I really hope they will provide a solution.
When we could use getServerSideProps we could easily do props.res.statusCode = .....
This is missing atm and I really hope they will provide a solution.
We could simply add it in /pages lmao
But that's stupid imo
White-crowned SparrowOP
U mean just to use the page directory and not the app ?
Well i think this is what I will do at the end of the story. But I really want to use the app directory and the server components concept.
@White-crowned Sparrow U mean just to use the page directory and not the app ?
And yes that what i've tought about