Wiki.js 2.5 API 使用详解

Wiki.js 2.5.315 GraphQL API 实战详解:JWT 与 API Key 双认证、登录与错误分支、pages/users/groups/system 各域读写实测、分页排序约定、限流与错误码体系,全部请求响应真实回显。

Wiki.jsWiki.jsNode.jsLinux2026/10/18

Wiki.js 2.5 API 使用详解

目标:以 GraphQL API 为核心,系统讲解 Wiki.js 2.5.315 的程序化调用方式——端点与认证体系(JWT / API Key)、登录与首次调用、页面/用户/组/系统各域 mutation 与 query 的请求格式与真实响应、错误码体系与限流约定,所有请求与响应 JSON 均在 Ubuntu 22.04 的 2.5.315 实例上 curl 实测采集,已在 Ubuntu 22.04 实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04 LTS(x86_64)
  • Wiki.js 版本:2.5.315(system.info 实查 currentVersion)
  • 数据库:PostgreSQL 16.15(dbVersion 实查)
  • API 端点:http://192.168.146.128:3101/graphql(Wiki.js 服务地址 + /graphql 路径)
  • 认证:本地(Local)策略管理员 administrator / admin@example.com / q1w2e3r4(实测演示账号)
  • 客户端工具:curl 7.81(系统自带);浏览器 GraphiQL 调试台(Wiki.js 内置,见 2.3)
  • 实例状态:已启用 API(管理后台 API 开关,开启方式见第八章实测)
  • 测试数据:中文页面 zh/home(欢迎页)、zh/getting-started(入门指南,标签「指南」)、英文页面 en/home(Welcome)

二、前置条件

2.1 端点

Wiki.js 全部管理与数据接口统一暴露在一个 GraphQL 端点:

POST http://<服务器IP>:<端口>/graphql
  • 请求头必须带 Content-Type: application/json,请求体为 {"query": "..."} 形式的 JSON。
  • 读操作(query)与写操作(mutation)都走同一端点,通过 query 语句中的 query/mutation 关键字区分。

2.2 开启 API 访问

Wiki.js 默认关闭 API。用 API Key 调用前必须先开启(管理员登录后:管理后台 → API(接口) 菜单 → 打开 API 开关)。未开启时实测响应:

{
    "data": {},
    "errors": [
        {
            "message": "API is disabled. You must enable it from the Administration Area first.",
            "path": []
        }
    ]
}

💡 说明:携带管理员 JWT 的会话调用不受该开关限制;该开关约束的是 API Key 方式的调用(第八章实测)。生产环境建议保持「后台开关关闭 + 临时需要时再开」的最小暴露面。

