创建 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 反馈 — 无需本地设置。
此课程中的所有课时
- Plumber 与 REST 入门
- 创建 GET 和 POST 端点
- 身份验证与 API 安全
- 将 Plumber API 部署到生产环境