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
MichalLytek opened this issue May 12, 2018 · 32 comments
Open

Schema directives support #77

MichalLytek opened this issue May 12, 2018 · 32 comments
Labels
Blocked 🚫 Resolving this issue is blocked by other issue or 3rd party stuffs Discussion 💬 Brainstorm about the idea Enhancement 🆕 New feature or request
Milestone

Comments

@MichalLytek
Copy link
Owner

MichalLytek commented May 12, 2018

Partially solved by #369

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 {
  // ...
}
@MichalLytek MichalLytek added the Enhancement 🆕 New feature or request label May 12, 2018
@MichalLytek MichalLytek added this to the Future release milestone May 12, 2018
@MichalLytek MichalLytek added the Blocked 🚫 Resolving this issue is blocked by other issue or 3rd party stuffs label May 23, 2018
@JasCodes
Copy link

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

@MichalLytek
Copy link
Owner Author

MichalLytek 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
Copy link

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 :(

@MichalLytek
Copy link
Owner Author

@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 😉

@MichalLytek
Copy link
Owner Author

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 has been minimized.

@Hossein-s
Copy link

Hossein-s 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.

@MichalLytek
Copy link
Owner Author

@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
Copy link

@19majkel94
Great. I will work on it.

@zhenwenc
Copy link

zhenwenc 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
Copy link

@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
Copy link

Hossein-s 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
Copy link

@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
Copy link

@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
Copy link

Hossein-s 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
Copy link

Hossein-s 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.

@MichalLytek
Copy link
Owner Author

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

@Hossein-s
Copy link

Hossein-s commented Jun 2, 2019

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

@MichalLytek
Copy link
Owner Author

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

@Hossein-s
Copy link

@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
Copy link

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

@jjwtay
Copy link

jjwtay 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
Copy link

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

@snys98
Copy link

snys98 commented Oct 12, 2019

@Hossein-s Thanks for your idea, and I finally finished my workaroud repo.

@MichalLytek This is an in-doing, buggy work for schema directive. I'm wondering if this is the right approach?

@MichalLytek
Copy link
Owner Author

@snys98
We already have a working implementation of directives support in a pending PR:
#369

@MichalLytek
Copy link
Owner Author

This issue is partially solved by #369 but it doesn't support all the directives locations like scalars or arguments. So I will leave this issue open to track the work needs to be done in the future.

@MichalLytek MichalLytek added the Discussion 💬 Brainstorm about the idea label Nov 2, 2019
@glentakahashi
Copy link

Are there plans to support Directives on Subscriptions?

@MichalLytek
Copy link
Owner Author

@glentakahashi

This issue is partially solved by #369 but it doesn't support all the directives locations

Feel free to open a PR with added support for subscriptions.

@MichalLytek
Copy link
Owner Author

Because of #546 and other issues, I've decided to rollback the support for JS-like syntax - now only the SDL string way is supported. Sorry for that, better now than after stable release 😝

@glentakahashi
I've added a test case and subscriptions should also be supported from the beginning 😉

@glentakahashi
Copy link

@MichalLytek thanks for the update! And to clarify, do you mean that directives on subscriptions should now work with the SDL method? Or that they will work in a future method.

@MichalLytek
Copy link
Owner Author

@glentakahashi I've only added a test case that is passing:
c602506

So it was working in November - if it still doesn't work for you (with the SDL approach), please open an issue with and provide a repository with minimal reproducible code example.

@glentakahashi
Copy link

Aha! Sorry my confusion was actually in how to implement the SchemaVisitor for the directive. For all other types (query, field, mutation) you override the field.resolve method, but for specifically subscriptions you must override the field.subscribe method instead.

So yes it has worked the whole time, I just didn't understand what I was doing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Blocked 🚫 Resolving this issue is blocked by other issue or 3rd party stuffs Discussion 💬 Brainstorm about the idea Enhancement 🆕 New feature or request
Projects
None yet
Development

No branches or pull requests

10 participants