当前位置: 首页 > news >正文

PHPGraphQLAPI实现与最佳实践

PHP GraphQL API实现与最佳实践

GraphQL是一种API查询语言,让客户端可以精确地获取需要的数据,不多不少。PHP中有多个GraphQL实现库,今天说说如何在PHP中搭建GraphQL服务。

GraphQL的核心概念是Schema、Query和Mutation。Schema定义了可查询的数据类型和操作。

```php
require 'vendor/autoload.php';

use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Schema;
use GraphQL\GraphQL;

// 定义类型
$userType = new ObjectType([
'name' => 'User',
'fields' => [
'id' => Type::int(),
'name' => Type::string(),
'email' => Type::string(),
'age' => Type::int(),
'posts' => [
'type' => Type::listOf(fn() => $postType),
'resolve' => function ($user) {
return getPostsByUserId($user['id']);
},
],
],
]);

$postType = new ObjectType([
'name' => 'Post',
'fields' => [
'id' => Type::int(),
'title' => Type::string(),
'content' => Type::string(),
'author_id' => Type::int(),
'created_at' => Type::string(),
'author' => [
'type' => Type::listOf(fn() => $userType),
'resolve' => function ($post) {
return getUsers(['id' => $post['author_id']]);
},
],
],
]);

// 定义查询
$queryType = new ObjectType([
'name' => 'Query',
'fields' => [
'user' => [
'type' => $userType,
'args' => [
'id' => Type::nonNull(Type::int()),
],
'resolve' => function ($root, $args) {
$users = getUsers(['id' => $args['id']]);
return $users[0] ?? null;
},
],
'users' => [
'type' => Type::listOf($userType),
'resolve' => function () {
return getUsers();
},
],
'post' => [
'type' => $postType,
'args' => [
'id' => Type::nonNull(Type::int()),
],
'resolve' => function ($root, $args) {
$posts = getPosts(['id' => $args['id']]);
return $posts[0] ?? null;
},
],
'posts' => [
'type' => Type::listOf($postType),
'args' => [
'author_id' => Type::int(),
],
'resolve' => function ($root, $args) {
if (isset($args['author_id'])) {
return getPostsByUserId($args['author_id']);
}
return getPosts();
},
],
],
]);

// 定义变更
$mutationType = new ObjectType([
'name' => 'Mutation',
'fields' => [
'createUser' => [
'type' => $userType,
'args' => [
'name' => Type::nonNull(Type::string()),
'email' => Type::nonNull(Type::string()),
'age' => Type::int(),
],
'resolve' => function ($root, $args) {
return createUser($args['name'], $args['email'], $args['age'] ?? null);
},
],
'updateUser' => [
'type' => $userType,
'args' => [
'id' => Type::nonNull(Type::int()),
'name' => Type::string(),
'email' => Type::string(),
'age' => Type::int(),
],
'resolve' => function ($root, $args) {
return updateUser($args['id'], $args);
},
],
'deleteUser' => [
'type' => Type::boolean(),
'args' => [
'id' => Type::nonNull(Type::int()),
],
'resolve' => function ($root, $args) {
return deleteUser($args['id']);
},
],
],
]);

// 模拟数据源
function getUsers(array $filter = []): array
{
$users = [
['id' => 1, 'name' => '张三', 'email' => 'zhangsan@test.com', 'age' => 28],
['id' => 2, 'name' => '李四', 'email' => 'lisi@test.com', 'age' => 35],
['id' => 3, 'name' => '王五', 'email' => 'wangwu@test.com', 'age' => 22],
];

if (isset($filter['id'])) {
return array_filter($users, fn($u) => $u['id'] === $filter['id']);
}

return $users;
}

function getPosts(array $filter = []): array
{
return [
['id' => 1, 'title' => 'PHP入门', 'content' => '内容1', 'author_id' => 1, 'created_at' => '2024-01-01'],
['id' => 2, 'title' => 'GraphQL基础', 'content' => '内容2', 'author_id' => 1, 'created_at' => '2024-01-15'],
['id' => 3, 'title' => '高级PHP', 'content' => '内容3', 'author_id' => 2, 'created_at' => '2024-02-01'],
];
}

function getPostsByUserId(int $userId): array
{
return array_filter(getPosts(), fn($p) => $p['author_id'] === $userId);
}

function createUser(string $name, string $email, ?int $age): array
{
return ['id' => 4, 'name' => $name, 'email' => $email, 'age' => $age ?? 0];
}

function updateUser(int $id, array $data): array
{
$users = getUsers(['id' => $id]);
if (empty($users)) throw new Exception("用户不存在");
return array_merge($users[0], $data);
}

function deleteUser(int $id): bool
{
return true;
}

// 处理GraphQL请求
$schema = new Schema([
'query' => $queryType,
'mutation' => $mutationType,
]);

$rawInput = file_get_contents('php://input');
$input = json_decode($rawInput, true);
$query = $input['query'] ?? '';
$variables = $input['variables'] ?? null;

try {
$result = GraphQL::executeQuery($schema, $query, null, null, $variables);
$output = $result->toArray();
} catch (Exception $e) {
$output = ['errors' => [['message' => $e->getMessage()]]];
}

header('Content-Type: application/json');
echo json_encode($output);
?>
```

