0Pricing
R Academy · 课时

Plumber 与 REST 入门

理解 REST 原则,并将 R 函数注释为 API 端点

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

什么是 REST API

REST(表述性状态转移)API 是一种通过 HTTP 提供数据和操作的 Web 服务。主要原则包括:

  • 无状态:每个请求都包含所需的全部信息;服务器端不保存会话。
  • 面向资源:端点表示资源(/users、/predictions)。
  • 标准 HTTP 动词:GET(读取)、POST(创建)、PUT(更新)、DELETE(删除)。
  • JSON:请求体和响应体的标准数据格式。
# REST API concepts in HTTP terms:
# GET /api/model/predict?x=5      -> read a prediction
# POST /api/model/train           -> create a new model
# GET /api/data/summary           -> read data summary
# DELETE /api/cache/flush         -> remove cached results

# Plumber maps R functions to these HTTP endpoints
cat('REST: stateless, resource-oriented, JSON responses')

plumber 注释语法

plumber 使用以 #* 开头的特殊注释来定义 API 端点。请将注释放在处理该端点的 R 函数正上方。函数参数会映射到请求参数;返回值会成为 JSON 响应体。

# plumber.R
library(plumber)

#* @get /ping
function() {
  list(status = 'ok', time = Sys.time())
}

#* @get /add
#* @param a:int First number
#* @param b:int Second number
function(a, b) {
  list(result = as.integer(a) + as.integer(b))
}

pr() — 创建 Plumber 路由器

pr('plumber.R') 会读取 plumber 文件,并创建一个注册所有带注释端点的路由器对象。路由器是您在启动前进行配置的中心对象(添加过滤器、序列化器等)。

library(plumber)

# Create a router from a plumber file
api <- pr('plumber.R')

# Inspect registered routes
print(api$routes)

# Alternatively, define inline without a file:
api <- pr() |>
  pr_get('/ping', function() list(status = 'ok')) |>
  pr_post('/echo', function(req) req$body)

pr_run() — 启动服务器

pr_run(router, host, port) 会启动 plumber API 服务器。默认情况下,它绑定到 127.0.0.1:8000。将 host = '0.0.0.0' 设置为接受来自任何网络接口的连接(Docker 或远程访问所必需)。

library(plumber)

api <- pr('plumber.R')

# Start server on localhost port 8000
# pr_run(api, host = '127.0.0.1', port = 8000)

# For Docker/remote access, bind to all interfaces
# pr_run(api, host = '0.0.0.0', port = 8000)

# View auto-generated Swagger docs in browser
# (automatically available at /docs or /__docs__/ endpoint)
cat('Swagger UI auto-generated at http://localhost:8000/__docs__/')

@get 注释

#* @get /path 注释会将 GET 请求映射到相应函数。查询字符串参数(例如 ?name=Alice)会自动作为 R 函数参数传入。如果没有提供转换注释,参数会以字符字符串形式传入。

# plumber.R

#* Greet a user by name
#* @param name:str The name to greet
#* @get /greet
function(name = 'World') {
  list(
    message = paste('Hello,', name),
    timestamp = format(Sys.time(), '%Y-%m-%d %H:%M:%S')
  )
}
# GET /greet?name=Alice
# -> {"message":"Hello, Alice","timestamp":"2026-01-01 12:00:00"}

@post 注释

#* @post /path 注释会将 POST 请求映射到相应函数。请求体(通常为 JSON)可通过特殊的 req 参数访问,即 req$body(当请求体为 JSON 时,这是一个已解析的列表)。POST 用于创建资源或触发计算的操作。

# plumber.R

#* Run a linear model prediction
#* @post /predict
function(req) {
  # req$body is already parsed from JSON
  input_data <- as.data.frame(req$body)

  # Run prediction with a pre-loaded model
  predictions <- predict(trained_model, newdata = input_data)

  list(
    predictions = as.numeric(predictions),
    n           = nrow(input_data)
  )
}

JSON 序列化器

默认情况下,plumber 使用 jsonlite 将返回值序列化为 JSON。#* @serializer json 注释可明确指定这一点。您可以在注释中以 JSON 列表的形式指定选项,从而配置美化打印或空值处理等序列化器选项。

# Default: automatic JSON serialization
#* @get /data
function() {
  list(values = 1:5, labels = c('a', 'b', 'c', 'd', 'e'))
}

# Explicit JSON serializer with options
#* @serializer json list(na = 'null', auto_unbox = TRUE)
#* @get /data_explicit
function() {
  list(value = 42, missing = NA)
}
# With auto_unbox=TRUE: {"value":42} not {"value":[42]}

HTTP 动词 — PUT、DELETE、PATCH

