开始使用 graphql-php:如何从 .graphql 文件向模式添加解析器函数?
getting started in graphql-php: how to add resolver functions to schema from .graphql file?
我是 GraphQL 的新手,想尝试使用 graphql-php 来构建一个简单的 API 入门。我目前正在阅读文档并尝试示例,但我一开始就卡住了。
我希望将我的模式存储在 schema.graphql
文件中而不是手动构建它,所以我遵循了有关如何执行此操作的文档并且它确实有效:
<?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\nreturn " . 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);
这是我的 schema.graphql
文件的样子:
schema {
query: Query
}
type Query {
products: [Product!]!
}
type Product {
id: ID!,
type: ProductType
}
enum ProductType {
HDRI,
SEMISPHERICAL_HDRI,
SOUND
}
我可以用
查询它
query {
__schema {types{name}}
}
这将 return 预期的元数据。但是现在我当然想查询实际的产品数据并从数据库中获取,为此我需要定义一个解析器函数。
http://webonyx.github.io/graphql-php/type-system/type-language/ 的文档状态:"By default, such schema is created without any resolvers. We have to rely on default field resolver and root value in order to execute a query against this schema." - 但没有执行此操作的示例。
如何为每个 types/fields 添加解析器函数?
这是我最后做的...
$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()
);
},
然后在配置中
$config = ServerConfig::create()
->setSchema($schema)
->setRootValue($rootResolver)
->setContext($context)
->setDebug(DEBUG_MODE)
->setQueryBatching(true)
;
$server = new StandardServer($config);
这对我来说感觉相当 hack-ish,我可能应该将解析器外包到单独的文件中,但它有效......仍然感到困惑,因为没有简单的例子来完成这个任务,也许比我的解决方案...
这种方法无需实例化服务器即可工作。在我的例子中,我已经有一个服务器并且可以读取 HTTP 数据,我所需要的只是读取 GraphQL 模式和 运行 查询。首先,我从文件中读取模式:
$schemaContent = // file_get_contents or whatever works for you
$schemaDocument = GraphQL\Language\Parser::parse($schemaContent);
$schemaBuilder = new GraphQL\Utils\BuildSchema($schemaDocument);
$schema = $schemaBuilder->buildSchema();
然后我执行传递自定义字段解析器的查询:
$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
);
字段解析器如下所示:
private static function defaultFieldResolver(
$source,
$args,
$context,
\GraphQL\Type\Definition\ResolveInfo $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;
}
}
我为此使用根值:
<?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);
我是 GraphQL 的新手,想尝试使用 graphql-php 来构建一个简单的 API 入门。我目前正在阅读文档并尝试示例,但我一开始就卡住了。
我希望将我的模式存储在 schema.graphql
文件中而不是手动构建它,所以我遵循了有关如何执行此操作的文档并且它确实有效:
<?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\nreturn " . 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);
这是我的 schema.graphql
文件的样子:
schema {
query: Query
}
type Query {
products: [Product!]!
}
type Product {
id: ID!,
type: ProductType
}
enum ProductType {
HDRI,
SEMISPHERICAL_HDRI,
SOUND
}
我可以用
查询它query {
__schema {types{name}}
}
这将 return 预期的元数据。但是现在我当然想查询实际的产品数据并从数据库中获取,为此我需要定义一个解析器函数。
http://webonyx.github.io/graphql-php/type-system/type-language/ 的文档状态:"By default, such schema is created without any resolvers. We have to rely on default field resolver and root value in order to execute a query against this schema." - 但没有执行此操作的示例。
如何为每个 types/fields 添加解析器函数?
这是我最后做的...
$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()
);
},
然后在配置中
$config = ServerConfig::create()
->setSchema($schema)
->setRootValue($rootResolver)
->setContext($context)
->setDebug(DEBUG_MODE)
->setQueryBatching(true)
;
$server = new StandardServer($config);
这对我来说感觉相当 hack-ish,我可能应该将解析器外包到单独的文件中,但它有效......仍然感到困惑,因为没有简单的例子来完成这个任务,也许比我的解决方案...
这种方法无需实例化服务器即可工作。在我的例子中,我已经有一个服务器并且可以读取 HTTP 数据,我所需要的只是读取 GraphQL 模式和 运行 查询。首先,我从文件中读取模式:
$schemaContent = // file_get_contents or whatever works for you
$schemaDocument = GraphQL\Language\Parser::parse($schemaContent);
$schemaBuilder = new GraphQL\Utils\BuildSchema($schemaDocument);
$schema = $schemaBuilder->buildSchema();
然后我执行传递自定义字段解析器的查询:
$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
);
字段解析器如下所示:
private static function defaultFieldResolver(
$source,
$args,
$context,
\GraphQL\Type\Definition\ResolveInfo $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;
}
}
我为此使用根值:
<?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);