Creates Application object. Application provides an interface for building high-performance REST API by registering R functions as handlers http requests.

Details

There are several advanced options to control how HTTP headers are processed:

There is also an option to switch-off runtime types validation in the Request/Response handlers. This might provide some performance gains, but ultimately leads to less robust applications. Use at your own risk! See options("RestRserve.runtime.asserts")

Public fields

logger

Logger object which records events during request processing. Alternatively user can use loggers from lgr package as a drop-in replacement - Logger methods and loggers created by lgr share function signatures.

content_type

Default response body content type.

HTTPError

Class which raises HTTP errors. Global HTTPError is used by default. In theory user can replace it with his own class (see RestRserve:::HTTPErrorFactory). However we believe in the majority of the cases using HTTPError will be enough.

Active bindings

endpoints

Prints all the registered routes with allowed methods.

Methods


Method new()

Creates Application object.

Usage

Application$new(
  middleware = list(EncodeDecodeMiddleware$new()),
  content_type = "text/plain",
  ...
)

Arguments

middleware

List of Middleware objects.

content_type

Default response body content (media) type. "text/plain" by default.

...

Not used at the moment.


Method add_route()

Adds endpoint and register user-supplied R function as a handler.

Usage

Application$add_route(
  path,
  method,
  FUN,
  match = c("exact", "partial", "regex"),
  ...
)

Arguments

path

Endpoint path.

method

HTTP method. Allowed methods at the moment: GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH.

FUN

User function to handle requests. FUN must take two arguments: first is request (Request) and second is response (Response).
The goal of the user function is to modify response or throw exception (call raise() or stop()).
Both response and request objects modified in-place and internally passed further to RestRserve execution pipeline.

match

Defines how route will be processed. Allowed values:

  • exact - match route as is. Returns 404 if route is not matched.

  • partial - match route as prefix. Returns 404 if prefix are not matched.

  • regex - match route as template. Returns 404 if template pattern not matched.

...

Not used.


Method add_get()

Shorthand to Application$add_route() with GET method.

Usage

Application$add_get(
  path,
  FUN,
  match = c("exact", "partial", "regex"),
  ...,
  add_head = TRUE
)

Arguments

path

Endpoint path.

FUN

User function to handle requests. FUN must take two arguments: first is request (Request) and second is response (Response).
The goal of the user function is to modify response or throw exception (call raise() or stop()).
Both response and request objects modified in-place and internally passed further to RestRserve execution pipeline.

match

Defines how route will be processed. Allowed values:

  • exact - match route as is. Returns 404 if route is not matched.

  • partial - match route as prefix. Returns 404 if prefix are not matched.

  • regex - match route as template. Returns 404 if template pattern not matched.

...

Not used.

add_head

Adds HEAD method.


Method add_post()

Shorthand to Application$add_route() with POST method.

Usage

Application$add_post(path, FUN, match = c("exact", "partial", "regex"), ...)

Arguments

path

Endpoint path.

FUN

User function to handle requests. FUN must take two arguments: first is request (Request) and second is response (Response).
The goal of the user function is to modify response or throw exception (call raise() or stop()).
Both response and request objects modified in-place and internally passed further to RestRserve execution pipeline.

match

Defines how route will be processed. Allowed values:

  • exact - match route as is. Returns 404 if route is not matched.

  • partial - match route as prefix. Returns 404 if prefix are not matched.

  • regex - match route as template. Returns 404 if template pattern not matched.

...

Not used.


Method add_static()

Adds GET method to serve file or directory at file_path.

Usage

Application$add_static(path, file_path, content_type = NULL, ...)

Arguments

path

Endpoint path.

file_path

Path file or directory.

content_type

MIME-type for the content.
If content_type = NULL then MIME code content_type will be inferred automatically (from file extension).
If it will be impossible to guess about file type then content_type will be set to application/octet-stream.

...

Not used.


Method add_openapi()

Adds endpoint to serve OpenAPI description of available methods.

Usage

Application$add_openapi(path = "/openapi.yaml", file_path = "openapi.yaml")

Arguments

path

path Endpoint path.

file_path

Path to the OpenAPI specification file.


Method add_swagger_ui()

Adds endpoint to show Swagger UI.

Usage

Application$add_swagger_ui(
  path = "/swagger",
  path_openapi = "/openapi.yaml",
  use_cdn = TRUE,
  path_swagger_assets = "/__swagger__/",
  file_path = "swagger-ui.html"
)

Arguments

path

path Endpoint path.

path_openapi

Path to the OpenAPI specification file.

use_cdn

Use CDN to load Swagger UI libraries.

path_swagger_assets

Swagger UI asstes endpoint.

file_path

Path to Swagger UI HTML file.


Method append_middleware()

Appends middleware to handlers pipeline.

Usage

Application$append_middleware(mw)

Arguments

mw

Middleware object.


Method process_request()

Process incoming request and generate Response object.

Usage

Application$process_request(request = NULL)

Arguments

request

Request object.
Useful for tests your handlers before deploy application.


Method print()

Prints application details.

Usage

Application$print()


Method clone()

