Introducing the @model directive


#1

The recent release of resolver functions offers, a natural next step is to define types other than model types for your Graphcool service. You can follow along the proposal for advanced resolver payload types.

Preparing more powerful resolver types, we are now introducing a change to how model types are specified in types.graphql. Formerly, you could deploy model type definitions in two ways:

type User {
  id: ID! @isUnique
  name: String
}

type OtherUser implements Node {
  id: ID! @isUnique
  name: String
}

As of now, you need to use the new @model directive to specify a model type:

type User @model {
  id: ID! @isUnique
  name: String
}

type OtherUser @model {
  id: ID! @isUnique
  name: String
}

If you use implements Node or no further specification, you’ll receive an error message. You can read more about the reasoning behind this change here:


#2

I don’t completely understand the thinking here. The “implements Node” felt completely natural and standard to Graphql schema in general. Why add a directive to the most basic first class citizen a schema?

How will this work when interfaces are implemented? (I’m really looking forward to graph.cool supporting interfaces (and unions) as it solves a lot of problems.)

Like this:

type OtherUser @model implements UserInterface  {
...
}

It would feel more consistent with the following:

type OtherUser implements UserInterface, Node{
...
}

Or better still, why not rename ‘Node’ to ‘Model’ and have both directive and interface implementations possible?

In addition, it would be useful not to have to define ‘id’ or any fields defined in an interface implementation if they are required in the interface. This would save many lines for more complex schemas.

To be explicit in the examples you could include the following in every types.graphql example:

interface Model {
   id: ID! @isUnique
   createdAt: DateTime! 
   updatedAt: DateTime!
}

type User implements Model {
  firstName: String!
  lastName: String!
}

TLDR: Can we keep “implements” as an option, which will be more consistent once interfaces are added.


#3

Hey Mark, thanks a lot for chiming in!

No, like this:

type OtherUser implements UserInterface @model {
...
}

The thing is that createdAt and updatedAt are only in the schema, if explicitely stated.


That’s a great idea, could you please add that suggestion here:


We’re pretty firm with this decision, but feel free to create a feature request nonetheless: https://github.com/graphcool/graphcool

Thanks a lot for your feedback! :raised_hands:


#4

@Mark_Petty If you define fields in an interface, you have to define them on the concrete Types too. I wouldn’t want any magic going one there. However, the Node interface makes some assumptions right now, for example that the ID field has to be ID!. When the FR for allowing custom ID’s goes through, this can’t be modelled with an interface anymore.

@nilan I must say I’m not a big fan of the @model directive either, I believe this kind of information shouldn’t be in the schema, but in you project configuration (or even stage specific), and your schema should stay ‘clean’. Especially if storage capabilities (supported data sources) are extended in the future. Then, the @model directive wouldn’t be sufficient anymore, and you’ll end up with half of your storage configuration in the schema with something like @model(provider: '....', ...), which I think is not what you want.