graphql-nexus / nexus

Code-First, Type-Safe, GraphQL Schema Construction
https://nexusjs.org
MIT License
3.4k stars 274 forks source link

allow custom directives #53

Open ngmariusz opened 5 years ago

ngmariusz commented 5 years ago

if i understand correctly there is only @deprecated possible so far? it there way to add custom ones? tools out there usually depend on custom directives then i could integrate nexus into toolchain

tgriesser commented 5 years ago

We can add the ability to define a directive for runtime use, but (as far as I can tell) adding them for use annotating the SDL would be more difficult, due to lack of support in graphql-js:

Can you talk more about the type of directives you are looking to add and how they would be used?

ngmariusz commented 5 years ago

Sure,

So Basically my question was motivated with context the of trying to use Nexus in already existing Project or pipeline (which is schema first) Let’s say i have a set of custom directives syntax that i use to annotate schema and then parse with my cli tools to generate resolvers, db and so on As Nexus actually generates schema i’ll put it on the beginning of tool chain try to achieve same result as i would write by hand in my .graphql files. So finally i would just like to be able to achive in exp this

type User @entity {
  id: ID! @id
  email: String! @column @map(path: "login.email") @depreciated(reason: 'lorem')
}

with sth like

const User = objectType({
 annotate:'@entity',
 name: 'User',
 definition(t) {
   t.string('email', { annotate:'@column @map(path: "login.email")', deprecation: 'lorem', nullable: true });
   t.id('id', { annotate:'@column' })
 }
});

