Skip to content

Commit

Permalink
Merge pull request #260 from ploomber/restapi-plumber
Browse files Browse the repository at this point in the history
Add REST API example with plumber
  • Loading branch information
neelasha23 authored Aug 2, 2024
2 parents 59a76f0 + d3baefd commit 593fdf4
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 0 deletions.
11 changes: 11 additions & 0 deletions examples/plumber/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM rstudio/plumber

WORKDIR /app

COPY . /app

RUN R -e "install.packages('caret', repos='http://cran.rstudio.com/')"

EXPOSE 80

ENTRYPOINT ["Rscript", "main.R"]
78 changes: 78 additions & 0 deletions examples/plumber/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# REST API with Plumber

A RESTful API built with the Plumber package in R.
The API provides three main functions:
- Checking the server status of the API with a GET request.
- Predicting iris petal length based on various parameters with a POST request.
- Displaying a plot that compares actual to predicted petal lengths with a GET request.

## Steps for Testing Locally

To run the API locally, use the following command in your terminal:
```sh
Rscript main.R
```

Now you can explore your Swagger Docs at `http://127.0.0.1/__docs__/`.

### Health Check (GET)
Check the API's server status with:
```sh
curl -X 'GET' 'http://127.0.0.1/health_check'
```

### Predict Petal Length (POST)

To predict petal length with only the petal width:
```sh
curl -X 'POST' 'http://127.0.0.1/predict_petal_length' -d 'petal_width=10'
```

To include petal width, sepal length, sepal width, and species of the flower:
```sh
curl -X 'POST' 'http://127.0.0.1/predict_petal_length' -d "petal_width=1.2" -d "sepal_length=3.5" -d "sepal_width=2.1" -d "species=setosa"
```

### Plot Actual vs Predicted (GET)
To download a plot comparing actual and predicted petal lengths:
```sh
curl -X 'GET' 'http://127.0.0.1/plot_actual_vs_predicted' --output plot.png
```

## Steps for Deploying on Ploomber Cloud
### Prerequisites
- [Ploomber Cloud account](https://www.platform.ploomber.io/applications)
- A Dockerfile
- Your code

Note: Docker deployment option is available exclusively to Pro, Teams, and Enterprise users. Start your 10-day free trial [here.](https://ploomber.io/pricing/)

There are two ways you can deploy it on Ploomber Cloud: via (1) [Graphical User Interface](https://docs.cloud.ploomber.io/en/latest/quickstart/app.html), and (2) [Command Line Interface](https://docs.cloud.ploomber.io/en/latest/user-guide/cli.html). Let's take a look at the CLI method.

### Command Line Interface

If you haven't installed `ploomber-cloud`, run
```sh
pip install ploomber-cloud
```

Then, set your API key following to [this documentation](https://docs.cloud.ploomber.io/en/latest/quickstart/apikey.html).
```sh
ploomber-cloud key YOURKEY
```

Navigate to your project directory where your Dockerfile is located and initialize the project. Confirm the inferred project type (Docker) when prompted.
```sh
cd <project-name>
ploomber-cloud init
```

Now, deploy your application.
```sh
ploomber-cloud deploy
```

Once its deployment is complete, access your endpoints deployed on Ploomber Cloud using your app's URL. For example, you can send a `GET` request with
```sh
curl -X 'GET' 'https://<id>.ploomberapp.io/health_check'
```
3 changes: 3 additions & 0 deletions examples/plumber/main.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
library(plumber)
pr <- plumb("plumber.R")
pr$run(port = 80, host = "0.0.0.0")
Binary file added examples/plumber/plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
69 changes: 69 additions & 0 deletions examples/plumber/plumber.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#* @apiTitle Iris Petal Length Prediction API
#* @apiDescription This API allows users to interact with a linear regression model predicting iris petal length based on petal width, and optionally, sepal length, sepal width, and species.
#* It provides endpoints for health checks, petal length predictions, and visualizations comparing actual to predicted lengths.

library(caret)
# Prepare the model
dataset <- iris

# Set seed for reproducibility
set.seed(42)

# Split data into training and testing sets
train_index <- createDataPartition(iris$Petal.Length, p = 0.8, list = FALSE)
train_data <- iris[train_index, ]
test_data <- iris[-train_index, ]

# Train the model using all parameters on the training data
model_all <- lm(Petal.Length ~ Sepal.Length + Sepal.Width + Petal.Width + Species, data = train_data)

# Train the model using only petal width on the training data
model_petal_width <- lm(Petal.Length ~ Petal.Width, data = iris)

#* Health check - Returns the API status and the current server time
#* @get /health_check
function() {
list(
status = "The API is running",
time = Sys.time()
)
}

#* Predict petal length - Returns a predicted petal length based on available parameters
#* @param petal_width Numeric: Width of the petal (required)
#* @param sepal_length Numeric: Length of the sepal
#* @param sepal_width Numeric: Width of the sepal
#* @param species Character: Species of the iris (setosa, versicolor, virginica)
#* @post /predict_petal_length
function(petal_width, sepal_length = NA, sepal_width = NA, species = NA) {
# Validate petal_width
if (is.na(petal_width) || is.na(as.numeric(petal_width))) {
return(list(error = "Invalid or missing parameter: petal_width"))
}
# Check which parameters are provided and create the input data frame accordingly
if (!is.na(sepal_length) && !is.na(sepal_width) && !is.na(species)) {
input_data <- data.frame(
Sepal.Length = as.numeric(sepal_length),
Sepal.Width = as.numeric(sepal_width),
Petal.Width = as.numeric(petal_width),
Species = as.factor(species)
)
prediction <- predict(model_all, input_data)
} else {
input_data <- data.frame(Petal.Width = as.numeric(petal_width))
prediction <- predict(model_petal_width, input_data)
}
list(petal_width = petal_width, predicted_petal_length = prediction)
}

#* Plot actual vs predicted - Displays a plot comparing actual vs predicted petal lengths for model_all
#* @serializer png
#* @get /plot_actual_vs_predicted
function() {
predictions <- predict(model_all, test_data)
plot(test_data$Petal.Length, predictions,
xlab = "Actual Petal Length", ylab = "Predicted Petal Length",
main = "Actual vs Predicted Petal Length"
)
abline(0, 1, col = "red") # 1:1 line
}

0 comments on commit 593fdf4

Please sign in to comment.