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  ```