2.3 客户端工具

  • curl:本文全部实测使用 curl,命令可直接复制执行。
  • GraphiQL 调试台:浏览器打开 http://<服务器IP>:<端口>/graphql(GET 方式访问)即进入内置 GraphiQL 界面,左侧写查询、右侧出结果,自带 schema 自动补全与文档面板(DOCS),是探索全部类型定义的最快途径。
  • 命令行探索 schema:实例文件内含全部类型定义(server/graph/schemas/*.graphql),按域拆分(page/user/group/system 等),字段拼写存疑时直接检索该文件最准确。

三、API 总览

3.1 认证方式

方式获取传递适用
匿名(Guest)无无未认证请求自动以 Guest 身份执行,权限 = Guests 组
JWTmutation authentication.login 签发请求头 Authorization: Bearer <jwt>脚本/自动化,默认 30 分钟过期
API Keymutation authentication.createApiKey 创建请求头 Authorization: Bearer <key>长期集成,有效期可配(默认建议)

JWT 的有效期为 30 分钟(tokenExpiration: '30m',系统初始化默认值),过期需重新登录换取;API Key 按创建时传入的 expiration 生效(如 100Y 即近乎永久),撤销走 revokeApiKey。

3.2 响应结构约定

业务 mutation 的响应普遍嵌套 responseResult(ResponseStatus 类型):

字段类型含义
succeededBoolean业务是否成功
errorCodeInt0 为成功;失败为业务错误码
slugString错误标识(如 ok、AuthLoginFailed)
messageString人类可读消息

错误体系分三层,实测样例见各域小节:

层级判别特征示例
schema 校验错误errors[].extensions.code = GRAPHQL_VALIDATION_FAILED字段名拼错、必填参数缺失
权限错误errors[].message = "Forbidden"匿名调用需 manage:system 的 query
业务错误responseResult.succeeded = false + errorCode/slug密码错误 AuthLoginFailed(1002)

3.3 限流约定

写操作与认证操作带服务端速率限制(schema 声明):authentication.login 为每 60 秒 5 次(@rateLimit(limit: 5, duration: 60)),loginTFA、forgotPassword 同样受限。脚本批量调用时注意节流,超限返回 Too Many Requests 类错误。

四、认证与首次调用

4.1 登录获取 JWT

本地账号登录(用户名传邮箱或用户名,strategy 固定 local):

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' \
  -d '{"query":"mutation { authentication { login(username: \"admin@example.com\", password: \"q1w2e3r4\", strategy: \"local\") { responseResult { succeeded errorCode slug message } jwt mustChangePwd continuationToken } } }"}'

实测回显(JWT 为超长字符串,节选首尾):

{
    "data": {
        "authentication": {
            "login": {
                "responseResult": {
                    "succeeded": true,
                    "errorCode": 0,
                    "slug": "ok",
                    "message": "Login success"
                },
                "jwt": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZW1haWwiOiJhZG1pbkBleGFtcGxlLmNvbSIsIm5hbWUiOiJBZG1pbmlzdHJhdG9yIiwiYXYiOm51bGwsInR6IjoiQW1lcmljYS9OZXdfWW9yayIsImxjIjoiZW4iLCJkZiI6IiIsImFwIjoiIiwicGVybWlzc2lvbnMiOlsibWFuYWdlOnN5c3RlbSJdLCJncm91cHMiOlsxXSwiaWF0IjoxNzkyMzEwMDYxLCJleHAiOjE3OTIzMTE4NjEsImF1ZCI6InVybjp3aWtpLmpzIiwiaXNzIjoidXJuOndpa2kuanMifQ.hfTlvPqRpOftbDJubrCBX6cGmm61nv96qO8gxjHVufI2dMYJGugGEzmewQZke9ctWcmlzZzRRKoIYv4EQDeAuaJaPC8TSEMg4w2HGd9edNG3OZQI8nq90dJ0MIkjlFtia_J241EuumIs4CvdQfrSwVctdcUlUcP6MNq6zS8ZNshdaXuUQbjkaCyvA1ssZS7rkWzG3ubyKQLhKxGvWWa1uFz-QA3sVU_e7QlmlopKLuRgGljIj7ur3RYudi6v4a6GpQ83VxexkOvTC34y7202COeRI7Yequ79gKou39TfOHzfqgvY3eJQ_zaaKiA_c-HE2LwZ0RvzhCZrJ1MQ",
                "mustChangePwd": null,
                "continuationToken": null
            }
        }
    }
}

关键解读:JWT 为 RS256 签名令牌(实测长度约 700 字符),其 payload 部分解码可见用户身份与权限(id、email、name、permissions: ["manage:system"]、groups: [1]、iat/exp 时间戳);mustChangePwd 非 null 时表示管理员要求强制改密,需走 loginChangePassword 流程。

之后所有需要认证的调用把 JWT 放进请求头:

JWT="<上一步返回的jwt>"
curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $JWT" -d '{"query":"..."}'

4.2 错误密码(业务错误分支实测)

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' \
  -d '{"query":"mutation { authentication { login(username: \"admin@example.com\", password: \"wrong-pass\", strategy: \"local\") { responseResult { succeeded errorCode slug message } jwt } } }"}'

实测回显:

{
    "data": {
        "authentication": {
            "login": {
                "responseResult": {
                    "succeeded": false,
                    "errorCode": 1002,
                    "slug": "AuthLoginFailed",
                    "message": "Invalid email / username or password."
                },
                "jwt": null
            }
        }
    }
}

关键解读:注意 HTTP 状态仍是 200,判断成败要看 responseResult.succeeded 与 slug(AuthLoginFailed/1002),不能依赖 HTTP 层状态码。

4.3 字段拼错(schema 校验错误分支实测)

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' \
  -d '{"query":"mutation { authentication { login(username: \"admin@example.com\", password: \"q1w2e3r4\", strategy: \"local\") { responseResult { succeeded } jwt mustChangePassword } } }"}'

实测回显(节选):

{
    "errors": [
        {
            "message": "Cannot query field \"mustChangePassword\" on type \"AuthenticationLoginResponse\". Did you mean \"mustChangePwd\"?",
            "locations": [{ "line": 1, "column": 165 }],
            "extensions": { "code": "GRAPHQL_VALIDATION_FAILED", ... }
        }
    ]
}

关键解读:GraphQL 的友好之处是错误消息直接给出「Did you mean」提示,照提示修正字段名即可;extensions.code 统一为 GRAPHQL_VALIDATION_FAILED。

五、页面域 API(pages)

页面是 Wiki.js 的核心对象,读(PageQuery)写(PageMutation)覆盖全生命周期。以下全部实测。

5.1 查询页面列表(pages.list)

JWT=$(cat /tmp/jwt.txt); curl -s -X POST http://localhost:3101/graphql \
  -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT" \
  -d '{"query":"query { pages { list { id path title locale isPublished updatedAt } } }"}'

实测回显:

{
    "data": {
        "pages": {
            "list": [
                {
                    "id": 2,
                    "path": "home",
                    "title": "欢迎页(中文示例)",
                    "locale": "zh",
                    "isPublished": true,
                    "updatedAt": "2026-10-18T07:56:06.217Z"
                }
            ]
        }
    }
}

💡 说明:不带 Authorization 头调用同一 query 不会报错,而是以 Guest 身份返回「Guest 组有权看到的页面」(Guests 默认有 read:pages)——本实例初期无页面时实测返回 {"data":{"pages":{"list":[]}}}。需要管理权限的 query(如 users.list)匿名调用则直接 Forbidden(见 4.x 错误体系)。

5.2 查询单页(pages.single)与页面树(pages.tree)

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT" \
  -d '{"query":"query { pages { single(id: 2) { id path title description updatedAt } } }"}'

实测回显:

{
    "data": {
        "pages": {
            "single": {
                "id": 2,
                "path": "home",
                "title": "欢迎页(中文示例)",
                "description": "GraphQL API 创建的示例页面(已更新)",
                "updatedAt": "2026-10-18T07:56:58.863Z"
            }
        }
    }
}

页面树(含层级深度):

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT" \
  -d '{"query":"query { pages { tree(locale: \"zh\", path: \"\", mode: ALL) { id path title locale depth } } }"}'

实测回显:

{
    "data": {
        "pages": {
            "tree": [
                { "id": 2, "path": "getting-started", "title": "入门指南", "locale": "zh", "depth": 1 },
                { "id": 3, "path": "home", "title": "欢迎页(中文示例)", "locale": "zh", "depth": 1 }
            ]
        }
    }
}

5.3 创建页面(pages.create)

创建中文页面(tags 为必填参数,空标签传 []):

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT" \
  -d '{"query":"mutation { pages { create(content: \"# 欢迎使用 Wiki.js\\n\\n这是通过 GraphQL API 创建的第一篇中文页面。\", description: \"GraphQL API 创建的示例页面\", editor: \"markdown\", isPublished: true, isPrivate: false, locale: \"zh\", path: \"home\", title: \"欢迎页(中文示例)\", tags: []) { responseResult { succeeded errorCode slug message } page { id path title locale updatedAt } } } }"}'

实测回显(响应节选,含已知瑕疵):

{
    "errors": [
        {
            "message": "Cannot return null for non-nullable field Page.locale.",
            "path": ["pages", "create", "page", "locale"],
            "extensions": { "code": "INTERNAL_SERVER_ERROR", ... }
        }
    ],
    "data": {
        "pages": {
            "create": {
                "responseResult": {
                    "succeeded": true,
                    "errorCode": 0,
                    "slug": "ok",
                    "message": "Page created successfully."
                },
                "page": null
            }
        }
    }
}

关键解读:页面实际已创建成功(succeeded: true,用 pages.list 复查可见),仅响应体回填的 page 对象在 2.5.315 下缺 locale 字段序列化而报错——写脚本时以 responseResult 为准,page 字段不可依赖。

⚠️ 注意:locale: "zh" 要求中文语言包已安装,否则报外键错误 ForeignKeyViolationError(详见第十章 FAQ Q1)。

校验错误实测:漏传必填的 tags 时(实测回显,节选):

{
    "errors": [
        {
            "message": "Field \"create\" argument \"tags\" of type \"[String]!\" is required, but it was not provided.",
            "extensions": { "code": "GRAPHQL_VALIDATION_FAILED", ... }
        }
    ]
}

权限错误实测:不带任何认证头匿名调用 pages.create(实测回显,节选):

{"errors":[{"message":"Forbidden","path":["pages","create"],"extensions":{"code":"INTERNAL_SERVER_ERROR","exception":{"stacktrace":["Error: Forbidden","    at field.resolve (/wiki/server/graph/directives/auth.js:47:17)",...]}}}]}

5.4 更新页面(pages.update)

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT" \
  -d '{"query":"mutation { pages { update(id: 2, content: \"# 欢迎使用 Wiki.js\\n\\n## 更新说明\\n\\n本段为 pages.update 追加的内容。\", description: \"GraphQL API 创建的示例页面(已更新)\", editor: \"markdown\", isPublished: true, isPrivate: false, locale: \"zh\", path: \"home\", title: \"欢迎页(中文示例)\", tags: []) { responseResult { succeeded errorCode slug message } page { id updatedAt } } } }"}'

实测回显:

{
    "data": {
        "pages": {
            "update": {
                "responseResult": {
                    "succeeded": true,
                    "errorCode": 0,
                    "slug": "ok",
                    "message": "Page has been updated."
                },
                "page": { "id": 2, "updatedAt": "2026-10-18T07:56:58.863Z" }
            }
        }
    }
}

5.5 版本历史(pages.history)

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT" \
  -d '{"query":"query { pages { history(id: 2) { trail { versionId versionDate authorName actionType } total } } }"}'

实测回显:

{
    "data": {
        "pages": {
            "history": {
                "trail": [
                    {
                        "versionId": 1,
                        "versionDate": "2026-10-18T07:56:06.217Z",
                        "authorName": "Administrator",
                        "actionType": "initial"
                    }
                ],
                "total": 1
            }
        }
    }
}

关键解读:trail 为版本轨迹(新→旧),actionType 取值 initial(创建)/edit/move 等;配合 pages.version(pageId, versionId) 可取任意版本全文。该 query 需要 manage:system 或 read:history 权限。

5.6 站内搜索(pages.search)与标签检索(pages.searchTags)

中文关键词搜索:

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT" \
  -d '{"query":"query { pages { search(query: \"入门\") { results { id title path locale } suggestions totalHits } } }"}'

实测回显:

{
    "data": {
        "pages": {
            "search": {
                "results": [
                    { "id": "4", "title": "入门指南", "path": "getting-started", "locale": "zh" }
                ],
                "suggestions": [],
                "totalHits": 1
            }
        }
    }
}

标签模糊检索(创建 zh/getting-started 时打了标签「指南」):

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT" \
  -d '{"query":"query { pages { searchTags(query: \"指\") } }"}'

实测回显:

{
    "data": {
        "pages": {
            "searchTags": ["指南"]
        }
    }
}

六、用户与组域 API(users / groups)

6.1 用户列表(users.list)

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT" \
  -d '{"query":"query { users { list { id name email providerKey } } }"}'

实测回显:

{
    "data": {
        "users": {
            "list": [
                { "id": 2, "name": "Guest", "email": "guest@example.com", "providerKey": "local" },
                { "id": 1, "name": "Administrator", "email": "admin@example.com", "providerKey": "local" }
            ]
        }
    }
}

权限错误实测(同一 query 不带认证头,回显节选):

{
    "errors": [
        { "message": "Forbidden", "path": ["users", "list"], "extensions": { "code": "INTERNAL_SERVER_ERROR", ... } }
    ]
}

💡 说明:users.list 属管理操作,需 manage:system 或 read:users 权限;字段选择注意 UserMinimal 类型只有 id/name/email/providerKey 等精简字段,误选 providerName 会得到 Did you mean "providerKey"? 的校验错误(实测)。

6.2 组列表与权限详情(groups.list / groups.single)

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT" \
  -d '{"query":"query { groups { list { id name userCount isSystem } } }"}'

实测回显:

{
    "data": {
        "groups": {
            "list": [
                { "id": 1, "name": "Administrators", "userCount": 1, "isSystem": true },
                { "id": 2, "name": "Guests", "userCount": 1, "isSystem": true }
            ]
        }
    }
}

单组详情(含权限位与页面规则,实测回显):

{
    "data": {
        "groups": {
            "single": {
                "id": 1,
                "name": "Administrators",
                "permissions": ["manage:system"],
                "pageRules": []
            }
        }
    }
}

💡 说明:groups.list 返回的是 GroupMinimal 精简类型(无 permissions 字段);要拿权限必须走 groups.single(id)。写操作 groups.update 可直接改权限位与页面规则,是实现「脚本化权限管理」的入口。

七、系统与本地化域 API(system / localization)

7.1 系统信息(system.info)

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT" \
  -d '{"query":"query { system { info { dbType dbVersion latestVersion nodeVersion platform currentVersion } } }"}'

实测回显:

{
    "data": {
        "system": {
            "info": {
                "dbType": "PostgreSQL",
                "dbVersion": "16.15",
                "latestVersion": "2.5.316",
                "nodeVersion": "24.21.0",
                "platform": "docker",
                "currentVersion": "2.5.315"
            }
        }
    }
}

关键解读:currentVersion 与 latestVersion 对比即升级检查;巡检脚本可直接解析该 JSON。

7.2 安装语言包(localization.downloadLocale)

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT" \
  -d '{"query":"mutation { localization { downloadLocale(locale: \"zh\") { responseResult { succeeded errorCode slug message } } } }"}'

实测回显:

{
    "data": {
        "localization": {
            "downloadLocale": {
                "responseResult": {
                    "succeeded": true,
                    "errorCode": 0,
                    "slug": "ok",
                    "message": "Locale downloaded successfully"
                }
            }
        }
    }
}

该 mutation 需 manage:system 权限;成功后即可创建该语种页面(对照实测:安装前创建 zh 页面报 pages_localecode_foreign 外键错误,安装后成功)。

八、API Key 长期鉴权

JWT 30 分钟即过期,长期集成(CI/CD、巡检脚本、第三方系统对接)应使用 API Key。完整链路实测如下。

8.1 创建 API Key

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT" \
  -d '{"query":"mutation { authentication { createApiKey(name: \"docs-api-key\", expiration: \"100Y\", fullAccess: true, group: 1) { responseResult { succeeded errorCode slug message } key } } }"}'

实测回显(key 节选首尾):

{
    "data": {
        "authentication": {
            "createApiKey": {
                "responseResult": {
                    "succeeded": true,
                    "errorCode": 0,
                    "slug": "ok",
                    "message": "API Key created successfully"
                },
                "key": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcGkiOjEsImdycCI6MSwiaWF0IjoxNzkyMzEwMzkxLCJleHAiOjQ5NDgwNzAzOTEsImF1ZCI6InVybjp3aWtpLmpzIiwiaXNzIjoidXJuOndpa2kuanMifQ.G1vNHhtct4Ug1XAaPvDZ8FcsDp6EbJsKiU_hau70ThkcweEwyffOyV1ePuPIh74FcevkDY_oi42JZuZ6IxrNgonZaZrNTK_wd5KplvjsLZDX9CQJWiwpfUIZIJYEwUJyUVNPTB2CDsFWP9lEDOA95l7bRl98U239qFqYbiD1YERNjE8EGTPu8AGvwKblm7f1PREF-0y707c1PPCmWivyamE0uQ95JSTL59qey5VG73iIG_0nq2jThupM6X6CVPQsEKI6f0rK-rXUkomnuzX9FZKyvErROoaIsEfAsabdjHxKBYpBba5AvhZgKMLrMVcxZwzdAa9eB_zwgzjMXuROkA"
            }
        }
    }
}

参数说明:

参数说明
nameKey 名称(管理后台可见)
expiration有效期(30d/12M/100Y 等时长格式)
fullAccesstrue 时继承所绑定组的全部权限
group绑定组 ID(权限边界即该组的权限位 + 页面规则)

⚠️ 注意:key 响应字段是标量字符串(AuthenticationCreateApiKeyResponse.key: String),写成 key { id name } 会报 Field "key" must not have a selection... 校验错误(实测踩坑)。key 值仅此一次展示,务必立即保存;遗失只能 revoke 后重建。

8.2 用 API Key 调用(需先开启 API 开关)

AK="<createApiKey 返回的 key>"
curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $AK" \
  -d '{"query":"query { users { list { id name email } } }"}'

未在管理后台开启 API 时的实测回显:

{
    "data": {},
    "errors": [
        { "message": "API is disabled. You must enable it from the Administration Area first.", "path": [] }
    ]
}

开启 API 开关(管理员 JWT 调用;等价于管理后台 API 页的开关,实测回显):

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT" \
  -d '{"query":"mutation { authentication { setApiState(enabled: true) { responseResult { succeeded message } } } }"}'
{
    "data": {
        "authentication": {
            "setApiState": {
                "responseResult": { "succeeded": true, "message": "API State changed successfully" }
            }
        }
    }
}

再次用同一 API Key 调用(实测回显):

{
    "data": {
        "users": {
            "list": [
                { "id": 2, "name": "Guest", "email": "guest@example.com" },
                { "id": 1, "name": "Administrator", "email": "admin@example.com" }
            ]
        }
    }
}

8.3 撤销与轮换

撤销走 authentication.revokeApiKey(id)(需 Key 的数字 ID,可用 authentication { apiKeys { id name isRevoked } } 查询获得)。轮换节奏建议:季度级轮换、人员离职即撤销、Key 命名带用途与日期(如 ci-docs-2026Q4)便于审计。

九、分页/过滤/排序通用约定

pages.list 是分页参数最全的 query,其约定可推广到多数列表型接口:

curl -s -X POST http://localhost:3101/graphql -H 'Content-Type: application/json' -H "Authorization: Bearer $JWT" \
  -d '{"query":"query { pages { list(limit: 2, orderBy: UPDATED, orderByDirection: DESC, locale: \"zh\") { id path title updatedAt } } }"}'

实测回显:

{
    "data": {
        "pages": {
            "list": [
                { "id": 2, "path": "home", "title": "欢迎页(中文示例)", "updatedAt": "2026-10-18T07:56:58.863Z" },
                { "id": 4, "path": "getting-started", "title": "入门指南", "updatedAt": "2026-10-18T07:56:41.338Z" }
            ]
        }
    }
}

标签过滤(实测回显,命中打了「指南」标签的页面):

{
    "data": {
        "pages": {
            "list": [
                { "id": 4, "path": "getting-started", "title": "入门指南" }
            ]
        }
    }
}

通用约定要点:

  • limit:返回条数上限;orderBy:排序键(如 UPDATED/TITLE/ID,枚举型);orderByDirection:ASC/DESC。
  • locale:按语种过滤(注意参数名是 locale,写 localeCode 会报 Unknown argument,实测踩坑);tags: [String!]:按标签精确过滤。
  • 无偏移游标体系:大数据量翻页用 history 类接口的 offsetPage/offsetSize 分页参数,pages.list 以 orderBy + limit 组合近似实现。

十、常见问题(FAQ)

Q1:创建页面报 ForeignKeyViolationError ... pages_localecode_foreign?

  • 实测现象:locale: "zh" 创建页面时返回 succeeded: false, slug: "ForeignKeyViolationError"。
  • 定位:页面表的 localeCode 外键指向语言包表,zh 未安装则插入被拒。
  • 解决:先 localization { downloadLocale(locale: "zh") }(或管理后台 Locale 页下载)再创建。

Q2:带着 JWT 调用还是 Forbidden?

  • ① JWT 过期(30 分钟,重登录即可);② 该 query/mutation 要求的权限超出账号所在组的权限位(如 users.list 需 manage:system 或 read:users);③ 页面类操作还受页面规则(Page Rules)约束——权限位过了、规则没放行同样 Forbidden。逐项比对 groups.single 返回的 permissions 与目标操作的 @auth(requires: [...]) 要求。

Q3:API Key 报 API is disabled?

  • 管理后台 API 开关未开启(GraphQL 等价操作 authentication.setApiState(enabled: true),见第八章实测)。开启后无需重启,立即生效。

Q4:登录接口频繁返回限流错误?

  • login 限流为 60 秒 5 次(schema 声明 @rateLimit(limit: 5, duration: 60))。脚本重试务必加退避间隔;集成场景改用 API Key(不受该限流约束)。

Q5:createApiKey 的 key 响应字段选了子字段报错?

  • key 是标量 String,直接 key 平取,不能 key { id name }(实测报 Field "key" must not have a selection since type "String" has no subfields)。

Q6:分页参数 localeCode 报 Unknown argument?

  • pages.list 的语种过滤参数名为 locale(错误消息会提示 Did you mean "locale"?)。各接口参数名以 GraphiQL 文档面板为准,勿凭直觉拼写。

十一、参考链接

  1. Wiki.js 官方 GraphQL 文档(Dev → API):https://docs.requarks.io/dev/api
  2. GraphQL 官网(查询语言规范):https://graphql.org/learn/
  3. schema 定义源码(v2.5.315,server/graph/schemas/):https://github.com/requarks/wiki/tree/v2.5.315/server/graph/schemas
  4. 本专栏相关篇目:《Wiki.js 2.5 介绍与选型指南》、《Wiki.js Docker Compose 部署指南》、《Wiki.js 2.5 配置参数详解》