REST API

Frappe 框架会自动为您的所有 DocType 生成 REST API。您还可以使用它们的点分模块路径来运行任意的 Python 方法。

身份验证

有两种通过 Frappe REST API 进行身份验证的方式:基于令牌的身份验证和基于密码的身份验证。

1. 基于令牌的身份验证

令牌由 API 密钥(API Key)和 API 机密(API Secret)组成。要生成这些令牌,请按照以下步骤操作:

  1. 前往用户列表并打开一个用户。
  2. 点击“设置”选项卡。(如果您看不到选项卡,请跳过此步骤)
  3. 展开“API 访问”部分,然后点击“生成密钥”。
  4. 您将看到一个包含 API 机密的弹出窗口。复制此值并将其保存在安全的地方(例如密码管理器)。
  5. 您还会在此部分看到另一个字段“API 密钥”。

令牌是通过使用冒号 : 连接 api_keyapi_secret 生成的。将字符串 token api_key:api_secret 传递给请求中的 Authorization 请求头。

fetch('http://<base-url>/api/method/frappe.auth.get_logged_user', {
    headers: {
        'Authorization': 'token api_key:api_secret'
    }
})
.then(r => r.json())
.then(r => {
    console.log(r);
})
➜ curl http://<base-url>/api/method/frappe.auth.get_logged_user -H "Authorization: token api_key:api_secret"

您使用这些令牌发出的每个请求都将记录在您在步骤 1 中选择的用户名下。这也意味着将针对该用户检查角色权限。您也可以创建一个仅用于 API 调用的新用户。

2. 基于密码的身份验证

基于密码的身份验证依赖于 Cookie 和会话数据来维持后续请求的身份验证状态。在大多数情况下,您用于发出 REST 调用的库会处理会话数据,但如果它不处理,您应该使用基于令牌的身份验证。

fetch('http://<base-url>/api/method/login', {
    method: 'POST',
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        usr: 'username or email',
        pwd: 'password'
    })
})
.then(r => r.json())
.then(r => {
    console.log(r);
})
➜ curl --cookie-jar snowcookie --request POST "http://<base-url>/api/method/login" -H 'Content-Type: application/json' -H 'Accept: application/json' --data-raw "{ "usr" : "<username>", "pwd": "<password>" }"
{"message":"Logged In","home_page":"/app","full_name":"<user:full_name>","dashboard_route":"/sites"}

➜ curl --cookie snowcookie --request POST "http://<base-url>/api/method/frappe.auth.get_logged_user" -H 'Accept: application/json'
{"message":"<username>"}

3. 访问令牌

请参阅有关如何设置 OAuth 的文档。

在请求头中使用生成的 access_token

fetch('http://<base-url>/api/method/frappe.auth.get_logged_user', {
    headers: {
        'Authorization': 'Bearer access_token'
    }
})
.then(r => r.json())
.then(r => {
    console.log(r);
})

列出文档

要获取某个 DocType 的记录列表,请向 /api/resource/:doctype 发送 GET 请求。默认情况下,它将返回 20 条记录,并且仅获取记录的 name 字段。查询结果可以在响应的 data 字段下找到。

我们将使用 ToDo DocType 来展示以下查询的示例响应。

GET /api/resource/:doctype

响应

{
  "data":[
    {"name":"f765eef382"},
    {"name":"2a26fa1c64"},
    {"name":"f32c68060f"},
    {"name":"9065fa9832"},
    {"name":"419082fc38"},
    {"name":"6234d15099"},
    {"name":"62f2181ee0"},
    {"name":"a50afbbfaa"},
    ...
  ]
}

您可以在 fields 参数中指定要获取的字段。它应该是一个 JSON 数组。

GET /api/resource/:doctype?fields=["field1", "field2"]

响应

