Suppose you’ve developed a very useful algorithm or statistical model and you need to integrate it with some external system. Nowadays HTTP became de facto a lingua-franca for this kind of tasks.
In this article we will demonstrate how to use RestRserve to build a basic REST API.
Generally RestRserve workflow consists of several major steps:
Application$new()request and
response as an input. request and
response are instances of RestRserve::Request
and RestRserve::Response. It is important to
remember that both request and
response are mutable objects.response in place or raise()
exception in case of errorFor simplicity we will use Fibonacci number calculation as an algorithm we want to expose.
calc_fib = function(n) {
if (n < 0L) stop("n should be >= 0")
if (n == 0L) return(0L)
if (n == 1L || n == 2L) return(1L)
x = rep(1L, n)
for (i in 3L:n) {
x[[i]] = x[[i - 1]] + x[[i - 2]]
}
return(x[[n]])
}Create function which will handle requests.
fib_handler = function(.req, .res) {
n = as.integer(.req$parameters_query[["n"]])
if (length(n) == 0L || is.na(n)) {
raise(HTTPError$bad_request())
}
.res$set_body(as.character(calc_fib(n)))
.res$set_content_type("text/plain")
}You may have noticed strange .req and .res
argument names. Starting from RestRserve v0.4.0 these
“reserved” names allows to benefit from autocomplete:
<img src=“https://cdn.rexy.ai/assets/req-res.gif” width=“640” style=“vertical-align:bottom”, alt=“request-response autocomplete gif”>
Technically .req and .res are just empty
instances of ?Request and ?Response classes
exported by RestRserve in order to make autocomplete
work.
Now we can test our application without starting it:
request = Request$new(path = "/fib", parameters_query = list(n = 10))
response = app$process_request(request)
cat("Response status:", response$status)
#> Response status: 200 OK
cat("Response body:", response$body)
#> Response body: 55It is generally a good idea to write unit tests against application. One can use a common framework such as tinytest.
Generally it is a good idea to provide documentation along with the API. Convenient way to do that is to supply a openapi specification. This as simple as adding a yaml file as an additional endpoint:
openapi: 3.0.1
info:
title: RestRserve OpenAPI
version: '1.0'
servers:
- url: /
paths:
/fib:
get:
description: Calculates Fibonacci number
parameters:
- name: "n"
description: "x for Fibonnacci number"
in: query
schema:
type: integer
example: 10
required: true
responses:
200:
description: API response
content:
text/plain:
schema:
type: string
example: 5
400:
description: Bad RequestNow all is ready and we can start application with Rserve backend. It will block R session and start listening for incoming requests.