Search code examples
typescriptauthorizationsveltesveltekittrpc.io

How to redirect on tRPC error in SvelteKit?


I am using tRPC with SvelteKit for the first time, and I am stuck trying to validate the user's authentication.

I have the following in hooks.server.ts:

import { createContext } from '$lib/trpc/context';
import { router } from '$lib/trpc/router';
import type { Handle, HandleServerError } from '@sveltejs/kit';
import { redirect } from '@sveltejs/kit';
import { createTRPCHandle } from 'trpc-sveltekit';

import { getHTTPStatusCodeFromError } from '@trpc/server/http';

const trpcHandleError = ({ type, path, error }) => {
    console.error(`Encountered error while trying to process ${type} @ ${path}:`, error);
    const httpStatus = getHTTPStatusCodeFromError(error);

    if (httpStatus === 401) {
        // How do I redirect here??
    } else if (httpStatus == 403) {
        // Throw a 404
    }
}

export const handle: Handle = createTRPCHandle({ router, createContext, onError: trpcHandleError });

export const handleError: HandleServerError = ({ error, event }) => {
    // ...or here?
}

My question is: How do I redirect the user within the trpcHandleError to /login if the error.code is UNAUTHORIZED?

I've tried simply throw redirect(307, '/login'); but it was just ignored.


Solution

  • onError is a hook that gets notified when error occurs, but gives you no control over the response result.

    Instead, you can provide a responseMeta function param to createTRPCHandle({ responseMeta }). This function is supposed to return a meta object that has { status, headers } keys, which affects the final response (source code).

    It has following function signature:

    const { status, headers } = responseMeta({
      ctx,
      paths,
      type,
      data: Array<{ error: ... } | { result: { data: ... } }>,
    });
    

    You can read the params.data array, and filter out items that have error key to handle them. To achieve the same effect of redirect(307, '/login'), you need to return a meta object of shape:

    { status: 307, headers: { Location: "/login" } }