Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Schema directives support #77

Open
19majkel94 opened this issue May 12, 2018 · 23 comments

Comments

@19majkel94
Copy link
Owner

commented May 12, 2018

Currently blocked by graphql/graphql-js#1343


Ability to define any arbitrary graphql directive to be passed to the compiled schema:

@ObjectType({ directives: ['@cacheControl(maxAge: 240)'] })
class SampleObject {
  // ...
}

Which should be equivalent to:

type SampleObject @cacheControl(maxAge: 240) {
  # ...
}

It might be also implemented as a separate decorator that would make possible to create custom decorators like @CacheControl({ maxAge: 240 }):

@Directive('@cacheControl(maxAge: 240)')
@ObjectType()
class SampleObject {
  // ...
}

@19majkel94 19majkel94 added this to the Future release milestone May 12, 2018

@19majkel94 19majkel94 added this to Backlog in Board via automation May 12, 2018

@jascodes

This comment has been minimized.

Copy link

commented Jun 29, 2018

@19majkel94 Why this is blocked? at face seems less complicated.

@19majkel94

This comment has been minimized.

Copy link
Owner Author

commented Jun 29, 2018

Go to the link in first post and read the discussion 😉
If you can implement this - feel free to make a PR 😃

@ntziolis

This comment has been minimized.

Copy link

commented Dec 23, 2018

