in router/core/operation_processor.go [499:615]
func (o *OperationKit) Parse() error {
var (
anonymousOperationCount = 0
anonymousOperationDefinitionRef = -1
)
if len(o.parsedOperation.Request.Query) == 0 {
return &httpGraphqlError{
message: "error parsing request body",
statusCode: http.StatusBadRequest,
}
}
report := &operationreport.Report{}
o.kit.doc.Input.ResetInputString(o.parsedOperation.Request.Query)
o.kit.parser.Parse(o.kit.doc, report)
if report.HasErrors() {
return &reportError{
report: report,
}
}
if !o.introspectionEnabled {
isIntrospection, err := o.isIntrospectionQuery()
if err != nil {
return &httpGraphqlError{
message: "could not determine if operation was an introspection query",
statusCode: http.StatusOK,
}
}
if isIntrospection {
return &httpGraphqlError{
message: "GraphQL introspection is disabled by Cosmo Router, but the query contained __schema or __type. To enable introspection, set introspection_enabled: true in the Router configuration",
statusCode: http.StatusOK,
}
}
}
o.kit.numOperations = 0
for i := range o.kit.doc.RootNodes {
if o.kit.doc.RootNodes[i].Kind != ast.NodeKindOperationDefinition {
continue
}
o.kit.numOperations++
ref := o.kit.doc.RootNodes[i].Ref
name := string(o.kit.doc.OperationDefinitionNameBytes(ref))
if len(name) == 0 {
anonymousOperationCount++
if anonymousOperationDefinitionRef == -1 {
anonymousOperationDefinitionRef = ref
}
continue
}
if o.parsedOperation.Request.OperationName == "" {
o.operationDefinitionRef = ref
o.originalOperationNameRef = o.kit.doc.OperationDefinitions[ref].Name
o.parsedOperation.Request.OperationName = name
continue
}
if name == o.parsedOperation.Request.OperationName && o.operationDefinitionRef == -1 {
o.operationDefinitionRef = ref
o.originalOperationNameRef = o.kit.doc.OperationDefinitions[ref].Name
}
}
if o.parsedOperation.Request.OperationName == "" && o.kit.numOperations > 1 {
return &httpGraphqlError{
message: "operation name is required when multiple operations are defined",
statusCode: http.StatusOK,
}
}
if o.parsedOperation.Request.OperationName != "" && o.kit.numOperations != 0 && o.operationDefinitionRef == -1 {
return &httpGraphqlError{
message: fmt.Sprintf("operation with name '%s' not found", o.parsedOperation.Request.OperationName),
statusCode: http.StatusOK,
}
}
if o.operationDefinitionRef == -1 {
if anonymousOperationCount == 1 {
o.operationDefinitionRef = anonymousOperationDefinitionRef
} else if anonymousOperationCount > 1 {
return &httpGraphqlError{
message: "operation name is required when multiple operations are defined",
statusCode: http.StatusOK,
}
} else {
return &httpGraphqlError{
message: fmt.Sprintf("operation with name '%s' not found", o.parsedOperation.Request.OperationName),
statusCode: http.StatusOK,
}
}
}
switch o.kit.doc.OperationDefinitions[o.operationDefinitionRef].OperationType {
case ast.OperationTypeQuery:
o.parsedOperation.Type = "query"
case ast.OperationTypeMutation:
o.parsedOperation.Type = "mutation"
case ast.OperationTypeSubscription:
o.parsedOperation.Type = "subscription"
default:
return &httpGraphqlError{
message: "operation type not supported",
statusCode: http.StatusOK,
}
}
// Replace the operation name with a static name to avoid different IDs for the same operation
replaceOperationName := o.kit.doc.Input.AppendInputBytes(staticOperationName)
o.kit.doc.OperationDefinitions[o.operationDefinitionRef].Name = replaceOperationName
return nil
}