i understand that will be implementing workaround (until it's figured out in graphql-js) perhaps by repacing printSchema in generateSchemaFile with https://github.com/graphql/graphql-js/issues/869#issuecomment-374351118

without this feature switching to Nexus seems like I have to leave behind everything that already works

tgriesser commented 5 years ago

I think this should be possible to add, going to dig into what it'll take to do this properly and keep you posted.

jregistr commented 5 years ago

👋 Hellos! I'm also interested in this. Perhaps all we'd need for implementing this is the ability to specify directives for type and field creation? At a glance, looks like one can use apollo's graph-tools to make the schema while providing directives.

tgriesser commented 5 years ago

👋

Perhaps all we'd need for implementing this is the ability to specify directives for type and field creation? At a glance, looks like one can use apollo's graph-tools to make the schema while providing directives.

Yes - you can add these in graphql-tools, but It's not quite as simple to do programmatically because they needed to be added to the AST for the schema, which is possible but takes a bit more work.

I've started work on it in this branch, it's something I plan on getting to but it still needs quite a bit of work to get the type generation, etc working properly.

tgriesser commented 5 years ago

Actually this looks like it might also be simple to do programmatically extendSchema, will take a look into that approach.

trufa commented 5 years ago

Any news on this?

Mika83AC commented 5 years ago

I'd also urgently need custom directives in nexus for applying authorization on query and field levels without highly repetetiv code in all resolvers.

Schubidu commented 5 years ago

Any news about directives. I want to use Apollo Federation and I need to use directives on nexus.

Schubidu commented 5 years ago

Oh I just found a related issue #148

jhalborg commented 5 years ago

Also relevant for caching with Apollo Server. We are trying to map out what it would take for us to migrate from graphql-js to nexus, and this feature is a blocker as we are quite reliant on directives on our platform

jhalborg commented 4 years ago

Any movement on this @tgriesser , active or planned?

tgriesser commented 4 years ago

Any movement on this @tgriesser , active or planned?

There is movement planned, but this is blocked on longer term changes from graphql-js end. I have discussed in depth with @IvanGoncharov and I believe the current thinking is that the extensions property (added in the 14.5.0 release) on all core type objects will eventually have a way to encode metadata into both the introspection as well as the emit of the SDL.

You can read up on the related issue https://github.com/graphql/graphql-js/issues/1343, but the gist of it is that the SDL was never intended to be used as the means to construct the schema, and the @deprecated directive is only present in the SDL because it can also be represented in the introspection query:

fragment FullType on __Type {
  # ...
  fields(includeDeprecated: true) {
    name
    # ...
    isDeprecated
    deprecationReason
  }
  enumValues(includeDeprecated: true) {
    name
    # ...
    isDeprecated
    deprecationReason
  }
  # ...
}

The fact that handwritten directives exist in the AST when writing-SDL first is only a result of that fact that it is valid syntax, but it's not necessarily meant to be utilized in this way.

So I'm planning on revisiting in the future when this is supported in the way that is intended, rather than trying to hack around this limitation.

jhalborg commented 4 years ago

@tgriesser Allright, thanks, that makes sense.

So for people looking to use a code-first approach with Apollo Federation, the short answer seems to be: "You can't" - at least yet, because Lee Byron and the GraphQL team does not believe that using directives in such a manner is the "intended" way of the GraphQL IDL?

tgriesser commented 4 years ago

Yeah that's more or less it. I think I had seen mention there was or will be an approach of federating via code first, but I'm not positive.

I'd also caution against jumping right to federation just because it's the new tech out there. Facebook, Shopify, Github, Twitter all examples of companies/codebases using GraphQL which are code-first and not federated at the GraphQL layer.

If you're moving to federation because you truly have multiple independent GraphQL services you control and really want to stitch together at the GraphQL layer (say, one in Ruby, one in Scala, one in Elixir, one in JS), then yes - federation seems like a possible solution.

Instead, if you're using federation to try and compartmentalize pieces of your app, I'd advise seeing how far code-first can get you. You can still come up with a set of conventions for where to place code so different teams can work on it and expose their pieces of the graph in ways that don't step on others' toes, particularly with helpers like extendType, mutationField, and queryField.

In my view, the ideal GraphQL layer hides the implementation details of any microservices/data stores at a lower level. As soon as you federate, you will run into a host of other problems you'll need to sort out.

marcotuna commented 4 years ago

I know that my comment will add nothing but currently we are at the end of March, is there any updates? Any workaround to add custom directives to use for example apollo-server cache and rateLimit library?

BondDimy commented 4 years ago

Hello, I've also faced with this problem, is there any updates ? I think now we are looking for any solutions. Thanks

maxwellsmart84 commented 4 years ago

bumping this as I just want to add a "@deprecated" flag to some queries/mutations

Mika83AC commented 4 years ago

@maxwellsmart84 you don't need directives for that. You can just set the "decprecation" property on the field/object and it will be deprecated in schema.

yaacovCR commented 3 years ago

see https://github.com/graphql-nexus/nexus/issues/148#issuecomment-749758266

i think there are two issues, allowing uses of custom directives within the schema and allowing definition of custom directives that could be used within the schema or the query...

the former is debatable, and graphql-tools has joined graphql-compose/gatsby in saying that these "directive" uses should be alternatively read from the extensions...

but the latter seems definitely like it should be supported

maybe it is supported? i am day #1 on using nexus so forgive me if I am incorrect.

I used a workaround with graphql-js extendSchema to add the definitions via SDL, but that seems less than ideal -- in contrast, my code-first stitching example with graphql-js lets me add the built directives.

bionicles commented 3 years ago

just want to argue this feature would be powerful for authorization, which ought to happen at the GraphQL layer, since it handles the data schema.

ideas of trust and ideas of data are forcibly linked because you can't make trust decisions without data and you can't just serve data without trust in many situations (finance, healthcare etc),

so some standard way to meta-program the schema would prevent us from doing a lot of boilerplate repetition

Mark-Panda commented 3 years ago

Is there any latest news?

Mark-Panda commented 3 years ago

Is there any latest news?

nicolastoulemont commented 3 years ago

just want to argue this feature would be powerful for authorization, which ought to happen at the GraphQL layer, since it handles the data schema.

ideas of trust and ideas of data are forcibly linked because you can't make trust decisions without data and you can't just serve data without trust in many situations (finance, healthcare etc),

so some standard way to meta-program the schema would prevent us from doing a lot of boilerplate repetition

@bionicles If your are looking to abstract your authorization in an easily consumable service, I suggest that you have a look at the field authorize plugin, it may be what you are looking for.

If it is not, you can always write your own custom plugins based on your need. For authorization, I would suggest writing a plugin on the onCreateFieldResolver operation. Here are the docs it's a fairly simple task and you can always have look at the default plugins source code here for inspiration :).

Good luck

hinsxd commented 3 years ago

In our case, we'd like to use custom directive to expose more information to the frontend, so as to generate some