使用 GraphQL API
数据墙DBW 自动为每个实体生成 GraphQL 架构。所有请求通过 POST 发送到 /graphql 端点,查询内容写在请求体的 query 字段中。
端点与请求格式
POST http://localhost:5000/graphql
Content-Type: application/json
{
"query": "{ books { items { id title } } }"
}GraphQL 端点始终使用 POST,即使只是查询数据。变量可以分离到 variables 字段中。
查询列表
curl
curl -X POST http://localhost:5000/graphql \
-H "Content-Type: application/json" \
-d '{"query": "{ books { items { id title year pages } } }"}'JavaScript
const res = await fetch("http://localhost:5000/graphql", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: "{ books { items { id title year pages } } }"
}),
});
const data = await res.json();
console.log(data.data.books.items);Python
import requests
res = requests.post("http://localhost:5000/graphql",
json={"query": "{ books { items { id title year pages } } }"})
data = res.json()
for item in data["data"]["books"]["items"]:
print(item)响应格式
{
"data": {
"books": {
"items": [
{ "id": 1, "title": "示例图书", "year": 2023, "pages": 300 }
],
"hasNextPage": false,
"endCursor": null
}
}
}GraphQL 响应嵌套在 data.{实体名}.items 中。分页字段 hasNextPage 和 endCursor 始终出现。
按主键查询
{
book_by_pk(id: 1) {
id
title
year
}
}如果主键不存在,GraphQL 返回错误而不是空数据:
{
"errors": [
{
"message": "Could not find item with the given key.",
"path": ["book_by_pk"]
}
]
}使用变量
变量将查询结构与参数值分离,避免字符串拼接:
query GetBook($id: Int!) {
book_by_pk(id: $id) {
id
title
year
}
}{
"query": "query GetBook($id: Int!) { book_by_pk(id: $id) { id title } }",
"variables": { "id": 1 }
}JavaScript 示例
const query = `
query GetBook($id: Int!) {
book_by_pk(id: $id) { id title year }
}
`;
const res = await fetch("http://localhost:5000/graphql", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query, variables: { id: 1 } }),
});筛选与排序
GraphQL 使用 filter 和 orderBy 参数,语法与 REST 不同——使用对象嵌套而非 URL 查询字符串:
{
books(
filter: { year: { ge: 2000 }, pages: { gt: 300 } }
orderBy: { year: DESC, title: ASC }
) {
items { id title year pages }
}
}筛选运算符
eq 等于 { title: { eq: "Dune" } }
neq 不等于 { year: { neq: 2000 } }
gt 大于 { pages: { gt: 300 } }
gte 大于等于 { year: { gte: 2000 } }
lt 小于 { pages: { lt: 100 } }
lte 小于等于 { year: { lte: 2020 } }
contains 包含 { title: { contains: "Foundation" } }
isNull 为空 { deleted_at: { isNull: true } }逻辑组合:
{
books(
filter: {
or: [
{ year: { gt: 2000 } }
{ title: { contains: "Dune" } }
]
}
) { items { id title } }
}分页
{
books(first: 5) {
items { id title }
hasNextPage
endCursor
}
}翻到下一页:
{
books(first: 5, after: "eyJpZCI6NX0=") {
items { id title }
hasNextPage
endCursor
}
}创建记录
mutation {
createBook(item: { id: 100, title: "新书", year: 2024, pages: 280 }) {
id
title
year
}
}变量形式:
mutation CreateBook($item: CreateBookInput!) {
createBook(item: $item) { id title year }
}{
"variables": {
"item": { "id": 100, "title": "新书", "year": 2024, "pages": 280 }
}
}IMPORTANT
GraphQL 变更(mutation)需要数据库连接池启用多活动结果集。SQL Server 用户请确保连接字符串包含 MultipleActiveResultSets=True。连接池配置 Pooling=False 可能导致变更操作失败。
更新记录
mutation {
updateBook(id: 100, item: { title: "更新后的书名" }) {
id
title
}
}只传递需要更新的字段,未传递的字段保持原值。
删除记录
mutation {
deleteBook(id: 100) {
id
title
}
}链式变更
可以在一个请求中执行多个不同类型的变更操作:
mutation {
book1: createBook(item: { id: 101, title: "第一本" }) { id title }
book2: updateAuthor(id: 10, item: { lastName: "更新后的姓" }) { id lastName }
}多个变更按顺序执行,互不影响。需要使用别名(book1:、book2:)区分同名或不同类型的操作。
IMPORTANT
链式变更不支持事务——某个操作失败时已执行的操作不会回滚。客户端需要同时检查 data 和 errors 来确认每个操作的结果。
NOTE
批量创建(items: [...] 数组形式)需要额外配置 runtime.graphql.multiple-mutations.create.enabled: true,详见GraphQL 多重变更。链式变更(使用别名)不需要该配置。多重创建仅 SQL Server 支持。
错误处理
GraphQL 错误统一在 errors 数组中返回:
{
"data": null,
"errors": [
{
"message": "Could not find item with the given key.",
"path": ["book_by_pk"]
}
]
}部分成功时 data 和 errors 可能同时存在:
{
"data": { "book_by_pk": null },
"errors": [{ "message": "..." }]
}客户端需要同时检查 data 和 errors 来确认每个操作的结果。
错误处理(JavaScript)
const res = await fetch("http://localhost:5000/graphql", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query }),
});
const { data, errors } = await res.json();
if (errors?.length) console.error(errors[0].message);字段别名
在查询中可以为字段指定别名:
{
books {
items {
bookId: id
bookTitle: title
}
}
}响应中字段名将使用别名:
{ "bookId": 1, "bookTitle": "示例图书" }架构内省
GraphQL 端点默认支持内省,客户端可以自动发现所有可用的查询、变更和类型。使用支持 GraphQL 的客户端(Apollo Studio、Postman、Insomnia)连接 /graphql 即可浏览完整架构。
生产环境可通过 runtime.graphql.allow-introspection: false 关闭内省。
下一步
- GraphQL 关系查询 — 嵌套关联数据查询。
- GraphQL 聚合查询 — 服务端统计计算。
- 使用 REST API — REST 调用方式。
