graphql-engine icon indicating copy to clipboard operation
graphql-engine copied to clipboard

How to mark certain columns as required fields in the generated GraphQL schema

Open venelin-mihaylov opened this issue 6 years ago • 24 comments

Not nullable fields in the database are not exposed through the graphql schema as required. Is this by design? Shouldn't non nullable fields be required?

venelin-mihaylov avatar Jan 21 '19 12:01 venelin-mihaylov

The schema generation logic respects the nullability of columns in the database. Can you give us an example where this is not as expected?

0x777 avatar Jan 22 '19 06:01 0x777

I created a very simple table "test", with "id" and "test" nonNullable field, and the "test" field was not marked with "!" in "test_insert_input" . What info would you like to have to reproduce the issue?

venelin-mihaylov avatar Jan 23 '19 13:01 venelin-mihaylov

Unfortunately NOT NULL constraint does not imply that the column value needs to be provided to insert a row. A column can have a NOT NULL constraint with a DEFAULT value, or the value can be set inside a Postgres trigger. So it will be incorrect to generate a not-null type("!") for such column in the input (as the column value need not be provided at all). Postgres does not provide information on whether a column input needs to be provided for a table (it cannot).

However, NOT NULL constraint implies that the data returned will never be NULL and so we generate not-null types for non nullable columns in the object type for a table response.

0x777 avatar Jan 23 '19 13:01 0x777

I understand. Is there another way for an input field to be marked as mandatory then?

venelin-mihaylov avatar Jan 29 '19 11:01 venelin-mihaylov

Any update? I too am looking for this feature. Our frontend team often struggle with figuring out the min required fields.

ajayar avatar May 11 '19 05:05 ajayar

perhaps you can add one more checkbox next to the col definition in the console.

ajayar avatar May 11 '19 05:05 ajayar

@ajayar That seems like a reasonable solution. Adding a "REQUIRED" checkbox that's unchecked by default would preserve backward compatibility.

With a little tooltip that explains why REQUIRED and NOT NULL are not the same thing.

trekze avatar May 12 '19 10:05 trekze

That would be a nice solution indeed. I came here looking for the exact same thing.

smeevil avatar May 14 '19 11:05 smeevil

Omg, yes please add this

wu-s-john avatar Sep 18 '19 13:09 wu-s-john

Please, I use elm-graqhql, I need to be able to set fields as required.

CharlonTank avatar Oct 16 '19 11:10 CharlonTank

@0x777 / @coco98 its true that NOT NULL columns can have defaults but it would be nice for schemas to mark fields as required if they are but NOT NULL and don't have a default. Since this would be a breaking change, it seems reasonable to flag it behind an environment setting.

Another option would be to expose two different insertion mutation with different insertion types - one would have current behavior and then a strict version of each which requires all fields which are NOT NULL and don't have defaults. field by field overrides could work too, but I see this as more complicated

maxcan avatar Nov 01 '19 17:11 maxcan

@venelin-mihaylov @wu-s-john if you're using typescript, i have a workaround:

This will create versions of input types were scalar fields are required and fields that commonly have defaults are excluded. This assumes you are using graphql-code-generator with defaults.

type SubtractKeys<T, U> = {
  [K in keyof T]: T[K] extends U ? K : never;
}[keyof T];

type Subtract<T, U> = { [K in SubtractKeys<T, U>]: T[K] };

type ExcludeCommonCalcedFields<T> = Required<
  Omit<T, "deleted_at" | "id" | "updated_at" | "created_at">
>;
type MakeMaybesRequired<T> = { [k in keyof T]: Exclude<T[k], null> };

type ScalarFieldTypes = string | number | boolean | Date;
type NonScalarFieldsKeys<T, U = ScalarFieldTypes> = Subtract<T, U>;
type ExcludeNonScalars<T> = {
  [k in keyof NonScalarFieldsKeys<T>]: NonScalarFieldsKeys<T>[k];
};
export type ReqInsertArr<T, E extends string = ""> = Array<ReqInsert<T>>;
export type ReqInsert<T, E extends string = ""> = Omit<
  ExcludeNonScalars<MakeMaybesRequired<ExcludeCommonCalcedFields<T>>>,
  E
>;

maxcan avatar Nov 03 '19 00:11 maxcan

