getting started in graphql-php: how to add resolver functions to schema from .graphql file?
我是GraphQL的新手,并且想与graphql-php一起使用,以构建一个入门的简单API。我目前正在阅读文档并尝试使用示例,但是起初我很困惑。
我希望将架构存储在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | <?php // graph-ql is installed via composer require('../vendor/autoload.php'); use GraphQL\\Language\\Parser; use GraphQL\\Utils\\BuildSchema; use GraphQL\\Utils\\AST; use GraphQL\\GraphQL; try { $cacheFilename = 'cached_schema.php'; // caching, as recommended in the docs, is disabled for testing // if (!file_exists($cacheFilename)) { $document = Parser::parse(file_get_contents('./schema.graphql')); file_put_contents($cacheFilename,"<?php\ return" . var_export(AST::toArray($document), true) . ';'); /*} else { $document = AST::fromArray(require $cacheFilename); // fromArray() is a lazy operation as well }*/ $typeConfigDecorator = function($typeConfig, $typeDefinitionNode) { // In the docs, this function is just empty, but I needed to return the $typeConfig, otherwise I got an error return $typeConfig; }; $schema = BuildSchema::build($document, $typeConfigDecorator); $context = (object)array(); // this has been taken from one of the examples provided in the repo $rawInput = file_get_contents('php://input'); $input = json_decode($rawInput, true); $query = $input['query']; $variableValues = isset($input['variables']) ? $input['variables'] : null; $rootValue = ['prefix' => 'You said: ']; $result = GraphQL::executeQuery($schema, $query, $rootValue, $context, $variableValues); $output = $result->toArray(); } catch (\\Exception $e) { $output = [ 'error' => [ 'message' => $e->getMessage() ] ]; } header('Content-Type: application/json; charset=UTF-8'); echo json_encode($output); |
这是我的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | schema { query: Query } type Query { products: [Product!]! } type Product { id: ID!, type: ProductType } enum ProductType { HDRI, SEMISPHERICAL_HDRI, SOUND } |
我可以例如查询
1 2 3 | query { __schema {types{name}} } |
并且这将按预期返回元数据。但是,当然,现在我想查询实际的产品数据,并从数据库中获取数据,为此,我需要定义一个解析器功能。
http://webonyx.github.io/graphql-php/type-system/type-language/上的文档说明:"默认情况下,这种架构是在没有任何解析器的情况下创建的。我们必须依靠默认字段解析器和根值以便针对该架构执行查询。" -但是没有这样做的例子。
如何为每种类型/字段添加解析器功能?
此方法无需实例化服务器即可工作。 就我而言,我已经有一个服务器并且可以读取HTTP数据,我所需要做的就是读取GraphQL模式并运行查询。 首先,我从文件中读取模式:
1 2 3 4 5 | $schemaContent = // file_get_contents or whatever works for you $schemaDocument = GraphQL\\Language\\Parser::parse($schemaContent); $schemaBuilder = new GraphQL\\Utils\\BuildSchema($schemaDocument); $schema = $schemaBuilder->buildSchema(); |
然后,我通过自定义字段解析器执行查询:
1 2 3 4 5 6 7 8 9 10 11 12 13 | $fieldResolver = function() { return call_user_func_array([$this, 'defaultFieldResolver'], func_get_args()); }; $result = GraphQL\\GraphQL::executeQuery( $schema, $query, // this was grabbed from the HTTP post data null, $appContext, // custom context $variables, // this was grabbed from the HTTP post data null, $fieldResolver // HERE, custom field resolver ); |
字段解析器如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | private static function defaultFieldResolver( $source, $args, $context, \\GraphQL\\Type\\Definition\ esolveInfo $info ) { $fieldName = $info->fieldName; $parentType = $info->parentType->name; if ($source === NULL) { // this is the root value, return value depending on $fieldName // ... } else { // Depending on field type ($parentType), I call different field resolvers. // Since our system is big, we implemented a bootstrapping mechanism // so modules can register field resolvers in this class depending on field type // ... // If no field resolver was defined for this $parentType, // we just rely on the default field resolver provided by graphql-php (copy/paste). $fieldName = $info->fieldName; $property = null; if (is_array($source) || $source instanceof \\ArrayAccess) { if (isset($source[$fieldName])) { $property = $source[$fieldName]; } } else if (is_object($source)) { if (isset($source->{$fieldName})) { $property = $source->{$fieldName}; } } return $property instanceof \\Closure ? $property($source, $args, $context) : $property; } } |
这就是我最终要做的...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | $rootResolver = array( 'emptyCart' => function($root, $args, $context, $info) { global $rootResolver; initSession(); $_SESSION['CART']->clear(); return $rootResolver['getCart']($root, $args, $context, $info); }, 'addCartProduct' => function($root, $args, $context, $info) { global $rootResolver; ... return $rootResolver['getCart']($root, $args, $context, $info); }, 'removeCartProduct' => function($root, $args, $context, $info) { global $rootResolver; ... return $rootResolver['getCart']($root, $args, $context, $info); }, 'getCart' => function($root, $args, $context, $info) { initSession(); return array( 'count' => $_SESSION['CART']->quantity(), 'total' => $_SESSION['CART']->total(), 'products' => $_SESSION['CART']->getProductData() ); }, |
然后在配置中
1 2 3 4 5 6 7 8 9 | $config = ServerConfig::create() ->setSchema($schema) ->setRootValue($rootResolver) ->setContext($context) ->setDebug(DEBUG_MODE) ->setQueryBatching(true) ; $server = new StandardServer($config); |
在我看来,这有点hacking,我可能应该将解析程序外包到单独的文件中,但是它可以正常工作……仍然感到困惑的是,没有简单的示例可以完成此任务,也许比我的解决方案更好。
我为此使用根值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | <?php require("vendor/autoload.php") ; require("exemplo-graphql.php"); require("Usuario.php"); use GraphQL\\GraphQL; use GraphQL\\Type\\Schema; use GraphQL\\Utils\\BuildSchema; $query = $_REQUEST['query']; $typeConfigDecorator = function($typeConfig, $typeDefinitionNode) { $name = $typeConfig['name']; // ... add missing options to $typeConfig based on type $name return $typeConfig; }; $contents = file_get_contents('schema.graphql'); $schema = BuildSchema::build($contents, $typeConfigDecorator); // $rawInput = file_get_contents('php://input'); $input = json_decode($query, true); $query = $input['query']; $variableValues = isset($input['variables']) ? $input['variables'] : null; try { // $rootValue = ['prefix' => 'You said: ']; $rootValue = [ 'usuario' => function($root, $args, $context, $info) { $usuario = new Usuario(); $usuario->setNome("aqui tem um teste"); $usuario->setEmail("aqui tem um email"); return $usuario; }, 'echo' => function($root, $args, $context, $info) { return"aqui tem um echooo"; }, 'adicionarUsuario' => function ($root, $args, $context, $info) { $usuario = new Usuario(); $usuario->setNome("aqui tem um teste"); $usuario->setEmail("aqui tem um email"); return $usuario; } ]; $result = GraphQL::executeQuery($schema, $query, $rootValue, null, $variableValues); if ($result->errors) { $output = [ 'errors' => [ [ 'message' => $result->errors ] ] ]; } else { $output = $result->toArray(); } } catch (\\Exception $e) { $output = [ 'errors' => [ [ 'message' => $e->getMessage() ] ] ]; } header('Content-Type: application/json'); echo json_encode($output); |