mcpField
F
frappe-core-api

frappe-core-api

github.com/impertio-studio开发198124 次安装30 周前更新
代码仓库

关于 frappe-core-api

面向 Frappe 开发者的 REST、RPC 与 Webhook 集成模式指南,涉及 API 认证、文档 CRUD、自定义方法和事件通知。内容还覆盖版本差异、分页、权限检查及签名验证等安全实践。

主要功能

  1. 01REST 文档 CRUD 与版本端点
  2. 02Token、OAuth 2.0 和会话认证
  3. 03RPC 自定义方法调用
  4. 04Webhook 事件与签名验证
  5. 05分页、权限及输入校验指引

适用场景

  1. 01从外部客户端读写 Frappe 文档
  2. 02为集成配置 API 认证
  3. 03通过 RPC 调用自定义服务端逻辑
  4. 04接收并验证文档变更 Webhook

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/impertio-studio/frappe_claude_skill_package --skill frappe-core-api

安装后在 Claude Code 中输入/frappe-core-api确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
anti-patterns.md
authentication-methods.md
examples.md
rest-api-reference.md
rpc-api-reference.md
webhooks-reference.md

详细介绍

Frappe API 模式

用于与 Frappe 集成的 REST、RPC 和 Webhook 确定性模式。


决策树

What do you need?
├── CRUD on documents (external client)
│   ├── v14: REST /api/resource/{doctype}
│   └── v15+: REST /api/v2/document/{doctype} (new) or /api/resource/ (still works)
│
├── Call custom server logic (external client)
│   └── RPC: POST /api/method/{dotted.path.to.function}
│
├── Notify external systems on document events
│   └── Webhooks (configured in UI or via DocType)
│
├── Client-side calls (JavaScript in Frappe desk)
│   ├── frappe.xcall() — async/await (RECOMMENDED)
│   └── frappe.call() — callback/promise pattern
│
└── Authentication method?
    ├── Server-to-server integration → Token Auth (RECOMMENDED)
    ├── Third-party app / mobile → OAuth 2.0
    ├── Browser session (short-lived) → Session/Cookie Auth
    └── Quick scripting / testing → Token Auth

身份验证方法

Token 身份验证(集成推荐使用)
headers = {
    'Authorization': 'token api_key:api_secret',
    'Accept': 'application/json',
    'Content-Type': 'application/json'
}

生成密钥:User > Settings > API Access > Generate Keys。务必立即保存 API secret——它只会显示一次。

Basic 身份验证(另一种 Token 格式)
import base64
credentials = base64.b64encode(b'api_key:api_secret').decode()
headers = {'Authorization': f'Basic {credentials}'}
OAuth 2.0(第三方应用)
# Step 1: Authorization redirect
GET /api/method/frappe.integrations.oauth2.authorize
    ?client_id={id}&response_type=code&scope=openid all
    &redirect_uri={uri}&state={random}

# Step 2: Exchange code for token
POST /api/method/frappe.integrations.oauth2.get_token
    grant_type=authorization_code&code={code}
    &redirect_uri={uri}&client_id={id}

# Step 3: Use bearer token
Authorization: Bearer {access_token}

# Refresh token
POST /api/method/frappe.integrations.oauth2.get_token
    grant_type=refresh_token&refresh_token={token}&client_id={id}
会话/Cookie 身份验证
session = requests.Session()
session.post(url + '/api/method/login', json={'usr': 'email', 'pwd': 'pass'})
# Subsequent requests use session cookie automatically

会话 Cookie 会在约 3 天后过期。切勿用于长时间运行的集成。


REST API:资源 CRUD

端点
操作方法v14 端点v15+ v2 端点
列出GET/api/resource/{doctype}/api/v2/document/{doctype}
创建POST/api/resource/{doctype}/api/v2/document/{doctype}
读取GET/api/resource/{doctype}/{name}/api/v2/document/{doctype}/{name}
更新PUT/api/resource/{doctype}/{name}PATCH /api/v2/document/{doctype}/{name}
删除DELETE/api/resource/{doctype}/{name}DELETE /api/v2/document/{doctype}/{name}
复制——GET /api/v2/document/{doctype}/{name}/copy [v15+]
文档方法——POST /api/v2/document/{doctype}/{name}/method/{method} [v15+]

