An OpenAPI Specification (OAS) compliant REST API framework for R inspired by Python's Flask.
This is designed to run as a service (e.g., via systemctl on Linux). Everything is returned as JSON and this package allows to return data from SQL connections or any type of object that can be serialized as JSON.
- OpenAPI 3.0 specification auto-generation
- Built-in Swagger UI at
/docs - OpenAPI spec served at
/openapi.json - Flask-like routing with piping support
- Automatic parameter extraction from query strings
remotes::install_github("pachadotdev/openapi")Paste this into an R console
library(openapi)
api <- api_init(
title = "My API",
version = "1.0.0",
description = "A sample API built with openapi for R"
) |>
api_get("/", function() {
list(message = "Welcome to openapi for R!")
},
summary = "Root endpoint",
description = "Returns a welcome message"
) |>
api_get("/hello", function() {
list(greeting = "Hello World!")
},
summary = "Hello endpoint",
tags = c("greetings")
) |>
api_get("/greet", function(name) {
if (is.na(name)) name <- "Moto"
list(greeting = paste("Hello,", name, "!"))
},
summary = "Greet by name",
description = "Greets the user by name, defaults to 'Moto' if not provided",
tags = c("greetings")
)
# Run the server
api_run(api, host = "127.0.0.1", port = 5000, debug = TRUE)then visit
- http://127.0.0.1:5000/ - Your API
- http://127.0.0.1:5000/docs - Swagger UI documentation
- http://127.0.0.1:5000/openapi.json - OpenAPI specification
- http://127.0.0.1:5000/hello
- http://127.0.0.1:5000/greet?name=World
Undefined parameters are NA.
library(openapi)
api <- api_init()
api <- api_get(api, "/mtcars1", function(cyl, am) {
# sanitize parameters
cyl <- as.integer(substr(cyl, 1, 1))
am <- as.integer(substr(am, 1, 1))
d <- mtcars
if (!is.na(cyl) && cyl > 0) { d <- d[d$cyl == cyl, ] }
if (!is.na(am) && am %in% 0:1) { d <- d[d$am == am, ] }
d
})
api <- api_get(api, "/mtcars2", function(cyl, vs) {
# sanitize parameters
cyl <- as.integer(substr(cyl, 1, 1))
vs <- as.integer(substr(vs, 1, 1))
d <- mtcars
if (!is.na(cyl) && cyl > 0) { d <- d[d$cyl == cyl, ] }
if (!is.na(vs) && vs %in% 0:1) { d <- d[d$vs == vs, ] }
d
})
api_run(api, host = "127.0.0.1", port = 5000, debug = TRUE)then visit
http://127.0.0.1:5000/mtcars1?cyl=6 http://127.0.0.1:5000/mtcars1?cyl=4&am=0 etc.
The package automatically generates an OpenAPI 3.0 specification from your routes.
When the server is running:
- Swagger UI: http://127.0.0.1:5000/docs
- OpenAPI JSON: http://127.0.0.1:5000/openapi.json
# Get spec as an R list
spec <- api_spec(api, host = "127.0.0.1", port = 5000)
# Write spec to file
api_spec_write(api, path = "openapi.json", host = "127.0.0.1", port = 5000)api <- api_init(
title = "My API",
version = "2.0.0",
description = "API description here"
) |>
api_get(
"/users",
function() { list(users = c("alice", "bob")) },
summary = "List all users",
description = "Returns a list of all registered users",
tags = c("users")
) |>
api_post(
"/users",
function(name) { list(created = name) },
summary = "Create a user",
tags = c("users")
)# Blocking (for production) - runs until Ctrl+C ----
api_run(api, host = "0.0.0.0", port = 5000)
# Non-blocking (for development/testing) ----
# returns modified api, so you must reassign
api <- api_run_background(api, port = 5000)
# do other things
httpuv::service() # process requests while doing other work
# stop when done
api_stop(api)By default, return values are JSON-serialized (lists and data frames work automatically):
# Error response with custom status
api <- api |>
api_get("/fail", function() {
response_error("Something went wrong", status = 400)
})#* @get /hello
function() {
list(message = "Hello!")
}
#* @param name The name to greet
#* @get /greet
function(name = "World") {
list(greeting = paste("Hello,", name))
}api <- api_init() |>
api_get("/hello", function() {
list(message = "Hello!")
}) |>
api_get("/greet", function(name) {
if (is.na(name)) name <- "World"
list(greeting = paste("Hello,", name))
})
api_run(api)Create /etc/systemd/system/openapi-api.service or similar:
[Unit]
Description=OpenAPI R API
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/path/to/api
ExecStart=/usr/bin/Rscript api.R
Restart=always
[Install]
WantedBy=multi-user.targetThen:
sudo systemctl daemon-reload
sudo systemctl enable openapi-api
sudo systemctl start openapi-apiApache Licence 2.0