supabase/functions-js

shouldThrowOnError does not apply to functions.invoke()

vejja opened this issue · 3 comments

vejja commented

Bug report

Describe the bug

When shouldThrowOnError is set on supabaseClient, errors raised from functions.invoke() do not throw.

Additional context

@supabase/functions uses the standard fetch API, which does not throw on HTTP status codes other than 2xx; in addition the wrapper does not return the HTTP status code in the response object which is always in the form { data, error }.

For instance, if the Edge Function was written to reject some unauthorized request by returning a 403 Forbidden response, it is impossible to catch this condition.
In other words, supabaseClient always returns { data, error: null }, even when the HTTP status code indicates an error (unless of course if fetch itself threw in the first place).

This forces the user to provide an additional 'httpError' key in the 'data' object, which feels convoluted and obliges to check errors at two different levels (in error and in data.httpError).

Proposed improvement

Modify the code of @supabase/functions:
1- Detect http status codes other than 2xx, and populate the error property in that case together with the status code, instead of populating the data property
2- Add an option to the invoke() function parameters to pass a shouldThrowOnError boolean flag. If set, throw rather than returning the { data, error } object

I can submit a PR if the above makes sense.

This really surprised me as it seems I have to manually watch for the error argument in the function response and then throw the error if I want it to act like a traditional fetch api. I would love to have this incorporated and would be down to try and make a PR as well

FYI - In the meantime I've made my own function for invoking supabase functions so that this behaves as expected:

export const callSupabaseFunction = async (
  functionName: string,
  params: any
) => {
  const { data, error } = await supabase.functions.invoke(functionName, {
    body: JSON.stringify({
      params,
    }),
  });

  if (error) {
    throw new Error(error.message);
  }

  return data;
};
export const cancelReservation = (reservation_id: string) =>
  callSupabaseFunction("cancel-reservation", {
    reservation_id,
  });

I believe this behavior should be built in as well. Having to inspect the response every single time introduces many areas for errors.