Skip to content
This repository was archived by the owner on Oct 9, 2025. It is now read-only.

Conversation

phamhieu
Copy link
Member

@phamhieu phamhieu commented Feb 22, 2021

What kind of change does this PR introduce?

What is the current behavior?

  • When rpc method insides PostgrestQueryBuilder. User can create this chain
    let res = await postgrest.from('users').rpc({ name_param: 'supabot'})
    It's wrong.
  • no way to set options param

Screenshot 2021-02-22 at 10 14 38 AM

What is the new behavior?

  • No breaking change. postgrest.rpc usage is the same after moving it to PostgrestRpcBuilder
  • Expose rpc options param

Screenshot 2021-02-23 at 9 27 46 AM

@phamhieu
Copy link
Member Author

phamhieu commented Feb 22, 2021

  • isVoid: set 'Prefer': 'return=minimal' to request header. This will prevent json parsing error when calling void function
  • head: set method = 'HEAD'

Can we use a head request to call void function?
Postgrest stored procedure rpc doesn't support HEAD request.

I'm trying to fix this issue supabase/supabase-js#132

@kiwicopple
Copy link
Member

It looks like the function was previously working. I wonder if we added something that broke it?

add isVoid param

I'm guessing the library is returning an error because we are trying to do some sort of await res.json() on an empty result? Perhaps it's better if we we just detect if (res.json) {} else .., so that the user doesn't have to add isVoid every time?

@phamhieu
Copy link
Member Author

phamhieu commented Feb 22, 2021

It seems to be a postgrest error. For void function, postgrest doesn't return anything.

my test function

CREATE FUNCTION public.void_func() 
RETURNS void AS $$
$$ LANGUAGE SQL;

When i create a unit test. It returns properly for my PR and the current master branch.
The unit test uses postgrest/postgrest:v7.0.1

Screenshot 2021-02-22 at 4 32 54 PM

However, when I test with a code playground and a real supabase project. postgrest doesn't complete the request for a void function.
I wonder if supabase project is using a different version of postgrest compare to the unit test? @kiwicopple

Screenshot 2021-02-22 at 4 29 29 PM

Screenshot 2021-02-22 at 4 29 44 PM

@phamhieu
Copy link
Member Author

Screenshot 2021-02-22 at 5 31 35 PM

Confirm, it's postgrest error on this version postgrest/postgrest:nightly-2021-01-25-18-38-c93e8f9

@kiwicopple
Copy link
Member

Let's wait to see what @steve-chavez thinks. I believe we're using the nightly version in prod so that we can update the config without downtime

@soedirgo
Copy link
Member

I see, looks like PostgREST 7.0.1 is returning null for void-returning functions:

$ curl -s 'http://localhost:3000/rpc/void_func' -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"param":"foo"}'
null

But it returns nothing on nightly.

@steve-chavez
Copy link
Member

But it returns nothing on nightly.

Yes, this was a side-effect of fixing functions that return SETOF on: PostgREST/postgrest@0c25f12.

Didn't realize it would break JSON.parse, I'll file it as a bug.

isVoid: set 'Prefer': 'return=minimal' to request header. This will prevent json parsing error when calling void function
Postgrest stored procedure rpc doesn't support HEAD request.

Postgrest do supports HEAD on RPC, but the return=minimal seems like a good workaround for now.

@steve-chavez
Copy link
Member

Another suggestion for fixing the issue:

if (body === '') return undefined
return JSON.parse(body)

From PostgREST/postgrest#1762 (comment).

@phamhieu
Copy link
Member Author

i improve fetch response parsing method. It can handle empty result

Copy link
Member

@soedirgo soedirgo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a couple comments, otherwise lgtm 👍

src/lib/types.ts Outdated
Comment on lines 94 to 100
if (text && text !== '') {
try {
data = JSON.parse(text)
} catch (_) {
error = { message: 'Failed to parse json response' }
}
}
Copy link
Member

@soedirgo soedirgo Feb 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should just do nothing in catch? Not sure if it's a good idea to "forge" PostgREST errors. Otherwise you'll also need other fields in PostgrestError:

interface PostgrestError {
message: string
details: string
hint: string
code: string
}

Copy link
Member Author

@phamhieu phamhieu Feb 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because users always expect json response from PostgREST. So if the response.text has content and we can't parse it to json. An error message is reasonable.

Actually, the error message is for us. I don't think users can do anything with this error. It's either PostgREST bug or postgrest-js bug.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, either way the user gets an unexpected error and files a bug. I guess we can keep old behavior and add special case for text === ''? Loud and explicit error > silent error IMO.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let do less. I remove try/catch block.

src/lib/types.ts Outdated
Comment on lines 110 to 114
try {
error = JSON.parse(text)
} catch (_) {
error = { message: text }
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can revert this to the original error = await res.json().
Just want to be safe here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reverted to error = await res.json()

data = null
const isReturnMinimal = this.headers['Prefer']?.split(',').includes('return=minimal')
if (this.method !== 'HEAD' && !isReturnMinimal) {
const text = await res.text()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will res.text ever be undefined here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@kiwicopple kiwicopple left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice one, thanks @phamhieu 👍

@phamhieu phamhieu merged commit 2bbc435 into master Feb 24, 2021
@github-actions
Copy link

🎉 This PR is included in version 0.24.4 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Call rpc void function returns json parsing error

4 participants