The objects of this class are cloneable with this method.

Usage

Application$clone(deep = FALSE)

Arguments

deep

Whether to make a deep clone.

Examples

# init logger
app_logger = Logger$new()
# set log level for the middleware
app_logger$set_log_level("debug")
# set logger name
app_logger$set_name("MW Logger")
# init middleware to logging
mw = Middleware$new(
  process_request = function(rq, rs) {
    app_logger$info(sprintf("Incomming request (id %s): %s", rq$id, rq$path))
  },
  process_response = function(rq, rs) {
    app_logger$info(sprintf("Outgoing response (id %s): %s", rq$id, rs$status))
  },
  id = "awesome-app-logger"
)

# init application
app = Application$new(middleware = list(mw))

# set internal log level
app$logger$set_log_level("error")

# define simply request handler
status_handler = function(rq, rs) {
  rs$set_body("OK")
  rs$set_content_type("text/plain")
  rs$set_status_code(200L)
}
# add route
app$add_get("/status", status_handler, "exact")

# add static file handler
desc_file = system.file("DESCRIPTION", package = "RestRserve")
# add route
app$add_static("/desc", desc_file, "text/plain")

# define say message handler
say_handler = function(rq, rs) {
  who = rq$parameters_path[["user"]]
  msg = rq$parameters_query[["message"]]
  if (is.null(msg)) msg = "Hello"
  rs$set_body(paste(who, "say", dQuote(msg)))
  rs$set_content_type("text/plain")
  rs$set_status_code(200L)
}
# add route
app$add_get("/say/{user}", say_handler, "regex")

# print application info
app
#> <RestRserve Application>
#>   <Middlewares>
#>  [request][response]: awesome-app-logger
#>   <Endpoints>
#>     HEAD [exact]: /status
#>     HEAD [regex]: /say/{user}
#>     GET [exact]: /status
#>     GET [exact]: /desc
#>     GET [regex]: /say/{user}

# test app
# simulate requests
not_found_rq = Request$new(path = "/no")
status_rq = Request$new(path = "/status")
desc_rq = Request$new(path = "/desc")
say_rq = Request$new(path = "/say/anonym", parameters_query = list("message" = "Hola"))
# process prepared requests
app$process_request(not_found_rq)
#> {"timestamp":"2024-04-18 01:54:44.752187","level":"INFO","name":"MW Logger","pid":3468,"msg":"Incomming request (id a107796a-fd26-11ee-98b2-0050569e8e3c): /no"}
#> {"timestamp":"2024-04-18 01:54:44.755027","level":"INFO","name":"MW Logger","pid":3468,"msg":"Outgoing response (id a107796a-fd26-11ee-98b2-0050569e8e3c): 404 Not Found"}
#> <RestRserve Response>
#>   status code: 404 Not Found
#>   content-type: text/plain
#>   <Headers>
#>     Server: RestRserve/1.2.2; Rserve/1.8.13
app$process_request(status_rq)
#> {"timestamp":"2024-04-18 01:54:44.793391","level":"INFO","name":"MW Logger","pid":3468,"msg":"Incomming request (id a107c0c8-fd26-11ee-98b2-0050569e8e3c): /status"}
#> {"timestamp":"2024-04-18 01:54:44.843766","level":"INFO","name":"MW Logger","pid":3468,"msg":"Outgoing response (id a107c0c8-fd26-11ee-98b2-0050569e8e3c): 200 OK"}
#> <RestRserve Response>
#>   status code: 200 OK
#>   content-type: text/plain
#>   <Headers>
#>     Server: RestRserve/1.2.2; Rserve/1.8.13
app$process_request(desc_rq)
#> {"timestamp":"2024-04-18 01:54:44.869942","level":"INFO","name":"MW Logger","pid":3468,"msg":"Incomming request (id a108015a-fd26-11ee-98b2-0050569e8e3c): /desc"}
#> {"timestamp":"2024-04-18 01:54:44.871164","level":"INFO","name":"MW Logger","pid":3468,"msg":"Outgoing response (id a108015a-fd26-11ee-98b2-0050569e8e3c): 200 OK"}
#> <RestRserve Response>
#>   status code: 200 OK
#>   content-type: text/plain
#>   <Headers>
#>     Server: RestRserve/1.2.2; Rserve/1.8.13
app$process_request(say_rq)
#> {"timestamp":"2024-04-18 01:54:44.874052","level":"INFO","name":"MW Logger","pid":3468,"msg":"Incomming request (id a1084002-fd26-11ee-98b2-0050569e8e3c): /say/anonym"}
#> {"timestamp":"2024-04-18 01:54:44.875389","level":"INFO","name":"MW Logger","pid":3468,"msg":"Outgoing response (id a1084002-fd26-11ee-98b2-0050569e8e3c): 200 OK"}
#> <RestRserve Response>
#>   status code: 200 OK
#>   content-type: text/plain
#>   <Headers>
#>     Server: RestRserve/1.2.2; Rserve/1.8.13

# run app
backend = BackendRserve$new()
# \donttest{
if (interactive()) {
  backend$start(app, 8080)
}
# }