How do I solve the following issue in my Astro project:
I can request the page content data
for various pages from my GraphQL endpoint. I am using Apollo Client for this.
Using the following query as an example:
query Page($target: String!) {
page(target: $target) {
id
type
content {
...on PageOne {
id
title
field
}
...on PageTwo {
id
title
anotherField
}
...on PageThree {
id
title
description
}
}
}
}
In Astro I created dynamic routes:
// pages/[...url].astro
---
import { Page } from '../components/page';
const url = `/${Astro.params.url}`;
---
<Page url={url} />
Note: I like to have a separate Astro component for the logic and mapping:
// Page.astro
---
const { url } = Astro.props;
const { data, loading } = await client.query({
query: GET_PAGE,
variables: {
target: url,
},
errorPolicy: 'all',
});
const Map = {
"PageOne": PageOneComponent,
"PageTwo": PageTwoComponent,
};
const Component = Map[data.page?.type]
---
<Component content={content} />
This all works fine. When hitting a certain target
url (existing in the backend) I can request the data
and pass it via a prop to the individual corresponding Astro components (PageOneComponent, PageTwoComponent etc).
The problem starts when trying a non existing page. Or trying a page with a page type which exist in the backend but I am not querying the content yet, since I am gradually building and adding the pages.
On a non existing page data.page?.type
is undefined
. How do I handle this in a clean way?
I can do something like this in [...url].astro
:
if (data.page?.type in Map === false) {
return new Response(null, {
status: 404,
statusText: 'Not found',
});
}
Unfortunately I cannot do above inside Page.astro
then I get the following error:
ResponseSentError: The response has already been sent to the browser
and cannot be altered.
- Do I have to make then another GraphQL query inside
[...url].astro
to solve this issue? - And what about the other case (existing page without content)?
- Just a non existing page which should return a 404 page.
I can simply move everything to [...url].astro
but then that file becomes very crowded. I like to extract things to its own components and folders.
2
1 Answer
There appears to be 2 ways of handling this:
- redirect the user to your 404 page with
Astro.redirect('/404')
or similar. On the plus side the user gets whatever look and functionality you have built in your 404 page. On the downside the URL will switch so they won’t see what URL is 404. - Render a not found component.
In either case it is better to trigger this from the GraphQL error
state rather than looking inside the data
object.
7
-
The strange thing is. The
error
state is alwaysundefined
? Perhaps this is due to the use of Apollo Client inside Astro? Apollo Client is more for React usage. Do I maybe have to switch to TanStack Query?– meez21 hours ago
-
Regarding 1). When I use
if (!(data.page?.type in Map)) { return new Response(null, { status: 404, statusText: 'Not found', }); }
it will show the custom Astro 404 page and you will still see the URL! This works fine. Why should you useAstro.redirect('/404')
instead?– meez21 hours ago
-
1. It sounds like your server is not returning an error when it should – you're probably just returning
undefined
for your unimplemented routes. 2. You said that if you returned a new response you would get an error.– Michel Floyd21 hours ago
-
Ok. And why is it better to trigger this from the GraphQL
error
instead of thedata
object?– meez19 hours ago
-
Why treat the values of data as error conditions when you have the ability to throw actual errors?
– Michel Floyd17 hours ago
Why not just look at the
error
returned fromclient.query
and navigate to the 404 page?yesterday
@MichelFloyd I can't do that inside
Page.astro
. When I try e.g.if (error) { return new Response(null, { status: 404, statusText: 'Not found', }); }
, then I get an Astro error about the<Component />
:Unable to render Component because it is undefined! Did you forget to import the component or is it possible there is a typo?
? So I guess I can't avoid it to move theclient.query
to[...url].astro
? And how would you 'navigate' to the 404 page, what do you mean by that?yesterday