github.com/99designs/gqlgen@v0.17.45/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 act a bit like annotations, decorators, or HTTP middleware. They give you a way to specify some behaviour based on a field or argument in a generic and reusable way. This can be really useful for cross-cutting concerns like permission checks which can be applied broadly across your API.
     9  
    10  **Note**: The current directives implementation is still fairly limited, and is designed to cover the most common "field middleware" case.
    11  
    12  ## Restricting access based on user role
    13  
    14  For example, we might want to restrict which mutations or queries a client can make based on the authenticated user's role:
    15  ```graphql
    16  type Mutation {
    17  	deleteUser(userID: ID!): Bool @hasRole(role: ADMIN)
    18  }
    19  ```
    20  
    21  ### Declare it in the schema
    22  
    23  Before we can use a directive we must declare it in the schema. Here's how we would define the `@hasRole` directive:
    24  
    25  ```graphql
    26  directive @hasRole(role: Role!) on FIELD_DEFINITION
    27  
    28  enum Role {
    29      ADMIN
    30      USER
    31  }
    32  ```
    33  
    34  Next, run `go generate` and gqlgen will add the directive to the DirectiveRoot:
    35  ```go
    36  type DirectiveRoot struct {
    37  	HasRole func(ctx context.Context, obj interface{}, next graphql.Resolver, role Role) (res interface{}, err error)
    38  }
    39  ```
    40  
    41  The arguments are:
    42   - *ctx*: the parent context
    43   - *obj*: the object containing the value this was applied to, e.g.:
    44      - for field definition directives (`FIELD_DEFINITION`), the object/input object that contains the field
    45      - for argument directives (`ARGUMENT_DEFINITION`), a map containing all arguments
    46   - *next*: the next directive in the directive chain, or the field resolver. This should be called to get the
    47             value of the field/argument/whatever. You can block access to the field by not calling `next(ctx)`
    48             after checking whether a user has a required permission, for example.
    49   - *...args*: finally, any args defined in the directive schema definition are passed in
    50  
    51  ## Implement the directive
    52  
    53  Now we must implement the directive. The directive function is assigned to the Config object before registering the GraphQL handler.
    54  ```go
    55  package main
    56  
    57  func main() {
    58  	c := generated.Config{ Resolvers: &resolvers{} }
    59  	c.Directives.HasRole = func(ctx context.Context, obj interface{}, next graphql.Resolver, role model.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.NewDefaultServer(generated.NewExecutableSchema(c), ))
    70  	log.Fatal(http.ListenAndServe(":8081", nil))
    71  }
    72  ```
    73  
    74  That's it! You can now apply the `@hasRole` directive to any mutation or query in your schema.