1package graphql
2
3import (
4	"context"
5
6	"github.com/graphql-go/graphql/gqlerrors"
7	"github.com/graphql-go/graphql/language/parser"
8	"github.com/graphql-go/graphql/language/source"
9)
10
11type Params struct {
12	// The GraphQL type system to use when validating and executing a query.
13	Schema Schema
14
15	// A GraphQL language formatted string representing the requested operation.
16	RequestString string
17
18	// The value provided as the first argument to resolver functions on the top
19	// level type (e.g. the query object type).
20	RootObject map[string]interface{}
21
22	// A mapping of variable name to runtime value to use for all variables
23	// defined in the requestString.
24	VariableValues map[string]interface{}
25
26	// The name of the operation to use if requestString contains multiple
27	// possible operations. Can be omitted if requestString contains only
28	// one operation.
29	OperationName string
30
31	// Context may be provided to pass application-specific per-request
32	// information to resolve functions.
33	Context context.Context
34}
35
36func Do(p Params) *Result {
37	source := source.NewSource(&source.Source{
38		Body: []byte(p.RequestString),
39		Name: "GraphQL request",
40	})
41
42	// run init on the extensions
43	extErrs := handleExtensionsInits(&p)
44	if len(extErrs) != 0 {
45		return &Result{
46			Errors: extErrs,
47		}
48	}
49
50	extErrs, parseFinishFn := handleExtensionsParseDidStart(&p)
51	if len(extErrs) != 0 {
52		return &Result{
53			Errors: extErrs,
54		}
55	}
56
57	// parse the source
58	AST, err := parser.Parse(parser.ParseParams{Source: source})
59	if err != nil {
60		// run parseFinishFuncs for extensions
61		extErrs = parseFinishFn(err)
62
63		// merge the errors from extensions and the original error from parser
64		extErrs = append(extErrs, gqlerrors.FormatErrors(err)...)
65		return &Result{
66			Errors: extErrs,
67		}
68	}
69
70	// run parseFinish functions for extensions
71	extErrs = parseFinishFn(err)
72	if len(extErrs) != 0 {
73		return &Result{
74			Errors: extErrs,
75		}
76	}
77
78	// notify extensions abput the start of the validation
79	extErrs, validationFinishFn := handleExtensionsValidationDidStart(&p)
80	if len(extErrs) != 0 {
81		return &Result{
82			Errors: extErrs,
83		}
84	}
85
86	// validate document
87	validationResult := ValidateDocument(&p.Schema, AST, nil)
88
89	if !validationResult.IsValid {
90		// run validation finish functions for extensions
91		extErrs = validationFinishFn(validationResult.Errors)
92
93		// merge the errors from extensions and the original error from parser
94		extErrs = append(extErrs, validationResult.Errors...)
95		return &Result{
96			Errors: extErrs,
97		}
98	}
99
100	// run the validationFinishFuncs for extensions
101	extErrs = validationFinishFn(validationResult.Errors)
102	if len(extErrs) != 0 {
103		return &Result{
104			Errors: extErrs,
105		}
106	}
107
108	return Execute(ExecuteParams{
109		Schema:        p.Schema,
110		Root:          p.RootObject,
111		AST:           AST,
112		OperationName: p.OperationName,
113		Args:          p.VariableValues,
114		Context:       p.Context,
115	})
116}
117