solid-js

Canonical way to handle exceptions in async functions in solid-js?


I'm very new to solid and frontend development hence my question. I have a class that talks to server API. It uses cookie to authenticate so eventually cookie may expire and an endpoint returns http 401 error.

export class UserActions {

  private handleError(response: Response): void {
    if (response.status === 401) {
      useNavigate()(`/login?redirect=${encodeURIComponent(location.pathname)}`)
      // throw new ServiceError(ErrorType.Authentication, 'Please login again');
    }
  }

  login(email: string, password: string): Promise<User | null> {

    return fetch('http://localhost:8080/api/login', {
      method: 'POST',
      credentials: 'include',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        email: email,
        password: password,
      }),
    })
        .then(response => {
          this.handleError(response);
          return response.ok ? response.json() : null;
        })
  }
}

and here is example how it's used

export default function UserProfile() {
  const context = useContext(SessionContext);

  const [read, write] = createSignal<string>("Initial value")

  const clickHandler = async () => {
    let user = await api.currentUser()
    write(user.email)
  };

  return (
      <AuthenticatedRoute>
        <div>Hello, {context?.user?.firstName} {context?.user?.lastName}</div><br/>
        <button onClick={clickHandler}>Refresh</button><br/>
        <div>Value: {read()}</div>
      </AuthenticatedRoute>
  );
}

How can I centralize handing of such error so that any page that gets the exception would redirect user to login page ? I tried using but it doesn't catch exception thrown in onClick handler because, I assume, it's not thrown in rendering stage.

I tried calling navigate() in UserActions but it does nothing.

What is the proper way to achieve such redirect ? Thank you.


Solution

  • Apparently I have to wrap async calls into createResource to make its exceptions to be catchable in ErrorBoundary.fallback.

    That was my page become something like this

    export default function UserProfile() {
      const context = useContext(SessionContext);
    
      const [data, { mutate, refetch }] = createResource(() => api.currentUser())
    
      return (
          <AuthenticatedRoute>
            <div>Hello, {context?.user?.firstName} {context?.user?.lastName}</div><br/>
            <button onClick={refetch}>Refresh</button><br/>
            <Suspense>
              <div>Value: {data()?.email}</div>
            </Suspense>
          </AuthenticatedRoute>
      );
    }