务必包含 Accept: application/json 标头——否则 Frappe 可能会返回 HTML。

列表参数
参数类型描述默认值
fieldsJSON 数组要返回的字段["name"]
filtersJSON 数组AND 条件无
or_filtersJSON 数组OR 条件无
order_bystring排序表达式modified desc
limit_startint分页偏移量0
limit_page_lengthint页面大小20
limitintlimit_page_length 的别名 [v15+]—
debugbool在响应中显示 SQLfalse
筛选运算符
filters = [["status", "=", "Open"]]
filters = [["amount", ">", 1000]]
filters = [["status", "in", ["Open", "Pending"]]]
filters = [["date", "between", ["2024-01-01", "2024-12-31"]]]
filters = [["reference", "is", "set"]]       # NOT NULL
filters = [["reference", "is", "not set"]]   # IS NULL
filters = [["name", "like", "%INV%"]]
filters = [["status", "not in", ["Cancelled"]]]

完整运算符列表:=、!=、>、<、>=、<=、like、not like、in、not in、is、between。

分页模式
import json, requests

def get_all_records(doctype, headers, base_url, page_size=100):
    all_data, offset = [], 0
    while True:
        params = {
            'fields': json.dumps(["name", "modified"]),
            'limit_start': offset,
            'limit_page_length': page_size
        }
        resp = requests.get(f'{base_url}/api/resource/{doctype}',
                            params=params, headers=headers)
        data = resp.json().get('data', [])
        if not data:
            break
        all_data.extend(data)
        if len(data) < page_size:
            break
        offset += page_size
    return all_data
创建包含子表的文档
requests.post(f'{base_url}/api/resource/Sales Order', json={
    "customer": "CUST-001",
    "items": [
        {"item_code": "ITEM-001", "qty": 5, "rate": 100},
        {"item_code": "ITEM-002", "qty": 2, "rate": 250}
    ]
}, headers=headers)
更新(部分)
# Only specified fields are changed
requests.put(f'{base_url}/api/resource/Customer/CUST-001',
             json={"customer_group": "Premium"}, headers=headers)
文件上传
requests.post(f'{base_url}/api/method/upload_file',
    files={'file': ('doc.pdf', open('doc.pdf', 'rb'), 'application/pdf')},
    data={'doctype': 'Customer', 'docname': 'CUST-001', 'is_private': 1},
    headers={'Authorization': 'token api_key:api_secret'})
# NOTE: Do NOT set Content-Type header — requests sets multipart boundary automatically

RPC API:自定义方法

服务端端点
@frappe.whitelist()
def get_balance(customer):
    """GET /api/method/myapp.api.get_balance?customer=CUST-001"""
    return frappe.db.get_value("Customer", customer, "outstanding_amount")

@frappe.whitelist(methods=["POST"])
def create_payment(customer, amount):
    """POST /api/method/myapp.api.create_payment"""
    if not frappe.has_permission("Payment Entry", "create"):
        frappe.throw(_("Not permitted"), frappe.PermissionError)
    pe = frappe.new_doc("Payment Entry")
    pe.party_type = "Customer"
    pe.party = customer
    pe.paid_amount = float(amount)
    pe.insert()
    return pe.name

@frappe.whitelist(allow_guest=True)
def public_status():
    """No authentication required."""
    return {"status": "ok"}
装饰器选项
选项效果版本
allow_guest=True无需身份验证全部
methods=["POST"]限制 HTTP 方法[v14+]
xss_safe=True跳过响应的 XSS 转义全部
响应结构
// RPC success
{"message": "return_value"}

// REST success
{"data": {...}}

// Error
{"exc_type": "ValidationError", "_server_messages": "[{\"message\": \"...\"}]"}
客户端调用(JavaScript)
// RECOMMENDED: async/await with frappe.xcall
const result = await frappe.xcall('myapp.api.get_balance', {
    customer: 'CUST-001'
});

// Alternative: frappe.call with promise
frappe.call({
    method: 'myapp.api.get_balance',
    args: {customer: 'CUST-001'},
    freeze: true,
    freeze_message: __('Loading...')
}).then(r => console.log(r.message));

