How to handle dynamic routes, non existing pages and no existing data from GraphQL request in Astro project

How to handle dynamic routes, non existing pages and no existing data from GraphQL request in Astro project


-2

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.

  1. Do I have to make then another GraphQL query inside [...url].astro to solve this issue?
  2. And what about the other case (existing page without content)?
  3. 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

  • Why not just look at the error returned from client.query and navigate to the 404 page?

    – Michel Floyd

    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 the client.query to [...url].astro? And how would you 'navigate' to the 404 page, what do you mean by that?

    – meez

    yesterday

1 Answer
1


0

There appears to be 2 ways of handling this:

  1. 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.
  2. 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 always undefined? 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?

    – meez

    21 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?

    – meez

    21 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 Floyd

    21 hours ago

  • Ok. And why is it better to trigger this from the GraphQL error instead of the data object?

    – meez

    19 hours ago

  • Why treat the values of data as error conditions when you have the ability to throw actual errors?

    – Michel Floyd

    17 hours ago



Leave a Reply

Your email address will not be published. Required fields are marked *