I'm submitting a ...
PostGraphQL version:
3.2.0
Minimal SQL file that can be loaded into a clean database:
CREATE TABLE users (
id integer NOT NULL,
firstname text,
lastname text,
email text,
password text,
meta jsonb,
slug text,
updated_at timestamp without time zone DEFAULT now() NOT NULL,
created_at timestamp without time zone DEFAULT now() NOT NULL,
CONSTRAINT users_email_check CHECK ((email ~* '^.+@.+..+$'::text))
);
CREATE FUNCTION signup(firstname text, lastname text, email text, password text) RETURNS users
LANGUAGE plpgsql STRICT SECURITY DEFINER
AS $$
declare
user users;
begin
insert into users (
firstname,
lastname,
email,
password
) values (
firstname,
lastname,
email,
crypt(password, gen_salt('bf'))
)
returning * into user;
return user;
end;
$$;
Graphql example :
// the following fails, but making firstname and lastname required do pass
// (so String! for $firstname and $lastname)
mutation signupFunction(
$email: String!,
$password: String!,
$firstname: String,
$lastname: String) {
signup(input: {
firstname: $firstname,
lastname: $lastname,
email: $email,
password: $password
}) {
clientMutationId
}
}
Steps to reproduce:
Trigger the signup function via graphql with variables firstname and lastname set as optional (defined with String without !)
Current behavior:
Fails with : Variable "$firstname" of type "String" used in position expecting type "String!
Expected behavior:
Successfull response (user created without firstname and lastname, as they're not required in the database)
You have defined your signup function as โstrictโ which means if any argument is null the entire function will skip the logic and just return null. We interpret that as all the arguments being required. Remove strict and it should work as you intend.
ok thx a lot got it
The line causing problem in the migration file if i'm not mistaking :
LANGUAGE plpgsql STRICT SECURITY DEFINER
I'll probably find out; if you have a moment to confirm me, can a postgres function be partially required ?
No - PostgreSQL treats a function as either all nullable or never nullable.
However, we can apply our own rules at the GraphQL layer. I've added pgStrictFunctions option you can use with PostGraphile - anything optional should have a default, e.g.
CREATE FUNCTION signup(email text, password text, firstname text = NULL, lastname text = NULL) RETURNS users
LANGUAGE plpgsql SECURITY DEFINER
AS $$
declare
user users;
begin
insert into users (
firstname,
lastname,
email,
password
) values (
firstname,
lastname,
email,
crypt(password, gen_salt('bf'))
)
returning * into user;
return user;
end;
$$;
Note optional args have to come at the end.
This isn't documented yet because I've not had time.
@benjie how can I add pgStrictFunctions ?
When using the library you can enable this by adding pgStrictFunctions: true to graphileBuildOptions; e.g.
app.use(postgraphile(process.env.DATABASE_URL, process.env.SCHEMA_NAME, {
dynamicJson: true,
graphileBuildOptions: {
pgStrictFunctions: true,
},
}));
If you use the CLI I've added a task to add support here, feel free to subscribe to it: https://github.com/graphile/postgraphile/issues/705
Most helpful comment
When using the library you can enable this by adding
pgStrictFunctions: truetographileBuildOptions; e.g.If you use the CLI I've added a task to add support here, feel free to subscribe to it: https://github.com/graphile/postgraphile/issues/705