public function testCustomTypes() { $authorType = null; $userInterface = new ObjectType(['name' => 'UserInterface', 'fields' => ['name' => new StringType()], 'resolveType' => function () use($authorType) { return $authorType; }]); $authorType = new ObjectType(['name' => 'Author', 'fields' => ['name' => new StringType()], 'interfaces' => [$userInterface]]); $schema = new Schema(['query' => new ObjectType(['name' => 'QueryType', 'fields' => ['user' => ['type' => $userInterface, 'resolve' => function () { return ['name' => 'Alex']; }]]])]); $schema->getTypesList()->addType($authorType); $processor = new Processor($schema); $processor->processPayload('{ user { name } }'); $this->assertEquals(['data' => ['user' => ['name' => 'Alex']]], $processor->getResponseData()); $processor->processPayload('{ __schema { types { name } } }'); $data = $processor->getResponseData(); $this->assertArraySubset([11 => ['name' => 'Author']], $data['data']['__schema']['types']); $processor->processPayload('{ user { name { } } }'); $result = $processor->getResponseData(); $this->assertEquals(['errors' => [['message' => 'Unexpected token "RBRACE"', 'locations' => [['line' => 1, 'column' => 19]]]]], $result); $processor->getExecutionContext()->clearErrors(); $processor->processPayload('{ user { name { invalidSelection } } }'); $result = $processor->getResponseData(); $this->assertEquals(['data' => ['user' => null], 'errors' => [['message' => 'You can\'t specify fields for scalar type "String"', 'locations' => [['line' => 1, 'column' => 10]]]]], $result); }
public function testListInsideInputObject() { $processor = new Processor(new Schema(['query' => new ObjectType(['name' => 'RootQueryType', 'fields' => ['empty' => ['type' => new StringType(), 'resolve' => function () { }]]]), 'mutation' => new ObjectType(['name' => 'RootMutation', 'fields' => ['createList' => ['type' => new StringType(), 'args' => ['topArgument' => new InputObjectType(['name' => 'topArgument', 'fields' => ['postObject' => new ListType(new InputObjectType(['name' => 'postObject', 'fields' => ['title' => new NonNullType(new StringType())]]))]])], 'resolve' => function () { return 'success message'; }]]])])); $processor->processPayload('mutation { createList(topArgument: { postObject:[ { title: null } ] })}'); $this->assertEquals(['data' => ['createList' => null], 'errors' => [['message' => 'Not valid type for argument "topArgument" in query "createList"', 'locations' => [['line' => 1, 'column' => 23]]]]], $processor->getResponseData()); $processor->getExecutionContext()->clearErrors(); $processor->processPayload('mutation { createList(topArgument:{ postObject:[{title: "not empty"}] })}'); $this->assertEquals(['data' => ['createList' => 'success message']], $processor->getResponseData()); }
public function processPayload($payload, $variables = [], $reducers = []) { if ($this->logger) { $this->logger->debug(sprintf('GraphQL query: %s', $payload), (array) $variables); } parent::processPayload($payload, $variables); }
public function testType() { $reportType = new ObjectType(['name' => 'Report', 'fields' => ['time' => new TestTimeType(), 'title' => new StringType()]]); $processor = new Processor(new Schema(['query' => new ObjectType(['name' => 'RootQueryType', 'fields' => ['latestReport' => ['type' => $reportType, 'resolve' => function () { return ['title' => 'Accident #1', 'time' => '13:30:12']; }]]])])); $processor->processPayload('{ latestReport { title, time} }'); $this->assertEquals(['data' => ['latestReport' => ['title' => 'Accident #1', 'time' => '13:30:12']]], $processor->getResponseData()); }
/** * @dataProvider queries * * @param $query * @param $expected */ public function testDateInput($query, $expected) { $schema = new Schema(['query' => new ObjectType(['name' => 'RootQuery', 'fields' => ['stringQuery' => ['type' => new StringType(), 'args' => ['from' => new DateTimeType(), 'fromtz' => new DateTimeTzType()], 'resolve' => function ($source, $args) { return sprintf('Result with %s date and %s tz', empty($args['from']) ? 'default' : $args['from'], empty($args['fromtz']) ? 'default' : $args['fromtz']); }]]])]); $processor = new Processor($schema); $processor->processPayload($query); $result = $processor->getResponseData(); $this->assertEquals($expected, $result); }
/** * @dataProvider queries * * @param $query * @param $expected * @param $variables */ public function testVariables($query, $expected, $variables) { $schema = new Schema(['query' => new ObjectType(['name' => 'RootQuery', 'fields' => ['stringQuery' => ['type' => new StringType(), 'args' => ['sortOrder' => new StringType()], 'resolve' => function ($args) { return sprintf('Result with %s order', empty($args['sortOrder']) ? 'default' : $args['sortOrder']); }]]])]); $processor = new Processor($schema); $processor->processPayload($query, $variables); $result = $processor->getResponseData(); $this->assertEquals($expected, $result); }
public function testInvalidVariableType() { $processor = new Processor(new StarWarsSchema()); $processor->processPayload('query($someId: Int){ human(id: $someId) { name } }'); $data = $processor->getResponseData(); $this->assertEquals($data, ['data' => ['human' => null], 'errors' => [['message' => 'Invalid variable "someId" type, allowed type is "ID"', 'locations' => [['line' => 1, 'column' => 7]]]]]); }
public function testDefaultEnum() { $enumType = new EnumType(['name' => 'InternalStatus', 'values' => [['name' => 1, 'value' => 'ACTIVE'], ['name' => 0, 'value' => 'DISABLED']]]); $schema = new Schema(['query' => new ObjectType(['name' => 'RootQuery', 'fields' => ['stringQuery' => ['type' => new StringType(), 'args' => ['statObject' => new InputObjectType(['name' => 'StatObjectType', 'fields' => ['status' => ['type' => $enumType, 'default' => 1], 'level' => new NonNullType(new IntType())]])], 'resolve' => function ($source, $args) { return sprintf('Result with level %s and status %s', $args['statObject']['level'], $args['statObject']['status']); }]]])]); $processor = new Processor($schema); $processor->processPayload('{ stringQuery(statObject: { level: 1 }) }'); $result = $processor->getResponseData(); $this->assertEquals(['data' => ['stringQuery' => 'Result with level 1 and status ACTIVE']], $result); }
/** * @inheritdoc */ public function connect(Application $app) { /** @var ControllerCollection $controllers */ $controllers = $app['controllers_factory']; $controllers->before(function (Request $request) { if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) { $data = json_decode($request->getContent(), true); $request->request->replace(is_array($data) ? $data : []); } })->match('/', function (Application $app, Request $request) { $query = $request->get('query', ''); $variables = $request->get('variables', []); $processor = new Processor($this->schema); $processor->processPayload($query, $variables); return $app->json($processor->getResponseData()); }); return $controllers; }
/** * @dataProvider queries * * @param $query * @param $expected */ public function testNullableResolving($query, $expected) { $schema = new Schema(['query' => new ObjectType(['name' => 'RootQuery', 'fields' => ['nonNullScalar' => ['type' => new NonNullType(new IntType()), 'resolve' => function () { return null; }], 'nonNullList' => ['type' => new NonNullType(new ListType(new IntType())), 'resolve' => function () { return null; }], 'user' => ['type' => new NonNullType(new ObjectType(['name' => 'User', 'fields' => ['id' => new NonNullType(new IdType()), 'name' => new StringType()]])), 'resolve' => function () { return ['id' => new uid('6cfb044c-9c0a-4ddd-9ef8-a0b940818db3'), 'name' => 'Alex']; }], 'nonNullListOfNpnNull' => ['type' => new NonNullType(new ListType(new NonNullType(new IntType()))), 'resolve' => function () { return [1, null]; }], 'nonNullArgument' => ['args' => ['ids' => new NonNullType(new ListType(new IntType()))], 'type' => new IntType(), 'resolve' => function () { return 1; }], 'nonNullArgument2' => ['args' => ['ids' => new NonNullType(new ListType(new NonNullType(new IntType())))], 'type' => new IntType(), 'resolve' => function () { return 1; }]]])]); $processor = new Processor($schema); $processor->processPayload($query); $result = $processor->getResponseData(); $this->assertEquals($expected, $result); }
public function testLoad10k() { $time = microtime(true); $postType = new ObjectType(['name' => 'Post', 'fields' => ['id' => new IdType(), 'title' => new StringType(), 'authors' => ['type' => new ListType(new ObjectType(['name' => 'Author', 'fields' => ['name' => new StringType()]]))]]]); $data = []; for ($i = 1; $i <= 10000; ++$i) { $authors = []; while (count($authors) < rand(1, 4)) { $authors[] = ['name' => 'Author ' . substr(md5(time()), 0, 4)]; } $data[] = ['id' => $i, 'title' => 'Title of ' . $i, 'authors' => $authors]; } $p = new Processor(new Schema(['query' => new ObjectType(['name' => 'RootQuery', 'fields' => ['posts' => ['type' => new ListType($postType), 'resolve' => function () use($data) { return $data; }]]])])); return true; $p->processPayload('{ posts { id, title, authors { name } } }'); $res = $p->getResponseData(); echo "Count: " . count($res['data']['posts']) . "\n"; var_dump($res['data']['posts'][0]); printf("Test Time: %04f\n", microtime(true) - $time); }
public function testComplexityReducer() { $schema = new Schema(['query' => new ObjectType(['name' => 'RootQuery', 'fields' => ['me' => ['type' => new ObjectType(['name' => 'User', 'fields' => ['firstName' => ['type' => new StringType(), 'args' => ['shorten' => new BooleanType()], 'resolve' => function ($value, $args) { return empty($args['shorten']) ? $value['firstName'] : $value['firstName']; }], 'lastName' => new StringType(), 'code' => new StringType(), 'likes' => ['type' => new IntType(), 'cost' => 10, 'resolve' => function () { return 42; }]]]), 'cost' => function ($args, $context, $childCost) { $argsCost = isset($args['cost']) ? $args['cost'] : 1; return 1 + $argsCost * $childCost; }, 'resolve' => function ($value, $args) { $data = ['firstName' => 'John', 'code' => '007']; return $data; }, 'args' => ['cost' => ['type' => new IntType(), 'default' => 1]]]]])]); $processor = new Processor($schema); $processor->setMaxComplexity(10); $processor->processPayload('{ me { firstName, lastName } }'); $this->assertArrayNotHasKey('error', $processor->getResponseData()); $processor->processPayload('{ me { } }'); $this->assertEquals(['errors' => [['message' => 'Unexpected token "RBRACE"', 'locations' => [['line' => 1, 'column' => 10]]]]], $processor->getResponseData()); $processor->getExecutionContext()->clearErrors(); $processor->processPayload('{ me { firstName, likes } }'); $this->assertEquals(['errors' => [['message' => 'query exceeded max allowed complexity of 10']]], $processor->getResponseData()); $processor->getExecutionContext()->clearErrors(); // don't let complexity reducer affect query errors $processor->processPayload('{ me { badfield } }'); $this->assertArraySubset(['errors' => [['message' => 'Field "badfield" not found in type "User"']]], $processor->getResponseData()); $processor->getExecutionContext()->clearErrors(); foreach (range(1, 5) as $cost_multiplier) { $visitor = new MaxComplexityQueryVisitor(1000); // arbitrarily high cost $processor->processPayload("{ me (cost: {$cost_multiplier}) { firstName, lastName, code, likes } }", ['cost' => $cost_multiplier], [$visitor]); $expected = 1 + 13 * (1 + $cost_multiplier); $this->assertEquals($expected, $visitor->getMemo()); } // TODO, variables not yet supported /*$query = 'query costQuery ($cost: Int) { me (cost: $cost) { firstName, lastName, code, likes } }'; foreach (range(1,5) as $cost_multiplier) { $visitor = new \Youshido\GraphQL\Execution\Visitor\MaxComplexityQueryVisitor(1000); // arbitrarily high cost $processor->processPayload($query, ['cost' => $cost_multiplier], [$visitor]); $expected = 1 + 13 * (1 + $cost_multiplier); $this->assertEquals($expected, $visitor->getMemo()); }*/ }
public function testCombinedFields() { $schema = new TestEmptySchema(); $interface = new InterfaceType(['name' => 'TestInterface', 'fields' => ['id' => ['type' => new IntType()], 'name' => ['type' => new IntType()]], 'resolveType' => function ($type) { }]); $object1 = new ObjectType(['name' => 'Test1', 'fields' => ['id' => ['type' => new IntType()], 'name' => ['type' => new IntType()], 'lastName' => ['type' => new IntType()]], 'interfaces' => [$interface]]); $object2 = new ObjectType(['name' => 'Test2', 'fields' => ['id' => ['type' => new IntType()], 'name' => ['type' => new IntType()], 'thirdName' => ['type' => new IntType()]], 'interfaces' => [$interface]]); $unionType = new UnionType(['name' => 'UnionType', 'types' => [$object1, $object2], 'resolveType' => function () { }]); $schema->addQueryField(new Field(['name' => 'union', 'type' => $unionType, 'args' => ['id' => ['type' => TypeMap::TYPE_INT]], 'resolve' => function () { return ['id' => 1, 'name' => 'Alex']; }])); $schema->addMutationField(new Field(['name' => 'mutation', 'type' => $unionType, 'args' => ['type' => new EnumType(['name' => 'MutationType', 'values' => [['name' => 'Type1', 'value' => 'type_1'], ['name' => 'Type2', 'value' => 'type_2']]])], 'resolve' => function () { return null; }])); $processor = new Processor($schema); $processor->processPayload($this->introspectionQuery); $responseData = $processor->getResponseData(); /** strange that this test got broken after I fixed the field resolve behavior */ $this->assertArrayNotHasKey('errors', $responseData); }
<?php namespace BlogTest; header('Access-Control-Allow-Credentials: false', true); header('Access-Control-Allow-Origin: *'); if ($_SERVER['REQUEST_METHOD'] == "OPTIONS") { return; } use Examples\Blog\Schema\BlogSchema; use Youshido\GraphQL\Execution\Processor; use Youshido\GraphQL\Schema\Schema; require_once __DIR__ . '/schema-bootstrap.php'; /** @var Schema $schema */ $schema = new BlogSchema(); if (isset($_SERVER['CONTENT_TYPE']) && $_SERVER['CONTENT_TYPE'] === 'application/json') { $rawBody = file_get_contents('php://input'); $requestData = json_decode($rawBody ?: '', true); } else { $requestData = $_POST; } $payload = isset($requestData['query']) ? $requestData['query'] : null; $variables = isset($requestData['variables']) ? $requestData['variables'] : null; $processor = new Processor($schema); $response = $processor->processPayload($payload, $variables)->getResponseData(); header('Content-Type: application/json'); echo json_encode($response);
<?php namespace Sandbox; use Youshido\GraphQL\Execution\Processor; use Youshido\GraphQL\Schema\Schema; use Youshido\GraphQL\Type\Object\ObjectType; use Youshido\GraphQL\Type\Scalar\StringType; require_once __DIR__ . '/../../../../../vendor/autoload.php'; $processor = new Processor(new Schema(['query' => new ObjectType(['name' => 'RootQueryType', 'fields' => ['currentTime' => ['type' => new StringType(), 'resolve' => function () { return date('Y-m-d H:ia'); }]]])])); $processor->processPayload('{ currentTime }'); echo json_encode($processor->getResponseData()) . "\n";
<?php namespace BlogTest; use Examples\Blog\Schema\BlogSchema; use Youshido\GraphQL\Execution\Processor; use Youshido\GraphQL\Schema\Schema; require_once __DIR__ . '/schema-bootstrap.php'; /** @var Schema $schema */ $schema = new BlogSchema(); $processor = new Processor($schema); $payload = 'mutation { likePost(id:5) { title(truncated: false), status, likeCount } }'; $payload = '{ latestPost { title, status, likeCount } }'; $payload = '{ pageContentUnion { ... on Post { title, summary } ... on Banner { title, imageLink } } }'; $payload = '{ pageContentInterface { title} }'; $payload = 'mutation { createPost(author: "Alex", post: {title: "Hey, this is my new post", summary: "my post" }) { title } }'; $processor->processPayload($payload); echo json_encode($processor->getResponseData()) . "\n";
public function testSimpleFragment() { $schema = new Schema(['query' => new ObjectType(['name' => 'RootQuery', 'fields' => ['user' => ['type' => new UserType(), 'resolve' => function ($args) { return ['id' => 'user-id-1', 'fullName' => 'Alex']; }, 'args' => ['id' => new IntType()]]]])]); $query = ' { User1: user(id: 1) { fullName } User2: user(id: 1) { ...Fields } } fragment Fields on User { fullName }'; $processor = new Processor($schema); $processor->processPayload($query); $result = $processor->getResponseData(); $expected = ['data' => ['User1' => ['fullName' => 'Alex'], 'User2' => ['fullName' => 'Alex']]]; $this->assertEquals($expected, $result); }
} fragment F0 on Ship { id, name } fragment F1 on Faction { id, factionId } fragment F2 on Faction { id, factionId, name, _shipsDRnzJ:ships(first:10) { edges { node { id, ...F0 }, cursor }, pageInfo { hasNextPage, hasPreviousPage } }, ...F1 } '; $processor->processPayload($payload, ['names_0' => ['rebels']]); echo json_encode($processor->getResponseData()) . "\n";