github.com/maeglindeveloper/gqlgen@v0.13.1-0.20210413081235-57808b12a0a0/example/todo/todo.go (about) 1 //go:generate go run ../../testdata/gqlgen.go 2 3 package todo 4 5 import ( 6 "context" 7 "errors" 8 "fmt" 9 "time" 10 11 "github.com/99designs/gqlgen/graphql" 12 "github.com/mitchellh/mapstructure" 13 ) 14 15 var you = &User{ID: 1, Name: "You"} 16 var them = &User{ID: 2, Name: "Them"} 17 18 type ckey string 19 20 func getUserId(ctx context.Context) int { 21 if id, ok := ctx.Value(ckey("userId")).(int); ok { 22 return id 23 } 24 return you.ID 25 } 26 27 func New() Config { 28 c := Config{ 29 Resolvers: &resolvers{ 30 todos: []*Todo{ 31 {ID: 1, Text: "A todo not to forget", Done: false, owner: you}, 32 {ID: 2, Text: "This is the most important", Done: false, owner: you}, 33 {ID: 3, Text: "Somebody else's todo", Done: true, owner: them}, 34 {ID: 4, Text: "Please do this or else", Done: false, owner: you}, 35 }, 36 lastID: 4, 37 }, 38 } 39 c.Directives.HasRole = func(ctx context.Context, obj interface{}, next graphql.Resolver, role Role) (interface{}, error) { 40 switch role { 41 case RoleAdmin: 42 // No admin for you! 43 return nil, nil 44 case RoleOwner: 45 ownable, isOwnable := obj.(Ownable) 46 if !isOwnable { 47 return nil, fmt.Errorf("obj cant be owned") 48 } 49 50 if ownable.Owner().ID != getUserId(ctx) { 51 return nil, fmt.Errorf("you dont own that") 52 } 53 } 54 55 return next(ctx) 56 } 57 c.Directives.User = func(ctx context.Context, obj interface{}, next graphql.Resolver, id int) (interface{}, error) { 58 return next(context.WithValue(ctx, ckey("userId"), id)) 59 } 60 return c 61 } 62 63 type resolvers struct { 64 todos []*Todo 65 lastID int 66 } 67 68 func (r *resolvers) MyQuery() MyQueryResolver { 69 return (*QueryResolver)(r) 70 } 71 72 func (r *resolvers) MyMutation() MyMutationResolver { 73 return (*MutationResolver)(r) 74 } 75 76 type QueryResolver resolvers 77 78 func (r *QueryResolver) Todo(ctx context.Context, id int) (*Todo, error) { 79 time.Sleep(220 * time.Millisecond) 80 81 if id == 666 { 82 panic("critical failure") 83 } 84 85 for _, todo := range r.todos { 86 if todo.ID == id { 87 return todo, nil 88 } 89 } 90 return nil, errors.New("not found") 91 } 92 93 func (r *QueryResolver) LastTodo(ctx context.Context) (*Todo, error) { 94 if len(r.todos) == 0 { 95 return nil, errors.New("not found") 96 } 97 return r.todos[len(r.todos)-1], nil 98 } 99 100 func (r *QueryResolver) Todos(ctx context.Context) ([]*Todo, error) { 101 return r.todos, nil 102 } 103 104 type MutationResolver resolvers 105 106 func (r *MutationResolver) CreateTodo(ctx context.Context, todo TodoInput) (*Todo, error) { 107 newID := r.id() 108 109 newTodo := &Todo{ 110 ID: newID, 111 Text: todo.Text, 112 owner: you, 113 } 114 115 if todo.Done != nil { 116 newTodo.Done = *todo.Done 117 } 118 119 r.todos = append(r.todos, newTodo) 120 121 return newTodo, nil 122 } 123 124 func (r *MutationResolver) UpdateTodo(ctx context.Context, id int, changes map[string]interface{}) (*Todo, error) { 125 var affectedTodo *Todo 126 127 for i := 0; i < len(r.todos); i++ { 128 if r.todos[i].ID == id { 129 affectedTodo = r.todos[i] 130 break 131 } 132 } 133 134 if affectedTodo == nil { 135 return nil, nil 136 } 137 138 err := mapstructure.Decode(changes, affectedTodo) 139 if err != nil { 140 panic(err) 141 } 142 143 return affectedTodo, nil 144 } 145 146 func (r *MutationResolver) id() int { 147 r.lastID++ 148 return r.lastID 149 }