如何让GraphQL始终返回特定类型的完整对象?(overblog/GraphQLBundle)
嘿,这个问题我之前也碰到过——像价格、GPS坐标这种本身就是一个完整逻辑单元的小对象,每次查询都要手动写全子字段确实挺麻烦的。好在overblog/GraphQLBundle有几种方案能解决这个需求:
方案1:自定义标量类型(最推荐)
把这类“原子性”对象包装成自定义标量,这样GraphQL就会把它们当作单个值处理,查询时不需要选子字段,直接返回完整结构。
步骤大概是这样:
- 创建标量类型类,实现
Overblog\GraphQLBundle\Definition\ScalarTypeInterface,处理对象和JSON的转换:
<?php namespace App\GraphQL\Scalar; use Overblog\GraphQLBundle\Definition\ScalarTypeInterface; use App\Entity\Price; use GraphQL\Language\AST\StringValueNode; class PriceScalarType implements ScalarTypeInterface { public function serialize($value) { if (!$value instanceof Price) { return null; } return [ 'amount' => $value->getAmount(), 'currency' => $value->getCurrency() ]; } public function parseValue($value) { // 处理客户端传入的参数(如果需要支持 mutation) if (is_array($value)) { $price = new Price(); $price->setAmount($value['amount']); $price->setCurrency($value['currency']); return $price; } return null; } public function parseLiteral($valueNode, array $variables = null) { // 处理 AST 节点解析(如果需要) if ($valueNode instanceof StringValueNode) { $data = json_decode($valueNode->value, true); return $this->parseValue($data); } return null; } public function getName() { return 'Price'; } }
- 在你的实体类中,把对应字段的类型指定为这个自定义标量:
// App\Entity\Foo.php /** * @GraphQLField(type="Price") */ private $price;
这样查询query { FooList { id price location } }时,price就会自动返回包含amount和currency的完整对象,不会再报错。
方案2:设置类型默认字段
如果不想自定义标量,也可以在类型定义时指定默认返回的字段,当查询时没有显式选择子字段,就自动返回这些默认字段。
在你的小对象类上添加defaultFields参数:
// App\Entity\Price.php /** * @GraphQLType(defaultFields={"amount", "currency"}) */ class Price { /** * @GraphQLField(type="Float") */ private $amount; /** * @GraphQLField(type="String") */ private $currency; // ... getter/setter }
配置后,当你只写price而不选子字段时,GraphQL会自动返回amount和currency两个字段的内容。这个方案的好处是,如果你偶尔需要只选部分字段,还是可以手动指定(比如price { amount }),灵活性更高。
方案3:自定义指令(进阶)
如果需要全局统一控制哪些类型要返回完整对象,可以自定义一个@fullObject指令,然后编写字段扩展来自动为带这个指令的类型添加所有子字段。不过这个方案相对复杂,适合有大量这类类型需要统一处理的场景,这里就不展开细说了。
总的来说,自定义标量适合那些完全不需要拆分的“值对象”,而默认字段则更灵活,能兼顾按需选择的场景,你可以根据自己的需求选合适的方案。
内容的提问来源于stack exchange,提问作者HubertNNN
相关产品推荐
相关产品推荐

