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

actions: Allow to reuse already existing types

Open xzilja opened this issue 5 years ago • 15 comments

Current Behaviour

We have to explicitly define action types for inputs and outputs, even if we are returning types that already exist (i.e. want to return characters type associated to already existing characters table, yet have to type it all out manually in action as a new type).

This creates few barriers, especially when we have to type out larger responses. It creates a lot of duplicate types, which get in the way when using tools like https://graphql-code-generator.com And makes it really hard to work with typescript, where it expects some values to be of enum type, but we can't re-use enums in actions (See #4513)

Right now this is a single peace of functionality in hasura (at least for our team) that requires a lot of manual work / workarounds to get them working correctly with typescript and apolo cache (apollo cache doesn't get updated correctly as actions don't return existing types we use with queries for example).

Right now editing / deleting custom types doesn't update hasura's hdb_custom_types correctly as well, making this issue of "a lot of unnecessary types" even worse (See #4967)

Doing so with approach described here https://hasura.io/docs/1.0/graphql/manual/actions/reuse-types-actions.html is viable, but perhaps a simpler method where we just define return types would be better?

Expected Behaviour

Actions should allow access to all types that already exist in our graphql schema (those generated when we create tables / enums etc...). We should be able to create actions without defining any custom types if action output uses already existing type (i.e. see characters example above). When "Derive Action" option is clicked from Graphiql, generated action should reuse types from the code we typed out in Graphiql instead of creating it's own custom types. Generated action schema should have correctly inherited __typename fields, so if it returns an existing type it will work correctly with tools like apollo cache.

I am not sure about this one, but it would add to dev experience if we could get type auto completion in actions text fields as well.

xzilja avatar Jun 06 '20 06:06 xzilja

Not sure if I should open another ticket about my problem, but as it seems to be quite similar with this one, I'll just comment here (stressing the importance of this while ticket doing so :) )

I have a (derived) action like this:

Type Mutation {
  InsertStuff (
    name: String
    type: MyTypesEnum
    colors: SelectedColors
): InsertStuffOutput
}

My issue is with the "type" and "colors" -field types.

I already have "type" defined in Hasura as an enum-table, and Hasura has auto-generated a type of it; "hasura_stuff_types_enum". I have similar auto-generated Hasura-type defined for colors, which is a list of objects; "[hasura_stuff_colors_insert_input]".

Now, when I try to use these existing, auto-generated types as my action's input types, they get not accepted as they are not defined in custom types.

It works if I re-define the same things as MyTypeEnum and SelectedColors in the Action console Types definition - but I'm having really hard time believing that this is the wanted and proper way to do this, because Hasura should already know these types. As my mutation is really much larger than this example I wrote, the action would create over 2000 lines of custom types required by this, some of which are enums already once defined in the schema.

Like mentioned above, there is a Hasura manual page about re-using existing types, but that seems to work only with output-types. My issue is with the input-types.

katya450 avatar Sep 14 '20 07:09 katya450

Up ! This becomes really problematic with typescript, not to say that defining the same enum in different places is bad design.

pacwoodson avatar Feb 13 '21 08:02 pacwoodson

In my humble opinion,

  • Cool

    Actions should allow access to all types that already exist - @IljaDaderko

    => Not forced to rely on Relationship.

  • Necessary

    Like mentioned above, there is a Hasura manual page about re-using existing types, but that seems to work only with output-types. My issue is with the input-types. - @katya450

    => Existing types as input, especially for enum in practical.

I guess the limit is introduced by technical uncertainty.

For instance, what should be done when existing types 'directly'(not depending on Relationship) used in action schema are modified or deleted? Should action be cascaded, or the change restricted?

For another example, for existing types directly used by actions, is it enough for an action handler to respond with just pk?

Current

type MyCustomType {
  fooId: String!
  # foo: Foo! # This will be dynamically created by Hasura by Relationship, if you set.
  bar: Int!
}

Expected

type MyCustomType {
  foo: Foo!
  bar: Int!
}

And action handler can return pk only, similar to the way Apollo Federation works?

{
  "foo": {
    "id": "helloworld" // This is pk.
     // foo's other fields are automatically queried by Hasura, if a client requests.
     // Action handler does not have to do that.
  },
  "bar": 123
}

There are a few things to decide first, and I feel the issue can be resolved, at least it looks far from being impossible.

jjangga0214 avatar Mar 18 '21 05:03 jjangga0214

Up ! Manually duplicating types representing the same entities is indeed error-prone and introduces unnecessary overhead. Allowing actions input types to consume enums from the schema is required to maintain a single source of truth regarding typing.

rfieve avatar Apr 30 '21 10:04 rfieve

Upvoting for this one. I'm trying to setup custom Action with Metadata Config v2.

I expect that adding new mutation should be as straightforward as this

# metadata/actions.graphql

type Mutation {
  insert_users_one_custom(object: residents_insert_input): users
}
# metadata/actions.yaml

actions:
  - name: insert_users_one_custom
    definition:
      kind: synchronous
      handler: '{{ACTION_BASE_URL}}/insert_users_one_custom' # custom route that's defined separately
      forward_client_headers: true
custom_types:
  enums: []
  input_objects: []
  objects: []
  scalars: []

Where

  • insert_users_one_custom : our custom mutation (and insert_users_one is existing one that we are trying to wrap with custom functionality)
  • residents_insert_input : existing input
  • users : existing type

But looks like it's not possible to do with current setup 😕

omieliekh avatar Jun 23 '21 12:06 omieliekh

When attempting to use an existing input object, the following error message reason is produced: "Inconsistent object: in action "myAction"; the type: "user_set_input" is not defined in custom types or it is not a scalar/enum/input_object" If this takes a while to fix, I would suggest changing the error message to include: "the type "user_set_input" must be defined in custom types and be of type scalar, enum, or input_object"

MarkNBroadhead avatar Jul 13 '21 23:07 MarkNBroadhead

I wish this could be implemented soon 😢 I'm facing an issue where I have a large table of 60+ columns, then I'm using an insert_ mutation but I need to validate some data with other services, then it becomes a mess of custom duplicated types when tried to derivate into an action.

joelbqz avatar Oct 08 '21 03:10 joelbqz

+1

bhm-wathan avatar Jan 23 '22 13:01 bhm-wathan

to keep things DRY we need this feature. Lots of duplication going on at the moment

snipebin avatar Feb 03 '22 00:02 snipebin

Hey, any forecasts on this?

NunoMartins21 avatar May 19 '22 16:05 NunoMartins21

Hey @0x777,

We do really appreciate your job 👍

Could you explain us why this in not implemented ?

AaronActu avatar May 26 '22 18:05 AaronActu

Please let me know if you have a better workaround:

Custom mutations

  • If https://github.com/hasura/graphql-engine/issues/5001 is solved
    • Then please replace current custom_* types with better solution
    • Else please vote for the issue
  • E.g. to add a custom mutation to insert one object to table item:
    • Run up_static to make sure static/schema.graphql is fresh
    • Open Add a new action page
    • Set "Action Definition" to
      type Mutation {
          custom_insert_item_one(
              object: custom_item_insert_input!
          ): custom_item
      }
      
    • Add a copy of input item_insert_input {...} found in static/schema.graphql to the "Type Configuration"
    • Rename it to custom_item_insert_input
    • Delete the unused columns and relations from {...}
    • Do the same for type item to become type custom_item
    • When you will create a custom_update_item_by_pk mutation, you will not need to declare type custom_item again

Scripts used:

  • up_static:
    for FORMAT in graphql json
    do gq $HASURA_GRAPHQL_ENDPOINT/v1/graphql \
        -H "X-Hasura-Admin-Secret: $HASURA_GRAPHQL_ADMIN_SECRET" \
        -H "X-Hasura-Role: user" \
        --introspect \
        --format $FORMAT > static/schema.$FORMAT
    done
    
  • gq - https://www.npmjs.com/package/graphqurl

denis-ryzhkov avatar Jun 03 '22 15:06 denis-ryzhkov

I'm not really a Go or Haskell programmer but maybe I can help with developing a concept. Or think along.

tombrouwer avatar Jul 13 '22 07:07 tombrouwer

Any news on this one ?

karibertils avatar Sep 11 '22 15:09 karibertils

bump

ilijaNL avatar Sep 13 '22 05:09 ilijaNL

+1

heberuriegas avatar Oct 25 '22 11:10 heberuriegas

bump

testbuddy avatar Nov 03 '22 13:11 testbuddy

bump

Omnean avatar Nov 15 '22 16:11 Omnean

+1

iangabrielsanchez avatar Nov 22 '22 06:11 iangabrielsanchez

+1

joelbqz avatar Nov 24 '22 18:11 joelbqz

Hey Folks,

Appreciate your patience, I noticed that there are 2 use cases here,

  1. Redefining an already existing type is a lot of effort
  2. I want “Hasura” to use the auto-generated types on Action definitions and keep that updated with tracked tables. Note that this means that if some customisation or permission is added to the table then the type would dynamically keep changing.

Point 2 is much harder and probably not a good architecture considering the dynamism of auto-generated types. But we are working on Point 1 - a feature that would allow the users to re-use the table shape without manually typing it - I hope this could help reducing the time spend on writing the action type definition, will this be useful for your problem?

soorajshankar avatar Nov 30 '22 10:11 soorajshankar

Hey Folks,

Update: We developed a console feature on the point 1 that I mentioned above and this feature will be available from the next release (v2.17)

Also I created a discussion https://github.com/hasura/graphql-engine/discussions/9273 describing the first iteration of the feature and possible enhancements, please take a look and let us know your thoughts.

soorajshankar avatar Dec 19 '22 07:12 soorajshankar

Thanks all for the feature request. We would like to update you that reuse enum types in Actions, is currently on the roadmap. We’ll get started in the next few months - would love to get you as a design partner when we get started, so please let us know if you are interested to collaborate.

Reusing other database types in Actions is still being considered and we cannot provide a timeline at this point. As @soorajshankar mentioned above it is more complex. Most of the comments in this issue mention the reuse of enums. We would be interested to know how many users are affected with the lack of support of other database types and what are the examples of those types/use-cases? Also what is the kind of behavior you would expect when the database types changes? Do the action types remain in sync or would they be modified manually?

rahulagarwal13 avatar Dec 20 '22 02:12 rahulagarwal13

We ran into this today, we have a pretty large number of columns in a particular table. We want to create an action to replace the standard insert, because it starts a transaction that has multiple steps (hidden from the user).

We were using events, but ran into race conditions. It would have been nice to reuse our existing insert type on this table to save a lot of headache.

Update: reuse enums i believe would fix our issue for the most part

lukepolo avatar Aug 22 '23 14:08 lukepolo

This would be a nice feature indeed

joanrodriguez avatar Nov 18 '23 18:11 joanrodriguez

Thanks everyone for your comments and patience on this issue. We have been closely listening into all the feedback and requests from the community, and have been working on a re-imagined, re-architectured Hasura, that tackles many of these from ground up. We are pleased to announce that we are launching V3-Alpha of Hasura (Data Delivery Network) on our next Community call on Nov 30. The new metadata structure in V3 is designed to be highly flexible and declarative, to support the perfect GraphQL schema you would like to achieve. In V3, we give user the controls to define the types and the mappings to objects (which includes actions), which helps solve this issue in a systemic manner. We would request to join this community call to learn more about Hasura V3. Post launch, we will update this issue with relevant details.

manasag avatar Nov 23 '23 15:11 manasag