1package gqlerror
2
3import (
4 "bytes"
5 "fmt"
6 "strconv"
7
8 "github.com/vektah/gqlparser/ast"
9)
10
11// Error is the standard graphql error type described in https://facebook.github.io/graphql/draft/#sec-Errors
12type Error struct {
13 Message string `json:"message"`
14 Path []interface{} `json:"path,omitempty"`
15 Locations []Location `json:"locations,omitempty"`
16 Extensions map[string]interface{} `json:"extensions,omitempty"`
17 Rule string `json:"-"`
18}
19
20func (err *Error) SetFile(file string) {
21 if file == "" {
22 return
23 }
24 if err.Extensions == nil {
25 err.Extensions = map[string]interface{}{}
26 }
27
28 err.Extensions["file"] = file
29}
30
31type Location struct {
32 Line int `json:"line,omitempty"`
33 Column int `json:"column,omitempty"`
34}
35
36type List []*Error
37
38func (err *Error) Error() string {
39 var res bytes.Buffer
40 if err == nil {
41 return ""
42 }
43 filename, _ := err.Extensions["file"].(string)
44 if filename == "" {
45 filename = "input"
46 }
47 res.WriteString(filename)
48
49 if len(err.Locations) > 0 {
50 res.WriteByte(':')
51 res.WriteString(strconv.Itoa(err.Locations[0].Line))
52 }
53
54 res.WriteString(": ")
55 if ps := err.pathString(); ps != "" {
56 res.WriteString(ps)
57 res.WriteByte(' ')
58 }
59
60 res.WriteString(err.Message)
61
62 return res.String()
63}
64
65func (err Error) pathString() string {
66 var str bytes.Buffer
67 for i, v := range err.Path {
68
69 switch v := v.(type) {
70 case int, int64:
71 str.WriteString(fmt.Sprintf("[%d]", v))
72 default:
73 if i != 0 {
74 str.WriteByte('.')
75 }
76 str.WriteString(fmt.Sprint(v))
77 }
78 }
79 return str.String()
80}
81
82func (errs List) Error() string {
83 var buf bytes.Buffer
84 for _, err := range errs {
85 buf.WriteString(err.Error())
86 buf.WriteByte('\n')
87 }
88 return buf.String()
89}
90
91func WrapPath(path []interface{}, err error) *Error {
92 return &Error{
93 Message: err.Error(),
94 Path: path,
95 }
96}
97
98func Errorf(message string, args ...interface{}) *Error {
99 return &Error{
100 Message: fmt.Sprintf(message, args...),
101 }
102}
103
104func ErrorPathf(path []interface{}, message string, args ...interface{}) *Error {
105 return &Error{
106 Message: fmt.Sprintf(message, args...),
107 Path: path,
108 }
109}
110
111func ErrorPosf(pos *ast.Position, message string, args ...interface{}) *Error {
112 return ErrorLocf(
113 pos.Src.Name,
114 pos.Line,
115 pos.Column,
116 message,
117 args...,
118 )
119}
120
121func ErrorLocf(file string, line int, col int, message string, args ...interface{}) *Error {
122 var extensions map[string]interface{}
123 if file != "" {
124 extensions = map[string]interface{}{"file": file}
125 }
126 return &Error{
127 Message: fmt.Sprintf(message, args...),
128 Extensions: extensions,
129 Locations: []Location{
130 {Line: line, Column: col},
131 },
132 }
133}