drupal-graphql / drupal-graphql/graphql

Some invalid queries may return a 500 Internal Server Error

Open
#1,158 0 comments 0 reactions 0 assignees View on GitHub
3.x bug
Dominant language
PHP
Stars
287
Forks
198
PR merge metrics
No merged PRs in 30d

Description

Disclaimer: I'm not that experienced in the domain of GraphQL, so I may very well have the wrong expectations here.

It is my understanding that (when using GraphQL over HTTP), the HTTP response status code is always 200 for queries that generate an error. For example, the Drupal GraphQL module correctly returns a 200 HTTP response status code for the following invalid query:
```
{
"errors": [
{
"message": "Cannot query field \"unknownField\" on type \"NodeArticle\".",
"category": "graphql",
"locations": [
{
"line": 5,
"column": 9
}
]
}
]
}
```

However, the following query results in a 500 Internal Server Error:
```
{
nodeQuery {
entities {
... on NodeBundleThatDoesNotExist {
unknownField
}
}
}
}
```
```
The website encountered an unexpected error. Please try again later.

LogicException: Missing type NodeBundleThatDoesNotExist. in Drupal\graphql\Plugin\GraphQL\Schemas\SchemaPluginBase->getType() (line 421 of modules/contrib/graphql/src/Plugin/GraphQL/Schemas/SchemaPluginBase.php).
Drupal\graphql\Plugin\GraphQL\Schemas\SchemaPluginBase->Drupal\graphql\Plugin\GraphQL\Schemas\{closure}('NodeBundleThatDoesNotExist') (Line: 319)
GraphQL\Type\Schema->loadType('NodeBundleThatDoesNotExist') (Line: 212)
GraphQL\Type\Schema->getType('NodeBundleThatDoesNotExist') (Line: 504)
GraphQL\Utils\AST::typeFromAST(Object, Object) (Line: 66)
GraphQL\Utils\TypeInfo::typeFromAST(Object, Object) (Line: 825)
GraphQL\Validator\Rules\OverlappingFieldsCanBeMerged->internalCollectFieldsAndFragmentNames(Object, Object, Object, Array, Array) (Line: 739)
GraphQL\Validator\Rules\OverlappingFieldsCanBeMerged->getFieldsAndFragmentNames(Object, Object, Object) (Line: 162)
GraphQL\Validator\Rules\OverlappingFieldsCanBeMerged->findConflictsWithinSelectionSet(Object, Object, Object) (Line: 71)
GraphQL\Validator\Rules\OverlappingFieldsCanBeMerged->GraphQL\Validator\Rules\{closure}(Object, 'selectionSet', Object, Array, Array)
call_user_func_array(Object, Array) (Line: 372)
GraphQL\Language\Visitor::GraphQL\Language\{closure}(Object, 'selectionSet', Object, Array, Array)
call_user_func_array(Object, Array) (Line: 426)
GraphQL\Language\Visitor::GraphQL\Language\{closure}(Object, 'selectionSet', Object, Array, Array)
call_user_func(Object, Object, 'selectionSet', Object, Array, Array) (Line: 251)
GraphQL\Language\Visitor::visit(Object, Array) (Line: 365)
Drupal\graphql\GraphQL\Execution\QueryProcessor->validateOperation(Object, Object, Object) (Line: 287)
Drupal\graphql\GraphQL\Execution\QueryProcessor->doExecuteOperation(Object, Object, Object, Object, 1) (Line: 241)
Drupal\graphql\GraphQL\Execution\QueryProcessor->executeCacheableOperation(Object, Object, Object, Object, 1) (Line: 204)
Drupal\graphql\GraphQL\Execution\QueryProcessor->executeOperation(Object, Object, Object, ) (Line: 149)
Drupal\graphql\GraphQL\Execution\QueryProcessor->executeOperationWithReporting(Object, Object, Object, ) (Line: 120)
Drupal\graphql\GraphQL\Execution\QueryProcessor->executeSingle(Object, Object) (Line: 109)
Drupal\graphql\GraphQL\Execution\QueryProcessor->processQuery('default:default', Object) (Line: 59)
Drupal\graphql\Controller\RequestController->handleSingle('default:default', Object) (Line: 70)
Drupal\graphql\Controller\RequestController->handleRequest('default:default', Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 573)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 151)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 708)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
```

I'm wondering if this is works as designed or this could be improved upon?

Catching all exceptions (`\Exception`) @ https://github.com/drupal-graphql/graphql/blob/8.x-3.x/src/GraphQL/Execution/QueryProcessor.php#L219 would solve this. The query above would then generate the following response (with 200 HTTP status code):
```
{
"errors": [
{
"message": "Internal server error",
"category": "internal"
}
]
}
```

But I'm unsure if this can cause any unintended consequences?

PS: the examples above are based on the 3.x version of the module. I haven't tested this on the 4.x version yet.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.