{
  "data":[
    {"description":"Business worker talk society. Each try theory prove notice middle. Crime couple trouble guy project hit.","name":"f765eef382"},
    {"description":"This reveal as look near sister. Car staff bar specific address.","name":"2a26fa1c64"},
    {"description":"Wear bag some walk. Movie partner new class tough run. Brother Democrat imagine.","name":"f32c68060f"},
    {"description":"Break laugh apply reveal new now focus heavy. Outside local staff research total. Else point try despite.","name":"9065fa9832"},
    {"description":"Truth reduce baby artist actually model. Cost phone us others himself wife almost. Language thing wonder share talk. Factor glass significant could window certain yet.","name":"419082fc38"},
    {"description":"Tv memory understand opportunity window beat physical.","name":"6234d15099"},
    {"description":"Should floor situation in response sell. Our assume company mean red majority shoulder.","name":"62f2181ee0"},
    {"description":"Performance seem sign recent. Court form me tonight simple trouble. Address job garden play teach. Happy speech amount offer change then.","name":"a50afbbfaa"},
    ...
  ]
}

您可以在 expand 参数中指定要展开的字段。它应该是一个 JSON 数组。

GET /api/resource/:doctype?expand=["priority"]

响应

{
  "data":[
    {
        "name":"f765eef382"
        "priority": {
            "name":"a1b2c3", 
            "title": "Medium", 
            "creation": "2025-11-05 19:02:19.106966",
        },
    },
    {
        "name":"f765eef393"
        "priority": {
            "name":"a1b2c4", 
            "title": "High", 
            "creation": "2025-11-05 20:02:19.106966",
        },
    },
    ...
  ]
}

您可以通过传递 filters 参数来过滤记录。过滤器应该是一个数组,其中每个过滤器的格式为:[field, operator, value]

GET /api/resource/:doctype?filters=[["field1", "=", "value1"], ["field2", ">", "value2"]]

响应

{
  "data":[
    {"name":"f765eef382"},
    {"name":"2a26fa1c64"},
    {"name":"f32c68060f"},
    {"name":"9065fa9832"},
    {"name":"419082fc38"},
    {"name":"6234d15099"},
    {"name":"62f2181ee0"},
    {"name":"a50afbbfaa"},
    ...
  ]
}

filters 参数使用 AND SQL 运算符连接所有指定的过滤器,如果您需要 OR 过滤器,则可以使用 or_filters 参数。or_filters 的语法与 `filters` 相同。

您还可以提供排序字段和排序顺序。其格式应为 fieldname ascfieldname desc。空格应进行 URL 编码。在下面一行中,我们假设字段名为 title

GET /api/resource/:doctype?order_by=title%20desc

您还可以通过提供 limit_startlimit_page_length 参数来对结果进行分页。

GET /api/resource/:doctype?limit_start=5&limit_page_length=10

响应

{
  "data": [
    {"name":"6234d15099"},
    {"name":"62f2181ee0"},
    {"name":"a50afbbfaa"},
    {"name":"aa12a5cf71"},
    {"name":"6ac9800d4e"},
    {"name":"4bcf8b701c"},
    {"name":"aee15f4c20"},
    {"name":"6ba753afef"},
    ...
  ]
}

limitlimit_page_length 的别名,用于在版本 13 中访问 /api/resource。这意味着以下请求也应返回与上述查询相同的响应。

GET /api/resource/:doctype?limit_start=5&limit=10

默认情况下,您将收到 List[dict] 格式的数据。您可以通过传递 as_dict=False 来以 List[List] 格式检索数据。

GET /api/resource/:doctype?limit_start=5&limit=5&as_dict=False

响应

{
  "data": [
    ["6234d15099"],
    ["62f2181ee0"],
    ["a50afbbfaa"],
    ["aa12a5cf71"],
    ["6ac9800d4e"]
  ]
}

要调试为您的请求构建的查询,您可以在请求中传递 debug=True。这将在响应的 exc 字段下返回已执行的查询和执行时间。

GET /api/resource/:doctype?limit_start=10&limit=5&debug=True

响应

{
  "data": [
    {"name":"4bcf8b701c"},
    {"name":"aee15f4c20"},
    {"name":"6ba753afef"},
    {"name":"f4b7e24abc"},
    {"name":"bd9156096c"}
  ],
  "exc": "[\"select `tabToDo`.`name`\\n\\t\\t\\tfrom `tabToDo`\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t order by `tabToDo`.`modified` DESC\\n\\t\\t\\tlimit 5 offset 10\", \"Execution time: 0.0 sec\"]"
}

CRUD 操作

Frappe 会自动为所有 DocType 生成用于 CRUD 操作的 REST 端点。请确保在您的请求中设置以下请求头,以便获得正确的 JSON 响应。

