Building APIs with plumber
Prerequisites: Working with JSON and APIs, Linear regression
Sometimes other systems need your R code's results — a website that shows a prediction, or an app that requests a forecast. plumber turns R functions into a web API by adding special comments.
install.packages("plumber")
An API file
# plumber.R
library(plumber)
model <- lm(mpg ~ wt + hp, data = mtcars)
#* Health check
#* @get /health
function() {
list(status = "ok")
}
#* Predict fuel economy for a car
#* @param wt:numeric Weight in 1000s of pounds
#* @param hp:numeric Horsepower
#* @get /predict
function(wt, hp, res) {
wt <- as.numeric(wt)
hp <- as.numeric(hp)
if (is.na(wt) || is.na(hp) || wt <= 0 || hp <= 0) {
res$status <- 400
return(list(error = "wt and hp must be positive numbers"))
}
list(mpg = round(predict(model, data.frame(wt = wt, hp = hp)), 1))
}
Run it:
plumber::pr("plumber.R") |> plumber::pr_run(port = 8000)
$ curl "http://localhost:8000/predict?wt=3&hp=150"
{"mpg":[21.1]}
#* @get /predictturns the function below it into an endpoint.- Query parameters arrive as function arguments — as text, so convert and validate them.
- Returned lists are converted to JSON automatically.
- plumber also generates interactive OpenAPI documentation at
/__docs__/.
Production concerns
- Validate every input and return clear 4xx errors — never trust what callers send.
- Load models and data once, at startup, not inside each request.
- R handles one request at a time per process; run several processes behind a load balancer (or use Posit Connect, which manages this) for more traffic.
- Deploy with Docker (the
rstudio/plumberimage) or Posit Connect, and protect endpoints with authentication if they aren't public.
For higher-throughput R APIs, newer frameworks such as ambiorix or fiery are worth a look, but plumber is the common, well-documented choice.