// Document method (frm.call)
frm.call('get_linked_doc', {throw_if_missing: true})
    .then(r => console.log(r.message));
标准 frappe.client 方法
方法端点用途
frappe.client.get_valuePOST获取单个字段值
frappe.client.get_listPOST根据筛选条件列出文档
frappe.client.getPOST获取完整文档
frappe.client.insertPOST创建文档
frappe.client.savePOST更新文档
frappe.client.deletePOST删除文档
frappe.client.submitPOST提交文档
frappe.client.cancelPOST取消文档
frappe.client.get_countPOST统计文档数量

Webhook

通过 UI 中的 Webhook DocType 进行配置。事件:

事件触发条件
after_insert创建新文档后
on_update每次保存时
on_submit提交后(docstatus=1)
on_cancel取消后(docstatus=2)
on_trash删除前
on_update_after_submit修订后
on_change每次更改时

安全性:务必设置 Webhook Secret。Frappe 会添加 X-Frappe-Webhook-Signature 标头,其中包含经 base64 编码的负载 HMAC-SHA256。请在接收端验证。

条件:使用 Jinja2——{{ doc.grand_total > 10000 }}。

完整的处理程序示例请参阅 references/webhooks-reference.md。

HTTP 状态码

代码含义常见原因
200成功—
400错误请求验证错误
401未授权缺少或无效的身份验证信息
403禁止访问无权执行此操作
404未找到文档不存在
417期望失败服务端异常(frappe.throw)
429请求频率受限请求过多
500服务端错误未处理的异常

关键规则

  1. 始终在 API 请求中包含 Accept: application/json 标头
  2. 始终在 @frappe.whitelist() 方法中添加权限检查
  3. 始终验证并清理白名单方法中的输入
  4. 始终使用参数化查询 — 绝不通过字符串插值构造 SQL
  5. 始终为外部 requests 调用设置 timeout=30
  6. 始终将凭据存储在 frappe.conf 或环境变量中 — 绝不硬编码
  7. 始终使用 HMAC-SHA256 验证 Webhook 签名
  8. 始终对列表响应进行分页 — 绝不返回无界结果集
  9. 绝不在会更改状态的端点上使用 allow_guest=True
  10. 绝不记录凭据或敏感数据
  11. 绝不将 Administrator API 密钥用于集成 — 应创建专用 API 用户

反模式

不要这样做应这样做
白名单中不检查权限操作前调用 frappe.has_permission()
frappe.db.sql(f"...{user_input}")使用参数化 %s 查询
allow_guest=True + 更改状态要求进行身份验证
不限量地返回所有记录使用 limit_page_length 分页
硬编码 API 凭据frappe.conf.get("api_key")
同步执行繁重处理对长时间任务使用 frappe.enqueue()
外部调用未设置超时requests.get(url, timeout=30)
响应格式不一致始终返回 {"status": "...", "data": ...}

版本差异

功能v14v15v16
/api/resource/(v1)是是是
/api/v2/document/(v2)否是是
/api/v2/doctype/{dt}/meta否是是
/api/v2/doctype/{dt}/count否是是
limit 别名参数否是是
OAuth2 的 PKCE有限支持是是
Server Script 速率限制否是是
通过 v2 URL 调用文档方法否是是

参考文件

文件内容
authentication-methods.mdToken、Session、OAuth2,附代码示例
rest-api-reference.md完整的 REST CRUD,包含筛选和分页
rpc-api-reference.md白名单方法、frappe.call、frappe.xcall
webhooks-reference.mdWebhook 配置、安全性和处理程序示例
anti-patterns.md常见错误及修复方法
examples.mdPython/JS/cURL 客户端实现

相关技能

  • frappe-core-permissions — API 端点的权限系统
  • frappe-core-database — API 方法背后的数据库查询
  • frappe-syntax-hooks — Webhook 的 Hook 配置
  • frappe-syntax-controllers — 通过 API 调用的控制器方法

已根据 Frappe 文档验证,日期为 2026-03-20 | Frappe v14/v15/v16

评论

支持 Markdown