Expose Koa's context in the beforeSSR method

Feature Card

Description

It looks like sometimes we are going to need to modify the response object once we are in the beforeSSR method. For example, in the case of 404 pages, we need to change the status code to 404 (or any other server error code) once we know that the page doesn’t exist, but we don’t know that until we are in the beforeSSR method.

User Stories

As a Frontity developer
I want to change the response object within my beforeSSR/afterSSR methods
so that I can control the response taking into account what happens in the React render

Examples

This is a possible beforeSSR method of tiny-router that is able to change the status to 404 if the current link doesn’t exist:

export const beforeSSR: TinyRouter["actions"]["router"]["beforeSSR"] = async ({
  state,
  actions
}) => ({ ctx }) => {
  if (state.router.autoFetch) {
    if (actions.source && actions.source.fetch) {
      await actions.source.fetch(state.router.link);
      const data = state.source.get(state.router.link);
      if (data.isError)
         ctx.status = data.errorStatus;
    } else
      console.warn(
        "You are trying to use autoFetch but no source package is installed."
      );
  }
};

Possible solution

The server is going to be based on the Koa’s ctx object, so I would expose that instead of just the response. It is also much nice to work with than a typical response object.

  1. I’m not sure if the best solution is to pass ctx to any server action, to beforeSSR and init or only to beforeSSR.
  2. I’m not sure if we should add ctx as part of the “store” (first function) or as a new argument (second function):
// As part of the "store"
beforeSSR: ({ state, actions, ctx }) => ...
// with Typescript being something like this:
beforeSSR?: ServerAction<TinyRouter>;
beforeSSR?: BeforeSSRAction<TinyRouter>;

// As a new argument
beforeSSR: ({ state, actions }) => ({ ctx }) =>
// with Typescript being something like this:
beforeSSR?: Action<TinyRouter, ServerContext>;

I think both will be backwards compatible with beforeSSR: ({ state, actions }) => ... but we need to be sure. Apart from that, we need to see which one is simpler with TypeScript.

Let’s do it only in beforeSSR and within the second argument, like this:

beforeSSR: ({ state, actions }) => ({ ctx }) =>

That way it should be trivial to implement.

This has been implemented according to: https://github.com/frontity/frontity/pull/309

We have added a ctx parameter to beforeSSR and return correct HTTP status code in frontity for corresponding errors from a server.

Now we can optionally use the curried version of beforeSSR which is called with an object that contains the Koa Context in the ctx parameter. You can use this ctx to modify things like status codes, headers and so on.

// The optional "curried" version of beforeSSR using the ctx
{
  beforeSSR: ({ state, libraries }) => async ({ ctx }) => {
    // ctx is koa context: https://koajs.com/#context
    console.log('SSR all day long', ctx.status);
  }
}

Docs: https://docs.frontity.org/learning-frontity/actions#actions-triggered-by-frontity)

1 Like