GraphQL的查询示例:

```graphql
// 查询示例
query {
user(id: 1) {
name
email
posts {
title
created_at
}
}
users {
name
age
}
}

// 变更示例
mutation {
createUser(name: "赵六", email: "zhao@test.com", age: 28) {
id
name
email
}
}
```

GraphQL相比REST API有几个优势。客户端精确控制返回字段,一次查询获取多个资源,强类型Schema提供自动文档。但GraphQL也有缺点,查询复杂度控制、缓存策略、文件上传等都比REST复杂。选择GraphQL还是REST取决于项目需求。

http://www.jsqmd.com/news/927097/

相关文章:

  • 机器学习驱动的数据清洗:从规则到智能的范式转变与实践指南
  • 《数据库原理》精要解读(八、九、十)—— 事务、恢复与并发:数据库内核的三大支柱
  • 区块链+物联网构建环境价值互联网:机器自主交易绿电与碳资产
  • 面试官最爱问的Python八股文,我用这18个知识点帮你一次性理清(附避坑指南)
  • AMD SEV实战:在KVM/QEMU上快速搭建你的第一个机密虚拟机(含密钥管理避坑指南)
  • 基于深度学习的yolov8仪器仪表识别 数字表压力表读数 温度计读数 电压表读数图像识别系统设计
  • 别再手动算时间差了!用Ant Design Vue的a-table组件,5分钟搞定表格日期列差值展示
  • 学生选课微信小程序全栈开发包(含SSM后台源码、MySQL建表脚本与部署说明)
  • 构建面向AI的现代数据湖:从架构原则到硬件选型实战
  • 基于打字模式的用户身份验证:从行为生物识别到AI驱动的持续安全防线
  • 用影子模式测试新版 Harness 逻辑
  • AI Agent Harness冷启动优化:快速响应方案
  • AI替代人类工作的三步走策略与真实案例分析
  • 医疗设备安规入门:一张图搞懂BF型设备的MOOP/MOPP绝缘路径(附GB 9706.1附录解析)
  • 从布尔表达式到可综合代码:一个全加器的Verilog RTL设计完整流程(附代码规范检查清单)
  • 从DDR到DDR5:Burst和Prefetch的演变如何决定了内存性能的飞跃
  • 【读书笔记】《架构即未来》精华解读
  • DIY土壤湿度传感器:从腐蚀铜板到Arduino读取的完整指南
  • AI驱动招聘自动化:四大核心场景与成本效益深度解析
  • 避坑指南:逆向同花顺问财hexin-v时,你可能遇到的3个环境检测与反调试问题
  • 保姆级教程:用Python和nuscenes-devkit从零玩转nuScenes自动驾驶数据集(附完整代码)
  • 别只当备份用!解锁PostgreSQL逻辑复制的5个高阶玩法:从CDC到微服务数据分发
  • 【分享】微恢复助手 照片快速恢复 安全不泄露超好用
  • 量子策略评估(QPE)原理与强化学习应用
  • 别再只用if了!用np.all()和np.any()让你的NumPy数据清洗效率翻倍
  • 保姆级避坑指南:Win11下搞定MATLAB 2022a、AMESim 2021与VS2019的联合仿真环境搭建
  • Nacos 2.x 本地联调踩坑记:解决 gRPC 端口偏移导致的 StatusRuntimeException
  • 从呼吸到电能:DIY口罩发电项目详解与能量收集技术实践
  • 【字节跳动】豆包全用户统一对话全量归档公共源码
  • 基于Arduino与步进/伺服电机的低成本物理开关自动化方案