error.go

  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}