This sadly prevents anybody from being able to use type-graphql that is using graphcool/prisma as a backend. We would love to use it but sadly without being able to generate the schema necessary by the downstream tooling its a non starter :(

@19majkel94

This comment has been minimized.

Copy link
Owner Author

commented Dec 23, 2018

@ntziolis
AFAIK, Prisma is the glue between your GraphQL server and your database.
You define your model using SDL and you receive a generated client that acts as an ORM in your server app.

So there should be no problem to use Prisma along with your GraphQL API build with TypeGraphQL. Of course, the tighter integration (defining prisma model and your API GraphQL Object Type in one class with decorators) would help in reducing boilerplate, but I think it's not a deal breaker 😉

@19majkel94

This comment has been minimized.

Copy link
Owner Author

commented Dec 23, 2018

And to report an update about the status of the issue - now I think I understand where is the problem with directives in graphql-js. They are purely the SDL thing, so tools written in different languages can parse the schema definition and apply certain behaviors in runtime.

So as with graphql-js we define a runtime JS object, other tools (like Prisma or Apollo Engine) don't have an access to the directives. That's why we have to wait for a new GraphQL specification that will expose the directives info via an introspection query. For now the only workaround is to generate typeDefs and resolversMap instead of executable GraphQLSchema and paste the "directives" from metadata storage into proper lines in SDL string 😕

@ntziolis

This comment was marked as off-topic.

Copy link

commented Dec 23, 2018

@19majkel94 I understand the first instinct, but there are various reasons why we feel when solving this issue a lot of other goodness would come from it:

  • prisma has a VERY poor data model migration story, in particular:
    • no versioning of schema during dev time
    • deployment of the same schema causes deployment errors in many cases breaking CI pipelines
    • no support for up/down migrations
  • using partial or changed types in public schema only possible via copy&paste
    • using the same types in your public schema minus a few fields requires copy&pasting the type (and related types) and manually removing the fields in question
    • causes errors when our devs update prisma data model but forget todo the same on the public side (lets be honest this happens a lot)

In order to clean this up and follow DRY here is how we wanted to use type-graphql

  • type-graphql becomes our way of defining both public & prisma schema (including generating the actual SDL files)
  • at the same time be able to generate type safe resolvers for the public schema
  • and use the additional features to standardize on DI etc most of which is handled manually / project by project today with different libs

I understand this might have been the initial intention of type-graphql but I can tell you after the 10th+ graphql project: The need for a framework that is the beginning and end where types originate is VERY high especially when using a graphql datasource underneath (we have tried various beyond prisma).

@Hossein-s

This comment has been minimized.

Copy link

commented May 22, 2019

Hi @19majkel94

I was trying to undestand the problem for long hours 😄 As far as I found apollo graphql-tools is doing simple job for schema directives. It just finds fields with directives and overrides their resolvers with enhanced version that applies that specific directive.

So as TypeGraphQL stores metadata for first part, the second part can be done the same way.

I don't know what you want to provide for prisma. The datamodel of the prisma is not a graphql thing. it's a customized version so I think it has nothing to do with TypeGraphQL that cares about server - client relation.

@19majkel94

This comment has been minimized.

Copy link
Owner Author

commented May 22, 2019

@Hossein-s So show me a proof of concept how to apply directive to a field using graphql-js, not GraphQL SDL syntax.

@Hossein-s

This comment has been minimized.

Copy link

commented May 22, 2019

@19majkel94
Great. I will work on it.

@zhenwenc

This comment has been minimized.

Copy link

commented May 22, 2019

@Hossein-s I also took quite a long time to find a possible solution for programatically declare directives for a node, but no luck so far. So I am also keen to see your finding.

If I understand correctly, your statement here is not quite right:

As far as I found apollo graphql-tools is doing simple job for schema directives. It just finds fields with directives and overrides their resolvers with enhanced version that applies that specific directive.

A directive is not a function, it is simply a piece of information that can be attached to a node (field, type, etc), which only contains name and optional args, and the directive itself has no logic at all, that said there is no way (and doesn't make sense) to "apply the directive".

In the case of apollo, you also need to implement SchemaDirectiveVisitor for specific directives.

@Hossein-s

This comment has been minimized.

Copy link

commented May 23, 2019

@zhenwenc
When you have SDL it's just piece of information. But when you want an executable schema, then executor applies the logic implemented for that piece of information to the resolver. As you can see in the SchemaDirectiveVisitor samples, every custom directive (and built in directives like deprecated directive) have an implementation, then you decorate fields and objects to call that implementation. (But I couldn't find cacheControl source to find how it works (even couldn't set it up to work with apollo 🚶 )).

Do you know any case that astNode definitions needed by server? I'm new on this topic.

@Hossein-s

This comment has been minimized.

Copy link

commented May 23, 2019

After investigating more, I found implementation of schema directives in apollo and graphql-yoga very similar to TypeGraphQL middlewares that are already available (But you can pass arguments to them).

@19majkel94 I don't know where schema directives sit in TypeGraphQL. 😞

@zhenwenc

This comment has been minimized.

Copy link

commented May 24, 2019

@Hossein-s

When you have SDL it's just piece of information.

The problem (or difficulty) here is not about executing the directive, since apollo already provided a way to handle it (via SchemaDirectiveVisitor), but how to add the directive into the GraphQLSchema without using DSL.

If I understand it correctly, the reason why TypeGraphQL can use Middleware to implement cache control is because you can easily manipulate the cache control store since apollo injected it into the resolve info, which doesn't actually needs to involve directive at all.

@Hossein-s

This comment has been minimized.

Copy link

commented May 24, 2019

@19majkel94 @zhenwenc
I've created a PoC to show what I'm talking about. you can find it here.

It does something like SchemaDirectiveVisitor.visitSchemaDirectives described here.

@Hossein-s

This comment has been minimized.

Copy link

commented May 24, 2019

If I understand it correctly, the reason why TypeGraphQL can use Middleware to implement cache control is because you can easily manipulate the cache control store since apollo injected it into the resolve info, which doesn't actually needs to involve directive at all.

@zhenwenc
Thanks! Now I undestand where the astNode is used 😄.

So I think it's possible to patch the resulting schema and add the astNode if there is need 🤔 I will work on it...

@Hossein-s

This comment has been minimized.

Copy link

commented May 24, 2019

I have updated PoC repository so that it adds astNode to GraphQLField. you can see it here.

So apollo cache control can read directives in this function. But other directives work without astNode.

It's very minimal just to show the posibility of feature.

@19majkel94

This comment has been minimized.

Copy link
Owner Author

commented Jun 1, 2019

@Hossein-s
Can you check in your PoC if you add directive to astNodes, will it show up in printSchema?

@Hossein-s

This comment has been minimized.

Copy link

commented Jun 2, 2019

@19majkel94
Unfortunately no. printSchema is not considering directives at all :-/
graphql/graphql-js#869

@19majkel94

This comment has been minimized.

Copy link
Owner Author

commented Jun 2, 2019

@Hossein-s
Yeah but we can use the custom one that prints astNodes 😉
graphql/graphql-js#869 (comment)

@Hossein-s

This comment has been minimized.

Copy link

commented Jun 2, 2019

@19majkel94
Yes, always there's a solution😃
I tested that snippet but it didn't work (because of lacking astNodes for Query and other types). So modified the original printSchema to print them. Hossein-s/type-graphql-schema-directives@fb236be

@ngmariusz

This comment has been minimized.

Copy link

commented Jun 21, 2019

Hey @Hossein-s @19majkel94 ,
What's the currnet status of this?
I was investigating this some time ago for prisma/nexus#53 (comment)
I have some time now and would like to help you solve and test this.

@jjwtay

This comment has been minimized.

Copy link

commented Jun 22, 2019

Yes please I would love to add field meta data from directives as well for use in the UI. My intent was to convert the schema in full server side and hang somewhere so the client can pull in all the meta data for UI auto generation.

@EdouardBougon

This comment has been minimized.

Copy link

commented Jul 26, 2019

Hey @Hossein-s, is your solution working ?
I'm really interested to add directive to field

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
8 participants
You can’t perform that action at this time.