github.com/maeglindeveloper/gqlgen@v0.13.1-0.20210413081235-57808b12a0a0/docs/content/reference/directives.md (about) 1 --- 2 title: Using schema directives to implement permission checks 3 description: Implementing graphql schema directives in golang for permission checks. 4 linkTitle: Schema Directives 5 menu: { main: { parent: 'reference', weight: 10 } } 6 --- 7 8 Directives are a bit like annotations in any other language. They give you a way to specify some behaviour without directly binding to the implementation. This can be really useful for cross cutting concerns like permission checks. 9 10 **Note**: The current directives implementation is still fairly limited, and is designed to cover the most common "field middleware" case. 11 12 ## Declare it in the schema 13 14 Directives are declared in your schema, along with all your other types. Lets define a @hasRole directive: 15 16 ```graphql 17 directive @hasRole(role: Role!) on FIELD_DEFINITION 18 19 enum Role { 20 ADMIN 21 USER 22 } 23 ``` 24 25 When we next run go generate, gqlgen will add this directive to the DirectiveRoot 26 ```go 27 type DirectiveRoot struct { 28 HasRole func(ctx context.Context, obj interface{}, next graphql.Resolver, role Role) (res interface{}, err error) 29 } 30 ``` 31 32 The arguments are: 33 - *ctx*: the parent context 34 - *obj*: the object containing the value this was applied to, eg: 35 - for field definition directives, the object/input object that contains the field 36 - for argument directives, a map containing all arguments 37 - *next*: the next directive in the directive chain, or the field resolver. This should be called to get the 38 value of the field/argument/whatever. You can block access to the field by not calling next for permission 39 checks etc. 40 - *...args*: Any args to the directive will be passed in too. 41 42 ## Use it in the schema 43 44 We can call this on any field definition now: 45 ```graphql 46 type Mutation { 47 deleteUser(userID: ID!): Bool @hasRole(role: ADMIN) 48 } 49 ``` 50 51 ## Implement the directive 52 53 Finally, we need to implement the directive, and pass it in when starting the server: 54 ```go 55 package main 56 57 func main() { 58 c := Config{ Resolvers: &resolvers{} } 59 c.Directives.HasRole = func(ctx context.Context, obj interface{}, next graphql.Resolver, role Role) (interface{}, error) { 60 if !getCurrentUser(ctx).HasRole(role) { 61 // block calling the next resolver 62 return nil, fmt.Errorf("Access denied") 63 } 64 65 // or let it pass through 66 return next(ctx) 67 } 68 69 http.Handle("/query", handler.GraphQL(todo.NewExecutableSchema(c), )) 70 log.Fatal(http.ListenAndServe(":8081", nil)) 71 } 72 ```