RestRserve is still work in progress - while we try hard to have stable API expect some breaking changes.
RestRserve
RestRserve is an R web API framework for building high-performance microservices and app backends. The main difference with other frameworks (plumber, jug) is that it is parallel by design (thanks to Rserve).
YES - it means it will handle all the incomming requests in parallel - each request in a separate fork.
Features
- Create a http API by simply setting up a handler (R function) for a given route - Hello-world
- Deploy applications with a couple of lines of the code. Easily stop them.
- Build high performance web API - more than 10000 requests per second on a laptop with 4 cores / 8 threads (Intel i7-7820HQ CPU), which is about 20x faster than plumber (but of course these numbers are for illustration only - everything depends on the user code!).
- Generate OpenAPI specification by parsing annotations in R code
- Expose Swagger UI
- Serve static files
- Provides extensive logging in JSON format
RestRserve is a very thin layer on the top of Rserve - most of the credits should go to Simon Urbanek.
Quick start
Creating application is as simple as:
library(RestRserve)
logger = Logger$new(level = TRACE, file = "")
app = RestRserve::RestRserveApplication$new(logger = logger)
# register endpoints and corresponding R handlers
app$add_get(path = "/hello",
FUN = function(request, response) {
response$body = '{"msg":"Hello from RestRserve"}'
forward()
})
app$run(http_port = "8001")Please follow quick start article on http://restrserve.org/ for more details.
Installation
- docker image available on docker-hub - https://hub.docker.com/r/dselivanov/restrserve/
- from github
remotes::install_github("dselivanov/RestRserve")
Known limitations
- RestRserve is primarily tested on UNIX systems. While it works natively on Windows plase don't expect it to be as performant as on UNIX-like systems. If you really want to use it on Windows - consider to try Windows Subsystem for Linux and report to us.
- The main goal for RestRserve is to provide framework to create backend microservices with performance close to bare metal. So we haven't had a focus on the useful but not absolutely necessary things like uri templates. Contributions are very welcome.
- Keep in mind that every request is handled in a separate process (forked from parent Rserve instance). While this is absolutely awesome feature which allows to handle requests in parallel it also put some limitations on reusing certain objects - notably database connections.
- as already mentioned
RserveandRestRserveprocess each request in a separate fork. In certain edge cases (usually badly designed user code) it is possible thatRservewon't be able to create a fork (for example lack of RAM). In these casesRservewill return 500 error. Keep in mind thatRserveandRestRservecan't control on how much resources will be needed to handle incoming request - everything depends on the user code. In order to limit number of connections/requests it is recommended to use specialized software such as HAproxy. - While
Rserveis matured and very well tested software,RestRserveis not - you can expect some minor bugs and minor API breaks
RestRserve in "cooperative" mode
If Rserve is installed in "cooperative" mode (compiled with -DCOOPERATIVE flag) than RestRserve will hadle incoming requests in a single parent process without forking. This means it can maintain state (hence maintain DB connections, etc):
# assuming Rserve is configured to work in "cooperative" mode
library(RestRserve)
app = RestRserveApplication$new()
counter = 0L
app$add_get("/add", function(req, res) {
counter <<- counter + 1L
res$body = as.character(counter)
forward()
})
app$add_get("/sub", function(req, res) {
counter <<- counter - 1L
res$body = as.character(counter)
forward()
})
app$run(8001)Acknowledgements
- Simon Urbanek (@s-u) for awesome Rserve and all the work on R itself and on his other packages
- Artem Klevtsov (@artemklevtsov) for useful suggestions and work on test coverage
- Jeff Allen (@trestletech) for his work on Swagger UI in plumber (from where we took inspiration for our implementation)
- Brodie Gaslam (@brodieG) for help with understanding on how to get traceback from try-catched function calls. Also thanks Hadley Wickham (@hadley) for evaluate::try_capture_stack function which we use for this purpose.