Seaography 2.0:强大且可扩展的 GraphQL 框架 🧭
Source: Dev.to
什么是 Seaography
Seaography 是一个基于 SeaORM 构建的 GraphQL 框架,能够自动生成带有 DataLoader 集成的解析器,以解决 N+1 问题。它提供了丰富的自定义选项、轻松添加自定义端点以及细粒度的授权(RBAC、hooks/guards)。
一个简短的演示展示了如何:
- 从已有数据库生成 SeaORM 实体(例如 Sakila SQLite 示例)
- 启动一个 GraphQL 服务器(兼容 Axum、Actix、Poem)
- 通过 GraphQL Playground 运行查询
您可以在 quick‑start guide 中遵循相同的步骤。
支持哪些类型的查询?
过滤、排序和分页
{
film(
filters: {
title: "{ contains: \"sea\" } # ⬅ like '%sea%'"
and: [{ releaseYear: { gt: "2000" } }, { length: { gt: 120 } }]
}
orderBy: { filmId: ASC }
pagination: { page: { page: 0, limit: 10 } }
# cursor‑based pagination is also supported:
# pagination: { cursor: { limit: 10, cursor: "Int[3]:100" } }
) {
nodes {
filmId
title
description
}
paginationInfo {
pages
current
}
}
}
嵌套关联查询
{
film(
# filter by related entity
having: {
actor: { firstName: { eq: "David" } }
category: { name: { eq: "Documentary" } }
}
) {
nodes {
filmId
title
actor {
nodes {
firstName
lastName
}
}
inventory {
nodes {
store {
address {
address
city {
city
}
}
}
}
}
}
}
}
使用的连接路径
film -> film_actor -> actor
-> inventory -> store -> address -> city
DataLoader 高效地解析这些关联,消除 N+1 问题。
变更:创建、更新、删除
完整的 CRUD 已支持(CreateOne、CreateBatch、Update、Delete)。
mutation {
filmTextCreateBatch(
data: [
{ filmId: 1, title: "\"Foo bar\"", description: "\"Lorem ipsum dolor sit amet\"" }
{ filmId: 2, title: "\"Fizz buzz\"", description: "\"Consectetur adipiscing elit\"" }
]
) {
filmId
title
description
}
}
自定义查询
Seaography 2.0 引入了宏,使您能够编写自定义查询端点,同时复用框架的分页和连接工具。
带分页的自定义查询
假设有一个从 Sakila 模式生成的 Customer 实体:
//! Entity from the sakila schema, generated by sea-orm-cli
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "customer")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub customer_id: i32,
pub store_id: i32,
pub first_name: String,
pub last_name: String,
// …
}
创建一个自定义端点,返回当前请求所属店铺的客户:
use seaography::{apply_pagination, Connection, CustomFields, PaginationInput};
pub struct Operations;
#[CustomFields]
impl Operations {
async fn customer_of_current_store(
ctx: &Context,
pagination: PaginationInput,
) -> async_graphql::Result> {
let db = ctx.data::()?;
let session = ctx.data::()?;
let query = customer::Entity::find()
.filter(customer::Column::StoreId.eq(session.store_id));
// Seaography handles pagination and execution
let connection = apply_pagination(&CONTEXT, db, query, pagination).await?;
Ok(connection)
}
}
该端点暴露为:
customer_of_current_store(
pagination: PaginationInput
): CustomerConnection!
示例查询
{
customer_of_current_store(pagination: { page: { page: 0, limit: 10 } }) {
nodes {
storeId
customerId
firstName
lastName
email
}
paginationInfo {
pages
current
}
}
}
只需几行代码,您即可添加一个完整功能、支持分页的 API 端点;繁重的工作由 Seaography + SeaORM 完成。
它是如何工作的?
- 桥接 – Seaography 将 SeaORM 类型映射到 Async‑GraphQL,使任何 SeaORM 实体都可以作为 GraphQL 输出。
- 模式生成 – 在应用启动时,Seaography 将 SeaORM 实体的元信息即时转换为 GraphQL 模式。
- 请求生命周期
- Async‑GraphQL 解析传入的 HTTP 请求并构建请求上下文。
- 您的 HTTP 处理器拦截请求,将上下文(例如数据库连接、会话)提供给 Seaography。
- 解析器(生成的或自定义的)通过 SeaORM 执行查询,可选地使用 DataLoader 高效加载关联。
- 在返回最终响应之前,自动应用分页、过滤、排序和授权钩子。