plumber 通过相应的注释支持所有标准 HTTP 动词:

  • #* @put /path:完整替换资源。
  • #* @delete /path:删除资源。
  • #* @patch /path:部分更新资源。
  • #* @head /path:仅返回标头(无正文)。
# plumber.R — CRUD-style endpoints

#* Update a model configuration
#* @put /config/<model_id>
function(model_id, req) {
  config <- req$body
  save_config(model_id, config)
  list(updated = model_id, config = config)
}

#* Remove cached results
#* @delete /cache/<key>
function(key) {
  cache_env <- globalenv()$cache
  rm(list = key, envir = cache_env)
  list(deleted = key)
}

路径参数

路径参数使用尖括号定义在路由中:/user/。plumber 会从 URL 中提取该值,并将其作为同名函数参数传入。这些参数不同于查询参数(查询参数出现在 ? 之后)。

# plumber.R

#* Get stats for a specific dataset
#* @param dataset_id:str The dataset identifier
#* @get /datasets/<dataset_id>/stats
function(dataset_id) {
  if (!dataset_id %in% available_datasets()) {
    stop(paste('Dataset not found:', dataset_id))
  }
  ds <- load_dataset(dataset_id)
  list(
    id    = dataset_id,
    rows  = nrow(ds),
    cols  = ncol(ds),
    names = names(ds)
  )
}

错误处理

当 R 函数抛出错误时,plumber 会捕获该错误,并返回包含 JSON 错误消息的 500 HTTP 响应。对于面向用户的 API,请使用 res$status 明确返回适当的 HTTP 状态码,并在验证错误时使用 stop()。

# plumber.R

#* Divide two numbers safely
#* @get /divide
function(a, b, res) {
  a <- suppressWarnings(as.numeric(a))
  b <- suppressWarnings(as.numeric(b))

  if (is.na(a) || is.na(b)) {
    res$status <- 400  # Bad Request
    return(list(error = 'Both a and b must be numeric'))
  }
  if (b == 0) {
    res$status <- 422  # Unprocessable Entity
    return(list(error = 'Division by zero is not allowed'))
  }
  list(result = a / b)
}

自动生成的 Swagger 文档

plumber 会根据您的注释自动生成交互式 Swagger UI 文档。服务器运行时,访问 /__docs__/ 即可查看所有端点及其参数,并在浏览器中尝试调用。使用 #* @tag 可按逻辑对端点分组。

# plumber.R with Swagger metadata

#* @apiTitle My ML Prediction API
#* @apiDescription Serves predictions from trained R models
#* @apiVersion 1.0.0

#* @tag model
#* @get /health
function() list(status = 'healthy')

#* Predict house price
#* @tag prediction
#* @param sqft:dbl Square footage
#* @param bedrooms:int Number of bedrooms
#* @get /predict
function(sqft = 1000, bedrooms = 3) {
  pred <- predict(price_model, data.frame(sqft = as.numeric(sqft),
                                          bedrooms = as.integer(bedrooms)))
  list(predicted_price = round(as.numeric(pred), 2))
}

快速检查

在 plumber 中,查询参数(例如 /greet?name=Alice)和路径参数(例如 /user/42)有什么区别?

plumber 与 REST 回顾

《plumber 与 REST 简介》的要点:

  • REST:无状态、面向资源、使用标准 HTTP 动词,并返回 JSON。
  • plumber 使用函数上方的 #* 注释,将 R 函数映射到端点。
  • pr('file.R') 会创建路由器;pr_run(api, host, port) 会启动服务器。
  • #* @get /path 处理 GET;#* @post /path 处理 POST。
  • 路径参数:/user/;查询参数:/search?term=foo。
  • 返回命名列表——plumber 会自动将其序列化为 JSON。
  • Swagger UI 会根据您的注释在 /__docs__/ 自动生成。
# Complete minimal plumber API
library(plumber)

#* @apiTitle Simple Prediction API

#* Health check
#* @get /health
function() list(status = 'ok')

#* Predict mpg from weight
#* @param wt:dbl Car weight (1000 lbs)
#* @get /predict
function(wt = 3.0) {
  pred <- predict(lm(mpg ~ wt, data = mtcars),
                  newdata = data.frame(wt = as.numeric(wt)))
  list(wt = as.numeric(wt), predicted_mpg = round(pred, 2))
}

# Run:
# api <- pr('plumber.R')
# pr_run(api, port = 8000)

常见问题解答

「Plumber 与 REST 入门」课时是免费的吗?

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

「Plumber 与 REST 入门」这节课中我会学到什么?

理解 REST 原则,并将 R 函数注释为 API 端点 你通过在浏览器中直接运行的动手代码来练习 R Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 R Academy 需要有经验吗?

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

「Plumber 与 REST 入门」课时需要多长时间?

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

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

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

此课程中的所有课时

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