Skip to Content
Course content

228: Building a Simple API with plumber

Click on the "Edit" button in the top corner of the screen to edit your slide content.

A few years ago, I worked with a data scientist who had built an incredibly accurate model for predicting warehouse inventory shortages. The model was a masterpiece of R code, but there was one problem: the logistics team didn't know R. They used a custom internal dashboard built in JavaScript. For three months, my colleague was essentially a human API—he would spend his mornings manually running the script for the logistics team, saving the results to a CSV, and emailing it to them. It was a tedious, fragile process that wasted everyone's time. We solved it in an afternoon by wrapping his logic in plumber, turning that script into a live endpoint the dashboard could call directly.

At its core, plumber allows you to take existing R functions and expose them as REST API endpoints. You don't have to write complex networking code or worry about the intricacies of HTTP headers; you simply "decorate" your R functions with special comments that tell plumber how to handle incoming requests.

Decorating Your Logic for the Web

The magic of plumber happens in the comments. Any comment starting with #* is interpreted as a directive. Instead of writing a separate routing file, you write your logic and the API definition in the same place. For instance, if we want to create an endpoint that predicts the yield of a crop based on rainfall, we don't just write the function—we tell plumber that this function should be accessible via a GET request at a specific path.

#* Predict crop yield based on rainfall
#* @param rainfall The amount of rainfall in mm
#* @get /predict-yield
function(rainfall) {
  yield <- as.numeric(rainfall) * 0.5 + 10
  list(predicted_yield = yield, unit = "bushels per acre")
}

Notice the @get /predict-yield line. This tells the server: "When someone hits the /predict-yield URL using a GET method, run this specific function." I find this approach refreshing because it keeps the documentation and the implementation side-by-side.

Handling Inputs and JSON Responses

One of the biggest headaches in API development is usually data serialization—converting your internal data structures into something the rest of the web understands, usually JSON. Plumber handles this automatically. When your function returns a list or a data frame, plumber serializes it to JSON before sending it back to the client.

You also need to be mindful of how you receive data. In the example above, rainfall is passed as a query parameter (e.g., /predict-yield?rainfall=120). Because URL parameters are transmitted as strings, I explicitly cast it using as.numeric(). If you forget this, you'll likely run into a type-mismatch error the moment you try to perform math on the input. If you're building a more complex API that requires sending a large object, you'll want to use @post instead of @get, which allows the client to send a JSON body.

Spinning Up the Plumber Server

Writing the functions is only half the battle; you actually have to host them. To turn your R script into a running server, you use the plumb() function to parse the file and the prun() function to start the service. I usually keep these calls in a separate run_api.R script so I don't accidentally start the server every time I'm just trying to test a local function.

library(plumber)

# Load the plumber file
pr <- plumb("plumber.R")

# Run the API on a specific port
pr$run(port=8000)

Once this is running, your R session is effectively hijacked to serve as a web server. You can open your browser or a tool like Postman and hit http://localhost:8000/predict-yield?rainfall=100 to see your R function's output rendered as JSON. Just a word of caution: the built-in prun() is great for development, but if you're moving to a production environment with high traffic, you'll want to look into running plumber behind a proxy like Nginx.




📋 Practical Task

Building a Regional Sales Forecasting Endpoint

Your task is to create a simple API using the plumber package that provides a simulated sales forecast for different business regions. This will mimic a real-world scenario where a frontend dashboard needs quick access to R-calculated forecasts.

Requirements:

  • Create a file named forecast_api.R.
  • Define a function decorated with @get /forecast.
  • The function must accept two parameters: region (a string) and multiplier (a numeric value).
  • Inside the function, create a base forecast value (e.g., 1000) and multiply it by the multiplier.
  • The function should return a named list containing the region, the calculated_forecast, and a status message saying "Success".
  • Ensure you handle the multiplier input by casting it to a numeric type to prevent errors.

Testing your work:

Run the API using plumb("forecast_api.R")$run(port=8000) and verify it works by visiting http://localhost:8000/forecast?region=North&multiplier=1.5 in your browser.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.