Prisma1: Expose user-defined directives in API schema

Created on 9 Nov 2017  路  21Comments  路  Source: prisma/prisma1

Graphcool currently supports a limited number of system directives which are used in the data model to construct the API. These system directives are not exposed through the GraphQL API. (Other directives are currently not accepted and will result in a deploy error.)

However, there are many other use cases (like in this forum post) for directives where you'd want to expose them directly in the GraphQL API.

kinfeature areapi aredatamodel rf0-needs-spec

Most helpful comment

I am extensively using custom directives and to be honest I've gotten into a pickle a few times maintaining the schema at database and then replicating again at app level to add in descriptions and directives.

This feature would save so much pain!

Please pass though descriptions to the type and input also.

All 21 comments

Generic feature request for https://github.com/graphcool/framework/issues/1032 too.

I'd like to add my +1 for this feature request.

With 1.0 coming up to release it puts a lot more power in the hands of the developer - I see this as a critical feature for its release. These directives will help to facilitate configuration of business logic - permissions, conditionals, caching, metadata etc.

The ideal situation would be: on gc deploy pass custom directives (and string/block descriptions) out to the generated src\generated\database.graphql schema - that way it can be used by graphql prepare and the graphql-yoga implementation - which already supports directives and block descriptions.

Any directives or descriptions should also pass to Input Definitions also.

"""
# Description of Post type
"""
type Post @custom(arg: "value"){
  id: ID! @unique
  title: String! @custom(arg: "value")
  "Text field desc"
  text: String!
  author: User! 
}

gc deploy generated output:

"""
# Description of Post type
"""
type Post implements Node @custom(arg: "value") {
  id: ID! @unique
  title: String! @custom(arg: "value")
  "Text field desc"
  text: String!
  author(where: UserWhereInput): User!
}

"""
# Description of Post type
"""
input PostCreateInput @custom(arg: "value") {
  title: String! @custom(arg: "value")
  "Text field desc"
  text: String!
  author: UserCreateOneWithoutPostsInput
}

"""
# Description of Post type
"""
input PostUpdateInput @custom(arg: "value") {
  title: String @custom(arg: "value")
  "Text field desc"
  text: String
  author: UserUpdateOneWithoutPostsInput
}

@schickling Is there a possibility this could be added to the 1.0 feature list?

Especially because it already preserves custom directives on fields, this is now in an inconsistent state that should be addressed. It's also blocking for quite a number of use cases.

I also posted here: https://github.com/graphcool/prisma/issues/1032

This may be the wrong place, but has this been addressed? I could really use custom directives defined in my datamodel.graphl, but Prisma removes them when generating prisma.graphl. I would like to define custom directives and be able to provide their implementation, and I am also running into the limitations of mergeSchemas

Posted a similar but different message in #1032.

You should be able to define directives in your application schema, and also define their logic there.

Feel free to revisit this discussion in a new issue if you feel that this approach could be extended 馃檪

@marktani I feel this issue should be re-opened to find a good way to address this

I am extensively using custom directives and to be honest I've gotten into a pickle a few times maintaining the schema at database and then replicating again at app level to add in descriptions and directives.

This feature would save so much pain!

Please pass though descriptions to the type and input also.

@develomark Exactly, just a 1-on-1 passthrough of any directives anywhere in the schema.

If anyone is interested, I've got a workaround for this. I just go through the datamodel.graphl schema, grab all of the directive information and attach it back to the generated/prisma.graphql schema. After that you can do what you want with it (write it to file, use makeExecutableSchema, etc):

const originalSchemaAST = parse(readFileSync('./datamodel.graphql').toString());
const originalDirectiveDefinitions = originalSchemaAST.definitions.filter((originalSchemaDefinition) => {
    return originalSchemaDefinition.kind === 'DirectiveDefinition';
});
const generatedSchemaAST = parse(readFileSync('./generated/prisma.graphql').toString());
const generatedSchemaASTWithDirectives = {
    ...generatedSchemaAST,
    definitions: [...originalDirectiveDefinitions, ...generatedSchemaAST.definitions.map((generatedSchemaDefinition) => {
        const matchingSchemaDefinition: ObjectTypeDefinitionNode = <ObjectTypeDefinitionNode> originalSchemaAST.definitions.find((originalSchemaDefinition) => {
            return (
                originalSchemaDefinition.kind === 'ObjectTypeDefinition' &&
                generatedSchemaDefinition.kind === 'ObjectTypeDefinition' &&
                originalSchemaDefinition.name.kind === 'Name' &&
                generatedSchemaDefinition.name.kind === 'Name' &&
                originalSchemaDefinition.name.value === generatedSchemaDefinition.name.value
            );
        });

        return matchingSchemaDefinition || generatedSchemaDefinition;
    })]
};

I think I've found an even better work around in this project: https://github.com/okgrow/merge-graphql-schemas

If you use their mergeTypes function, you should be able to merge your datamodel.graphl with your prisma.graphl. It will produce a schema string with all of your types merged, including any custom directives. For example:

```javascript
const ultimateSchemaString = mergeTypes([
readFileSync('./schema/datamodel.graphql').toString(),
readFileSync('./generated/prisma.graphql').toString()
], {
all: true
});
const ultimateSchema = makeExecutableSchema({
typeDefs: ultimateSchemaString,
resolvers,
directiveResolvers
});

const server = new GraphQLServer({
schema: ultimateSchema,
context: (req) => {
return {
...req,
db: PrismaDBConnection
};
}
});

server.start(() => console.log('Server is running on http://localhost:4000'));

@lastmjs nice work. I am going to check this out!

@develomark See this write-up for more information, or to just see this integrated in a small example application: https://medium.com/@lastmjs/advanced-graphql-directive-permissions-with-prisma-fdee6f846044

@kbrandwijk did you guys have some progress on @cacheControl? I know a lot of time has passed, just wondering if there's any easy way to implement it at the moment.

Would a PR be accepted? Isn't it as simple as not stripping out directives in datamodel.prisma? Just leave them in? It's up to the application server to interpret the directives anyway, so at that point shouldn't Prisma not care about the generated schema?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 10 days if no further activity occurs. Thank you for your contributions.

Any progress?

@lastmjs

Would a PR be accepted?

Could you please create the pull request? Hope it will speed up the fix for this issue.

I'm curious about this too, adopting custom directives to the workflow would make things like auth & roles so much easier. Any updates?

Waiting for this too! :) Like @develomark said, this feature will make things easy.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

marktani picture marktani  路  62Comments

blocka picture blocka  路  74Comments

marktani picture marktani  路  71Comments

marktani picture marktani  路  34Comments

sorenbs picture sorenbs  路  48Comments