supabase-js: Major DX change: response and error handling

Decision

We’ve decided to make a major change to support a better developer experience for working with supabase-js. Instead of throwing an error, we will return the error object as part of the response.

Example

Given a successful query, e.g. const response = await supabase.from('products').select('*'), response will be:

{
  "error": null,
  "data": [...],
  "status": 200,
  "statusCode": 200,
  "statusText": "",
  "body": [...] // for backwards compatibility: `body === data`
}

Given a bad query, e.g. const response = await supabase.from('productx').select('*'), response will be:

{
  "error": {
    "code": 404,
    "message": "relation \"public.productx\" does not exist",
    "details": null,
    "hint": null
  },
  "data": null,
  "status": 404,
  "statusCode": 404,
  "statusText": "",
  "body": null // for backwards compatibility: `body === data`
}

Future DX

This will enable the following experience:

const { error, data: products } = await supabase.from('products').select('*')
if (error) {
  alert(error.message)
  return // abort
}
console.log(`Found ${products.length} products.`)

Additional context

Inspiration has been taken from https://github.com/vercel/swr#quick-start:

import useSWR from 'swr'

function Profile() {
  const { data, error } = useSWR('/api/user', fetcher)

  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>
  return <div>hello {data.name}!</div>
}

as well as Stripe.js : https://stripe.com/docs/js/payment_methods/create_payment_method image

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 20
  • Comments: 15 (8 by maintainers)

Commits related to this issue

Most upvoted comments

Throwing errors by default, or have that as an option on createClient, would be a great improvement for us too. We use a lot of rxjs with supabase and regular error throwing would make the whole process more logical. Now we have to remember to write throwOnError after every query, because otherwise the error will go silent

Can we set this as a default behaviour globally via a parameter or smth? This is super unusual behaviour, as SDKs ussually throw errors, otherwise we have to add lots of additional checks around that which doesn’t make sense.

This is not specific to .rpc(). You can use .throwOnError() on .select(), .insert(), etc. and it will throw errors instead of returning it in the response object. See the example I linked above.

Does this error handling include programmer errors?

I don’t think this should be expected, just catch and rethrow unexpected errors. As you say, handling every possible error would be unwieldy. We should just shape expected errors.

so there’s no need to use the data field in place of body.

This one is just a preference. I guess we should decide now what is the more appropriate name for the key. IMO body seems like a throwback to when we used ajax used to request HTML snippets that would be injected into HTML.

Currently the error handling looks more like this

if (!ok) { // status code is not 2XX
  return // abort
}

I’d far prefer this one to look like the suggested change (if (error)). The term ok is unexpected, and error is very clear