{
    "Accept": "application/json",
    "Content-Type": "application/json",
}

创建

通过向 /api/resource/:doctype 发送 POST 请求来创建新文档。在请求体中发送 JSON 格式的文档。

POST /api/resource/:doctype

# Body
{"description": "New ToDo"}

响应

{
  "data": {
    "name": "af2e2d0e33",
    "owner": "Administrator",
    "creation": "2019-06-03 14:19:00.281026",
    "modified": "2019-06-03 14:19:00.281026",
    "modified_by": "Administrator",
    "idx": 0,
    "docstatus": 0,
    "status": "Open",
    "priority": "Medium",
    "description": "New ToDo",
    "doctype": "ToDo"
  }
}

读取

通过向 /api/resource/:doctype/:name 发送 GET 请求来获取文档。

GET /api/resource/:doctype/:name

响应

{
  "data": {
    "name": "bf2e760e13",
    "owner": "Administrator",
    "creation": "2019-06-03 14:19:00.281026",
    "modified": "2019-06-03 14:19:00.281026",
    "modified_by": "Administrator",
    "idx": 0,
    "docstatus": 0,
    "status": "Open",
    "priority": "Medium",
    "description": "
<p>Test description</p>",
    "doctype": "ToDo"
  }
}

通过向 /api/resource/:doctype/:name?expand_links=True 发送 GET 请求来展开所有链接字段。

GET /api/resource/:doctype/:name?expand_links=True

响应

{
  "data": {
    "name": "bf2e760e13",
    "owner": "Administrator",
    "creation": "2019-06-03 14:19:00.281026",
    "modified": "2019-06-03 14:19:00.281026",
    "modified_by": "Administrator",
    "idx": 0,
    "docstatus": 0,
    "status": "Open",
    "priority": {
        "name":"a1b2c3", 
        "title": "Medium", 
        "creation": "2025-11-05 19:02:19.106966",
    },
    "description": "
<p>Test description</p>",
    "doctype": "ToDo"
  }
}

更新

通过向 /api/resource/:doctype/:name 发送 PUT 请求来更新文档。您无需发送整个文档,只需发送要更新的字段即可。

PUT /api/resource/:doctype/:name

# Body
{"description": "New description"}

响应

{
  "data": {
    "name": "bf2e760e13",
    "owner": "Administrator",
    "creation": "2019-06-03 14:19:00.281026",
    "modified": "2019-06-03 14:21:00.785117",
    "modified_by": "Administrator",
    "idx": 0,
    "docstatus": 0,
    "status": "Open",
    "priority": "Medium",
    "description": "New description",
    "doctype": "ToDo"
  }
}

删除

通过向 /api/resource/:doctype/:name 发送 DELETE 请求来删除文档。

DELETE /api/resource/:doctype/:name

响应

{"message": "ok"}

远程方法调用

Frappe 允许您使用 REST API 触发任意的 Python 方法来处理自定义逻辑。这些方法必须被标记为 白名单 才能通过 REST 访问。

要运行位于 frappe.auth.get_logged_user 的白名单 Python 方法,请向端点 /api/method/frappe.auth.get_logged_user 发送请求。

GET /api/method/frappe.auth.get_logged_user

响应

{
  "message": "[email protected]"
}
  • 如果您的方法返回一些值,您应该发送一个 GET 请求。
  • 如果您的方法更改了数据库的状态,请使用 POST。在成功的 POST 请求之后,框架将自动调用 frappe.db.commit() 将更改提交到数据库。
  • 成功的响应将返回一个包含 message 键的 JSON 对象。
  • 出错的响应将返回一个包含 exc 键的 JSON 对象,该键包含堆栈跟踪,以及包含所抛出异常的 exc_type 键。
  • 方法的返回值将被转换为 JSON 并作为响应发送。

文件上传

有一个专门的方法 /api/method/upload_file,它接受二进制文件数据并将其上传到系统中。

以下是它的 curl 命令:

➜ curl -X POST \
  http://<base-url>/api/method/upload_file \
  -H 'Accept: application/json' \
  -H 'Authorization: token xxxx:yyyy' \
  -F file=@/path/to/file/file.png

如果您使用客户端 Javascript 上传文件,您可以将上传的文件附加为 FormData 并发送 XHR 请求。以下是 Frappe Desk 中的实现代码。