0Pricing
R Academy · 课时

创建 GET 和 POST 端点

处理路径参数、查询字符串和请求正文解析

创建 GET 和 POST 端点 是 CoddyKit 上的免费 R Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 R Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 R Academy 课程共包含 4 节课。

什么是 Plumber

plumber 使用特殊的注释,将普通 R 函数转换为 HTTP API 端点。为函数添加 #* @get /path 注释后,Plumber 会创建一个调用该函数并以 JSON 形式返回结果的 GET 路由。

使用 install.packages('plumber') 安装。

您的第一个 GET 端点

基本的 Plumber API 位于一个文件中(例如 api.R)。使用 #* @get 为函数添加注释,后面跟上路径。Plumber 会自动将函数的返回值序列化为 JSON。

# api.R
# library(plumber)
#
# #* Return a greeting
# #* @get /hello
# function() {
#   list(message = 'Hello from Plumber!')
# }
#
# Start with:
# pr <- plumb('api.R')
# pr$run(port = 8000)

带类型提示的路径参数

使用尖括号语法嵌入可变的路径片段:/users/<id:int>。Plumber 会解析该片段,并将其作为具有指定类型的参数传递给您的函数。支持的类型包括 int、dbl 和 chr。

# #* Get a user by ID
# #* @get /users/<id:int>
# function(id) {
#   # id is already an integer
#   list(
#     user_id = id,
#     name    = paste('User', id)
#   )
# }
#
# GET /users/42  =>  {"user_id":42, "name":"User 42"}

使用 #* @param 处理查询参数

使用 #* @param name Description 记录查询参数。参数名称必须与函数参数名称匹配。Plumber 会自动从查询字符串中读取该参数——无需手动解析。

# #* Search users by name
# #* @param name The name to search for
# #* @param limit Maximum results to return
# #* @get /users/search
# function(name = '', limit = '10') {
#   limit <- as.integer(limit)
#   # query string: /users/search?name=Alice&limit=5
#   list(query = name, max = limit)
# }

创建 POST 端点

对于接收请求体的端点,请使用 #* @post /path。特殊的 req 参数可访问原始请求对象。当函数参数名为 req 时,Plumber 会自动传入该对象。

# #* Create a new user
# #* @post /users
# function(req) {
#   body <- jsonlite::fromJSON(req$postBody)
#   # body$name, body$email are now available
#   list(
#     status  = 'created',
#     user_id = sample(1000:9999, 1),
#     name    = body$name
#   )
# }

解析请求体

req$postBody 包含 POST 请求体中的原始 JSON 字符串。使用 jsonlite::fromJSON(req$postBody) 对其进行解析,以获取命名的 R 列表。处理数据前,请始终验证必需字段。

# #* @post /orders
# function(req, res) {
#   body <- jsonlite::fromJSON(req$postBody)
#   if (is.null(body$product_id)) {
#     res$status <- 400L
#     return(list(error = 'product_id is required'))
#   }
#   list(
#     order_id   = as.integer(Sys.time()),
#     product_id = body$product_id,
#     quantity   = body$quantity %||% 1
#   )
# }

使用 res$status 设置 HTTP 状态码

res 参数(同样由 Plumber 自动注入)可用于设置 HTTP 响应状态码。请在返回结果前设置它:res$status <- 404L。常见状态码:

  • 200 — OK(默认)
  • 201 — 已创建
  • 400 — 错误请求
  • 404 — 未找到
  • 500 — 内部服务器错误
# #* @get /items/<id:int>
# function(id, res) {
#   items <- list(
#     list(id=1, name='Widget'),
#     list(id=2, name='Gadget')
#   )
#   found <- Filter(function(x) x$id == id, items)
#   if (length(found) == 0) {
#     res$status <- 404L
#     return(list(error = paste('Item', id, 'not found')))
#   }
#   found[[1]]
# }

将命名列表作为 JSON 返回

Plumber 使用 jsonlite 将 R 返回值序列化为 JSON。命名列表会成为 JSON 对象;未命名列表会成为 JSON 数组。对于结构化响应,请返回命名列表。

# Named list => JSON object
# list(id=1, name='Alice')  => {"id":1, "name":"Alice"}
#
# Unnamed list => JSON array
# list(1, 2, 3)  =>  [1, 2, 3]
#
# Nested structures work too:
# list(
#   user   = list(id=1, name='Alice'),
#   orders = list(list(id=101), list(id=102))
# )
# => {"user":{"id":1,"name":"Alice"}, "orders":[{"id":101},{"id":102}]}

Plumber 路由器对象

使用 plumb('api.R') 加载带注释的 R 文件,以创建 Plumber router 对象。调用 pr$run(port = 8000) 启动服务器。在生产环境中,通常会调用 pr_run(pr, host='0.0.0.0', port=8000)。

# Standard plumber startup in api_start.R:
# library(plumber)
# pr <- plumb('api.R')
# pr$run(port = 8000, host = '0.0.0.0')
#
# Or with pipe style:
# plumb('api.R') |> pr_run(port = 8000)
#
# Test with:
# curl http://localhost:8000/hello

处理多种 HTTP 方法

通过编写带有不同注解的函数,单个路径可以支持多种方法。Plumber 会根据所使用的 HTTP 方法,将请求路由到正确的函数。

# #* List all products
# #* @get /products
# function() {
#   list(products = list(list(id=1, name='Widget')))
# }
#
# #* Create a product
# #* @post /products
# function(req) {
#   body <- jsonlite::fromJSON(req$postBody)
#   list(created = TRUE, name = body$name)
# }

测试您的 API 端点

服务器运行时,可以在终端中使用 curl,或在 R 中使用 httr2 来测试端点。httr2 还可以让您将可重复的测试与 API 代码放在一起编写。

# From terminal:
# curl http://localhost:8000/users/42
# curl -X POST http://localhost:8000/users \
#      -H 'Content-Type: application/json' \
#      -d '{"name":"Alice","email":"alice@example.com"}'
#
# From R:
# library(httr2)
# resp <- request('http://localhost:8000/users/42') |> req_perform()
# resp_body_json(resp)

快速检查:路径参数

如何声明一个名为 id 的路径参数,使 Plumber 将其解析为整数?

GET 和 POST 端点回顾

使用 Plumber 构建 REST 端点:

  • #* @get /path 创建 GET 路由;#* @post /path 创建 POST 路由
  • 路径参数使用 <name:type> 语法(int、dbl、chr)
  • 查询参数会自动解析为相匹配的函数参数
  • POST 请求体可通过 jsonlite::fromJSON(req$postBody) 获取
  • 对于非 200 的 HTTP 响应,请设置 res$status
  • 返回带名称的列表——它们会自动序列化为 JSON 对象

常见问题解答

「创建 GET 和 POST 端点」课时是免费的吗?

是的 — 「创建 GET 和 POST 端点」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 R Academy 课程的其余内容,请升级到 CoddyKit PRO。 R Academy 课程共包含 4 节课。

「创建 GET 和 POST 端点」这节课中我会学到什么?

处理路径参数、查询字符串和请求正文解析 你通过在浏览器中直接运行的动手代码来练习 R Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 R Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 R Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「创建 GET 和 POST 端点」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 R Academy 课中编写并运行代码吗?

能。每节 R Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. Plumber 与 REST 入门
  2. 创建 GET 和 POST 端点
  3. 身份验证与 API 安全
  4. 将 Plumber API 部署到生产环境
← 返回 R Academy