使用Laravel和Lighthouse快速构建GraphQL服务器
首先
我们将使用Laravel的GraphQL框架”Lighthouse”构建GraphQL服务器。
另外,我们将使用Postman或Next.js的Apollo Client来实际执行查询请求来测试所构建的GraphQL服务器。
GraphQL是一种查询语言。
GraphQL是一种用于API的查询语言,用于执行查询并使用现有数据的运行时。
https://graphql.org/
根据公式的解释,GraphQL是一种用于API的查询语言。
通过向一个端点发送请求,GraphQL可以获取和更新数据。

画像来源:《Apollo Server 简介》
以下是特点,包括以下优点和缺点。
优点
-
- 型を指定できる
-
- RESTの問題点(オーバーフェッチ、アンダーフェッチ)を解消できる
必要な情報のみ取得できる
複数の情報を少ないリクエストで取得できる
缺点
-
- N+1問題が発生する
-
- HTTPキャッシュ方式をサポートしていない
- クエリが複雑化する
关于GraphQL的问题,您可以参考这篇文章。
环境
-
- PHP 8.2.0
-
- Laravel 9.43.0
-
- nuwave/lighthouse 5.68
-
- React 18.2.0
-
- Next.js 13.0.6
- Apollo Client 3.7.2
建立GraphQL服务器
安装Lighthouse
现在我们将按照官方文件的指引来构建GraphQL服务器。
首先,我们要安装包。
$ composer require nuwave/lighthouse
接下来,我们将创建一个架构定义文件。
$ php artisan vendor:publish --tag=lighthouse-schema
将在/graphql目录下创建schema.graphql文件。
您将在该文件中编写模式定义(默认情况下已定义了用户模式)。
scalar DateTime
@scalar(class: "Nuwave\\Lighthouse\\Schema\\Types\\Scalars\\DateTime")
type Query {
user(
id: ID @eq @rules(apply: ["prohibits:email", "required_without:email"])
email: String
@eq
@rules(apply: ["prohibits:id", "required_without:id", "email"])
): User @find
users(
name: String @where(operator: "like")
): [User!]! @paginate(defaultCount: 10)
}
type User {
id: ID!
name: String!
email: String!
email_verified_at: DateTime
created_at: DateTime!
updated_at: DateTime!
}
为了通过/graphql端点发送请求,需要进行cors设置。
return [
- 'paths' => ['api/*', 'sanctum/csrf-cookie'],
+ 'paths' => ['api/*', 'graphql', 'sanctum/csrf-cookie'],
...
创建测试数据
在工厂预先创建测试数据。
公共函数向上执行()
{
架构::创建(‘用户’, 函数 (蓝图 $表) {
$表->标识符();
$表->字符串(‘姓名’);
$表->字符串(‘电子邮件’)->唯一();
$表->时间戳(‘电子邮件验证时间’)->可为空();
$表->字符串(‘密码’);
$表->记住令牌();
$表->时间戳();
});
}
public function up()
{
Schema::create(‘posts’, function (Blueprint $table) {
$table->id();
$table->foreignIdFor(User::class)->constrained();
$table->text(‘contents’);
$table->timestamps();
});
}
public function definition()
{
return [
‘name’ => $this->faker->name(),
’email’ => $this->faker->unique()->safeEmail(),
’email_verified_at’ => now(),
‘password’ => ‘$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi’, // 密码
‘remember_token’ => Str::random(10),
];
}
公共函数定义()
{
返回 [
‘用户ID’ => 1,
‘内容’ => $this->faker->realText(32),
];
}
public function run()
{
User::factory(1)->create();
Post::factory(10)->create();
}
数据库种子文件(DatabaseSeeder.php)
数据库种子文件(DatabaseSeeder.php)
public function run()
{
User::factory(1)->create();
Post::factory(10)->create();
}
试着从邮递员那里发送查询。
那么我们来尝试向GraphQL的端点发送查询吧。

让我们也尝试从Next.js发送查询
我将使用Next.js搭建项目并安装Apollo Client。
$ npx create-next-app --ts
$ yarn add @apollo/client graphql
我将修改index.tsx文件,将获取到的数据打印到控制台上。
import { ApolloClient, InMemoryCache, gql } from '@apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:9004/graphql',
cache: new InMemoryCache(),
});
export default function Home() {
client
.query({
query: gql`
query GetUsers {
user(id: 1) {
name
email
}
}
`,
})
.then((result) => console.log(result));
...

获取相关数据部分同时进行整合
让我们一起获取已经设置好的相关数据。
首先,我们需要定义模型的相关关系。
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
将Post的定义添加到GraphQL模式中。
type User {
id: ID!
name: String!
email: String!
email_verified_at: DateTime
+ posts: [Post]
created_at: DateTime!
updated_at: DateTime!
}
+ type Post {
+ id: ID!
+ user_id: Int!
+ contents: String!
+ created_at: DateTime!
+ updated_at: DateTime!
+ }

执行Mutation(更新系的查询)
我将尝试在Mutation中添加一条记录。
首先,在GraphQL模式中添加Mutation的定义。
type Mutation {
createPost(
user_id: Int
contents: String
): Post
@create(model: Post)
}

这个帖子里已经插入了记录。
解决N+1问题
在开始部分,提到了GraphQL的缺点之一是”N+1问题”。
如果按照上述关联数据一起获取的方式去做,那么每个帖子都会发出查询请求。
通过在Lighthouse中使用@hasMany或@belongsTo,可以告诉它通过Eager loading来解决这个问题。
type User {
id: ID!
name: String!
email: String!
email_verified_at: DateTime
- posts: [Post]
+ posts: [Post] @hasMany
created_at: DateTime!
updated_at: DateTime!
}
总结
您还可以定义页面分页,使用本地作用域,并使用Eloquant进行各种功能的协作。请详细参阅官方文档。
最后
GoQSystem目前正在招募一起工作的伙伴!
如果你有兴趣,请通过以下链接进行确认。