I'm using elm, I hope this gonna be a feature at some point, I might PR too

CharlonTank avatar Nov 05 '19 01:11 CharlonTank

ping..

maxcan avatar Nov 13 '19 20:11 maxcan

pleasssse <3

CharlonTank avatar Dec 05 '19 18:12 CharlonTank

Wouldn't it be possible to generate directives in the schema to define constraints of fields?

In case of input types we could have eg @required or similar to mark it as a required field.

There could also be directives for ranges, regexp validation strings, etc.

beepsoft avatar Apr 01 '20 07:04 beepsoft

This would be really useful.

My generated types are full of

foo?: Maybe<Scalars['String']>;

When in fact I know that foo will never be null.

ryanberckmans avatar Jun 17 '20 07:06 ryanberckmans

I was excited to introduce Hasura to the team until I found this limitation. This, at least to me, is a show stopper if front end developers can't easily tell which GraphQL fields are required and which are optional.

VRspace4 avatar Aug 24 '20 05:08 VRspace4

This makes our mutation code super fragile, and requires each pass to either go through manual or automated testing to ensure no compulsory field is missed

manually adding a check-box would be of huge help. We are currently wrapping all mutations with proper typed code, and have to manually maintain it as fields become non-nullable.

I think its even safe to be more aggressive and be on the safe side to mark it as compulsory if the field is non-nullable in the graphql API, and allow it to be override otherwise (there can also be a --strict-mutations flag)

ziahamza avatar Feb 26 '21 12:02 ziahamza

My current workaround is to avoid using the generated input types and just pass individual scalar fields as arguments to mutations. This at least shifts the burden onto writing the GQL queries but at least my generated typescript code (thank you graphql code generator) will enforce the correct types.

maxcan avatar Feb 26 '21 13:02 maxcan

Having a required checkbox should be a fairly simple solution. Imo it would be great to move this into the create/update permissions since this would give more flexibility. That way a create from a user role could require different fields than a admin role. Also this would embed nicely in the existing metadata for permssions.

ghry5 avatar May 04 '21 15:05 ghry5

Looking forward to this being fixed. It is quite frustrating, because it defeats the whole point of having strong typing... Mutations could easily break at runtime because you missed a null value when calling the mutation, because the column doesn't allow null values and doesn't set defaults. I wish the compiler would break and remind me to action on that potentially null variable. Instead, this breaks at runtime...

An environment variable to enable this feature for any column without a default value would be my preferred solution. Otherwise, the checkbox for mandatory input would be an easy enough setup.

carlosbaraza avatar Jan 02 '22 13:01 carlosbaraza

@0x777 Can we please have an update on the prioarity / roadmap status for this feature? I can't stress how important this is for having a functional, self-explaining and fully-typed GraphQL endpoint.

perhaps you can add one more checkbox next to the col definition in the console.

I mean, an additional checkbox would be certainly enough to do this and probably not that complicated to implement...

maaft avatar May 25 '22 10:05 maaft

@0x777 Hello?

maaft avatar Jul 28 '22 13:07 maaft

+1 This would be a game changer

vxm5091 avatar Jan 16 '23 08:01 vxm5091

I came here looking for the exact same thing, any update?

Estifanos-Neway avatar Feb 16 '23 06:02 Estifanos-Neway

Bumping request for status on this flaw. If a field is:

  1. Non-nullable at the database level
  2. Does not have a default value at the database level
  3. Does not have a Column Preset at the Hasura level

then I believe we can know for sure that this field is required on the insert input type.

Short the ability to detect this state without additional configuration, a "require this field to be explicitly set" checkbox in Column Insert Permissions would help a ton.

roryacuity avatar Aug 09 '23 00:08 roryacuity

@roryacuity

Fields could also be set by e.g. insert triggers.

The "require" option on permission is imho the only way for now. Should also be straight forward to be implemented.

maaft avatar Aug 09 '23 07:08 maaft

@maaft yes, that's correct, thank you. Explicit configuration is a more realistic option than trying to account for every possible way the column could be set on an insert mutation.

roryacuity avatar Aug 09 '23 13:08 roryacuity

Agree about explicit configuration. Should be a metadata option.

maxcan avatar Aug 09 '23 20:08 maxcan