graphql - graphql-php 入门:如何将解析器函数从 .graphql 文件添加到模式?
问题描述
我对 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}}
}
这将按预期返回元数据。但当然现在我想查询实际的产品数据并从数据库中获取,为此我需要定义一个解析器函数。
http://webonyx.github.io/graphql-php/type-system/type-language/上的文档状态:“默认情况下,这样的模式是在没有任何解析器的情况下创建的。我们必须依赖默认字段解析器和根值为了对此模式执行查询。” - 但没有这样做的例子。
如何为每个类型/字段添加解析器函数?
解决方案
这种方法无需实例化服务器即可工作。在我的例子中,我已经有一个服务器并且可以读取 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;
}
}
推荐阅读
- stripe-payments - Flutter Web - Stripe 集成的对话框弹出窗口
- javascript - 如何在同一个php文件中的php代码之后运行javascript代码?
- reactjs - 是否可以定义一个 React 不受控制的功能组件(没有类)?
- python - 如何使 GluonTS / Apache mxnet 中的培训信息静音?
- database - 在将数据发送回用户之前,有什么方法可以聚合数据?
- css - css 函数 calc() 的用例
- python - 使用 python 和 HTML 从商店定位器中提取所有位置
- c++ - 在二维数组中查找最大和最小数字不起作用
- kubernetes - 为什么 fluentd/kube-proxy/prometheus 的 GKE 中的 IP 地址等于节点地址
- python - 如何更改语言或自定义模板“password_reset_confirm”