当前位置: 首页 > 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.zskr.cn/news/1438429.html

相关文章:

  • 机器学习驱动的数据清洗:从规则到智能的范式转变与实践指南
  • 基于打字模式的用户身份验证:从行为生物识别到AI驱动的持续安全防线
  • 用影子模式测试新版 Harness 逻辑
  • AI替代人类工作的三步走策略与真实案例分析
  • 避坑指南:逆向同花顺问财hexin-v时,你可能遇到的3个环境检测与反调试问题
  • 【分享】微恢复助手 照片快速恢复 安全不泄露超好用
  • 保姆级避坑指南:Win11下搞定MATLAB 2022a、AMESim 2021与VS2019的联合仿真环境搭建
  • MVP原型开发工具选型:Codex、Cursor与Factory的实战对比与决策框架
  • STM32F103驱动4.3寸屏:用CubeMX配置FSMC接口的细节与参数解读(附工程)
  • 51单片机编程,为什么你的‘位操作’总出错?可能是没搞懂Keil C51里的sfr和sbit
  • Python实战:用pyrolite库批量分析土壤数据并可视化(从CSV到三角图)
  • 神经网络加速引力波数据分析:FLEX算法原理与应用
  • AI智能体规模化工程实践:七层蓝图解决服务、安全与可观测性挑战
  • 深入理解线程:从操作系统原理到Java并发编程实战
  • AI如何破解科学摘要简化难题:大语言模型与提示工程实践
  • 别只盯着引擎!从Unity转向Godot/Unreal,你的C#代码和资产管线如何平滑迁移?
  • Matlab双目标定翻车实录:从‘误差爆炸’到‘精度达标’,我踩过的5个坑
  • AI智能体如何通过搜索-执行模式安全管理云基础设施
  • 人机链协同:AI匹配与智能合约如何重塑去中心化工作平台
  • 告别MessageBox!用HandyControl的Growl为你的WPF应用做个优雅的通知中心
  • 用STM32F103的TIM3捕获PWM信号:从PA6引脚读取方波频率和占空比的保姆级教程
  • 集中式数据库管理范式为何失效?分布式数据架构的演进与实践
  • 从一次诡异的‘本地回环’访问告警说起:tcpdump抓包细节如何影响安全分析判断?
  • 从BLCR到CRIU:聊聊Linux进程热迁移工具的演进与选型心得
  • 保姆级教程:用Altium Designer从零画一块Type-C小板(附立创商城白嫖封装技巧)
  • 时间序列分析实战:从ARIMA到LightGBM的预测建模与异常检测
  • 从《欧卡2》Mod路径逆向,聊聊单机游戏资源加载的通用Hook思路
  • 新手必看!用泡沫胶和热熔胶枪搞定你的第一架固定翼无人机(附详细工具清单)
  • MAT内存泄漏排查实战:从JDK版本不匹配到支配树分析,一次搞定
  • GR4CIL:基于CLIP的类增量学习框架,解决灾难性遗忘与模态间隙难题