Title: | An API Generator for R |
---|---|
Description: | Gives the ability to automatically generate and serve an HTTP API from R functions using the annotations in the R documentation around your functions. |
Authors: | Barret Schloerke [cre, aut] , Jeff Allen [aut, ccp], Bruno Tremblay [ctb], Frans van Dunné [ctb], Sebastiaan Vandewoude [ctb], Posit Software, PBC [cph, fnd] |
Maintainer: | Barret Schloerke <[email protected]> |
License: | MIT + file LICENSE |
Version: | 1.2.2.9000 |
Built: | 2024-11-14 23:23:38 UTC |
Source: | https://github.com/rstudio/plumber |
This will set the appropriate fields in the Content-Disposition
header value.
To make sure the attachment is used, be sure your serializer eventually calls serializer_headers
as_attachment(value, filename = NULL)
as_attachment(value, filename = NULL)
value |
Response value to be saved |
filename |
File name to use when saving the attachment.
If no |
Object with class "plumber_attachment"
## Not run: # plumber.R #' @get /data #' @serializer csv function() { # will cause the file to be saved as `iris.csv`, not `data` or `data.csv` as_attachment(iris, "iris.csv") } ## End(Not run)
## Not run: # plumber.R #' @get /data #' @serializer csv function() { # will cause the file to be saved as `iris.csv`, not `data` or `data.csv` as_attachment(iris, "iris.csv") } ## End(Not run)
This method allows serializers to return preexec
, postexec
, and aroundexec
() hooks in addition to a serializer.
This is useful for graphics device serializers which need a preexec
and postexec
hook to capture the graphics output.
endpoint_serializer( serializer, preexec_hook = NULL, postexec_hook = NULL, aroundexec_hook = NULL )
endpoint_serializer( serializer, preexec_hook = NULL, postexec_hook = NULL, aroundexec_hook = NULL )
serializer |
Serializer method to be used. This method should already have its initialization arguments applied. |
preexec_hook |
Function to be run directly before a PlumberEndpoint calls its route method. |
postexec_hook |
Function to be run directly after a PlumberEndpoint calls its route method. |
aroundexec_hook |
Function to be run around a PlumberEndpoint call. Must handle a |
preexec
and postexec
hooks happened directly before and after a route is executed.
These hooks are specific to a single PlumberEndpoint's route calculation.
# The definition of `serializer_device` returns # * a `serializer_content_type` serializer # * `aroundexec` hook print(serializer_device)
# The definition of `serializer_device` returns # * a `serializer_content_type` serializer # * `aroundexec` hook print(serializer_device)
This function is used when a filter is done processing a request and wishes to pass control off to the next handler in the chain. If this is not called by a filter, the assumption is that the filter fully handled the request itself and no other filters or endpoints should be evaluated for this request.
forward()
forward()
Request character set
get_character_set(content_type = NULL)
get_character_set(content_type = NULL)
content_type |
Request Content-Type header |
Default to UTF-8
. Otherwise return charset
defined in request header.
Returns the file at the given path as the response. If you want an endpoint to return a file as an attachment for user to download see as_attachment()
.
include_file(file, res, content_type = getContentType(tools::file_ext(file))) include_html(file, res) include_md(file, res, format = NULL) include_rmd(file, res, format = NULL)
include_file(file, res, content_type = getContentType(tools::file_ext(file))) include_html(file, res) include_md(file, res, format = NULL) include_rmd(file, res, format = NULL)
file |
The path to the file to return |
res |
The response object into which we'll write |
content_type |
If provided, the given value will be sent as the
|
format |
Passed as the |
include_html
will merely return the file with the proper
content_type
for HTML. include_md
and include_rmd
will
process the given markdown file through rmarkdown::render
and return
the resultant HTML as a response.
Determine if Plumber object
is_plumber(pr)
is_plumber(pr)
pr |
Hopefully a |
Logical value if pr
inherits from Plumber
is_plumber(Plumber$new()) # TRUE is_plumber(list()) # FALSE
is_plumber(Plumber$new()) # TRUE is_plumber(list()) # FALSE
There are a number of global options that affect Plumber's behavior. These can
be set globally with options()
or with options_plumber()
. Options set using
options_plumber()
should not include the plumber.
prefix. Alternatively,
environment variable can be used to set plumber options using uppercase and
underscores (i.e. to set plumber.apiHost
you can set environment variable PLUMBER_APIHOST
).
options_plumber( ..., port = getOption("plumber.port"), docs = getOption("plumber.docs"), docs.callback = getOption("plumber.docs.callback"), trailingSlash = getOption("plumber.trailingSlash"), methodNotAllowed = getOption("plumber.methodNotAllowed"), apiURL = getOption("plumber.apiURL"), apiScheme = getOption("plumber.apiScheme"), apiHost = getOption("plumber.apiHost"), apiPort = getOption("plumber.apiPort"), apiPath = getOption("plumber.apiPath"), maxRequestSize = getOption("plumber.maxRequestSize"), sharedSecret = getOption("plumber.sharedSecret"), legacyRedirects = getOption("plumber.legacyRedirects") ) get_option_or_env(x, default = NULL)
options_plumber( ..., port = getOption("plumber.port"), docs = getOption("plumber.docs"), docs.callback = getOption("plumber.docs.callback"), trailingSlash = getOption("plumber.trailingSlash"), methodNotAllowed = getOption("plumber.methodNotAllowed"), apiURL = getOption("plumber.apiURL"), apiScheme = getOption("plumber.apiScheme"), apiHost = getOption("plumber.apiHost"), apiPort = getOption("plumber.apiPort"), apiPath = getOption("plumber.apiPath"), maxRequestSize = getOption("plumber.maxRequestSize"), sharedSecret = getOption("plumber.sharedSecret"), legacyRedirects = getOption("plumber.legacyRedirects") ) get_option_or_env(x, default = NULL)
... |
Ignored. Should be empty |
port , docs , docs.callback , trailingSlash , methodNotAllowed , apiScheme , apiHost , apiPort , apiPath , apiURL , maxRequestSize , sharedSecret , legacyRedirects
|
See details |
x |
a character string holding an option name. |
default |
if the specified option is not set in the options list, this value is returned. This facilitates retrieving an option and checking whether it is set and setting it separately if not. |
plumber.port
Port Plumber will attempt to use to start http server.
If the port is already in use, server will not be able to start. Defaults to NULL
.
plumber.docs
Name of the visual documentation interface to use. Defaults to TRUE
, which will use "swagger"
.
plumber.docs.callback
A function. Called with
a single parameter corresponding to the visual documentation url after Plumber server is ready. This can be used
by RStudio to open the docs when then API is ran from the editor. Defaults to option NULL
.
plumber.trailingSlash
Logical value which allows the router to redirect any request
that has a matching route with a trailing slash. For example, if set to TRUE
and the
GET route /test/
existed, then a GET request of /test?a=1
would redirect to
/test/?a=1
. Defaults to FALSE
. This option will default to TRUE
in a future release.
plumber.methodNotAllowed
Logical value which allows the router to notify that an
unavailable method was requested, but a different request method is allowed. For example,
if set to TRUE
and the GET route /test
existed, then a POST request of /test
would
receive a 405 status and the allowed methods. Defaults to TRUE
.
plumber.apiURL
Server urls for OpenAPI Specification respecting
pattern scheme://host:port/path
. Other api*
options will be ignored when set.
plumber.apiScheme
Scheme used to build OpenAPI url and server url for
OpenAPI Specification. Defaults to http
, or an empty string
when used outside a running router.
plumber.apiHost
Host used to build docs url and server url for
OpenAPI Specification. Defaults to host
defined by run
method, or an empty string
when used outside a running router.
plumber.apiPort
Port used to build OpenAPI url and server url for
OpenAPI Specification. Defaults to port
defined by run
method, or an empty string
when used outside a running router.
plumber.apiPath
Path used to build OpenAPI url and server url for OpenAPI Specification. Defaults to an empty string.
plumber.maxRequestSize
Maximum length in bytes of request body. Body larger
than maximum are rejected with http error 413. 0
means unlimited size. Defaults to 0
.
plumber.sharedSecret
Shared secret used to filter incoming request.
When NULL
, secret is not validated. Otherwise, Plumber compares secret with http header
PLUMBER_SHARED_SECRET
. Failure to match results in http error 400. Defaults to NULL
.
plumber.legacyRedirects
Plumber will redirect legacy route /__swagger__/
and
/__swagger__/index.html
to ../__docs__/
and ../__docs__/index.html
. You can disable this
by settings this option to FALSE
. Defaults to TRUE
The complete, prior set of options()
values.
If a particular parameter is not supplied, it will return the current value.
If no parameters are supplied, all returned values will be the current options()
values.
Parsers are used in Plumber to transform request body received by the API. Extra parameters may be provided to parser functions when enabling them on router. This will allow for non-default behavior.
parser_form() parser_json(...) parser_geojson(...) parser_text(parse_fn = identity) parser_yaml(...) parser_csv(...) parser_tsv(...) parser_read_file(read_fn = readLines) parser_rds(...) parser_feather(...) parser_parquet(...) parser_octet() parser_multi() parser_none()
parser_form() parser_json(...) parser_geojson(...) parser_text(parse_fn = identity) parser_yaml(...) parser_csv(...) parser_tsv(...) parser_read_file(read_fn = readLines) parser_rds(...) parser_feather(...) parser_parquet(...) parser_octet() parser_multi() parser_none()
... |
parameters supplied to the appropriate internal function |
parse_fn |
function to further decode a text string into an object |
read_fn |
function used to read a the content of a file. Ex: |
Parsers are optional. When unspecified, only default endpoint parsers are enabled.
You can use @parser NAME
tag to enable parser on endpoint.
Multiple parsers can be enabled on the same endpoint using multiple @parser NAME
tags.
User should be aware that rds
parsing should only be done from a
trusted source. Do not accept rds
files blindly.
See registered_parsers()
for a list of registered parsers names.
parser_form()
: Form query string parser
parser_json()
: JSON parser. See jsonlite::parse_json()
for more details. (Defaults to using simplifyVectors = TRUE
)
parser_geojson()
: GeoJSON parser. See geojsonsf::geojson_sf()
for more details.
parser_text()
: Helper parser to parse plain text
parser_yaml()
: YAML parser. See yaml::yaml.load()
for more details.
parser_csv()
: CSV parser. See readr::read_csv()
for more details.
parser_tsv()
: TSV parser. See readr::read_tsv()
for more details.
parser_read_file()
: Helper parser that writes the binary body to a file and reads it back again using read_fn
.
This parser should be used when reading from a file is required.
parser_rds()
: RDS parser. See readRDS()
for more details.
parser_feather()
: feather parser. See arrow::read_feather()
for more details.
parser_parquet()
: parquet parser. See arrow::read_parquet()
for more details.
parser_octet()
: Octet stream parser. Returns the raw content.
parser_multi()
: Multi part parser. This parser will then parse each individual body with its respective parser. When this parser is used, req$body
will contain the updated output from webutils::parse_multipart()
by adding the parsed
output to each part. Each part may contain detailed information, such as name
(required), content_type
, content_disposition
, filename
, (raw, original) value
, and parsed
(parsed value
). When performing Plumber route argument matching, each multipart part will match its name
to the parsed
content.
parser_none()
: No parser. Will not process the postBody.
## Not run: # Overwrite `text/json` parsing behavior to not allow JSON vectors to be simplified #* @parser json list(simplifyVector = FALSE) # Activate `rds` parser in a multipart request #* @parser multi #* @parser rds pr <- Plumber$new() pr$handle("GET", "/upload", function(rds) {rds}, parsers = c("multi", "rds")) ## End(Not run)
## Not run: # Overwrite `text/json` parsing behavior to not allow JSON vectors to be simplified #* @parser json list(simplifyVector = FALSE) # Activate `rds` parser in a multipart request #* @parser multi #* @parser rds pr <- Plumber$new() pr$handle("GET", "/upload", function(rds) {rds}, parsers = c("multi", "rds")) ## End(Not run)
Process a Plumber API
plumb(file = NULL, dir = ".")
plumb(file = NULL, dir = ".")
file |
The file to parse as the plumber router definition. |
dir |
The directory containing the |
API routers are the core request handler in plumber. A router is responsible for taking an incoming request, submitting it through the appropriate filters and eventually to a corresponding endpoint, if one is found.
See the Programmatic Usage article for additional details on the methods available on this object.
So that packages can ship multiple plumber routers, users should store their Plumber APIs
in the inst
subfolder plumber
(./inst/plumber/API_1/plumber.R
).
plumb_api(package = NULL, name = NULL, edit = FALSE) available_apis(package = NULL)
plumb_api(package = NULL, name = NULL, edit = FALSE) available_apis(package = NULL)
package |
Package to inspect |
name |
Name of the package folder to |
edit |
Whether or not to open the API source code for viewing / editing |
To view all available Plumber APIs across all packages, please call available_apis()
.
A package
value may be provided to only display a particular package's Plumber APIs.
A Plumber
object. If either package
or name
is null, the appropriate available_apis()
will be returned.
plumb_api()
: plumb()
s a package's Plumber API. Returns a Plumber
router object
available_apis()
: Displays all available package Plumber APIs. Returns a data.frame
of package
, name
, and source_directory
information.
Package Plumber Router
Package Plumber Router
Routers are the core request handler in plumber. A router is responsible for taking an incoming request, submitting it through the appropriate filters and eventually to a corresponding endpoint, if one is found.
See the Programmatic Usage article for additional details on the methods available on this object.
plumber::Hookable
-> Plumber
flags
For internal use only
endpoints
Plumber router endpoints read-only
filters
Plumber router filters read-only
mounts
Plumber router mounts read-only
environment
Plumber router environment read-only
routes
Plumber router routes read-only
new()
Create a new Plumber
router
Plumber$new(file = NULL, filters = defaultPlumberFilters, envir)
file
path to file to plumb
filters
a list of Plumber filters
envir
an environment to be used as the enclosure for the routers execution
A new Plumber
router
run()
Start a server using Plumber
object.
See also: pr_run()
Plumber$run( host = "127.0.0.1", port = get_option_or_env("plumber.port", NULL), swagger = deprecated(), debug = missing_arg(), swaggerCallback = missing_arg(), ..., docs = missing_arg(), quiet = FALSE )
host
a string that is a valid IPv4 or IPv6 address that is owned by this server, which the application will listen on. "0.0.0.0" represents all IPv4 addresses and "::/0" represents all IPv6 addresses.
port
a number or integer that indicates the server port that should be listened on. Note that on most Unix-like systems including Linux and Mac OS X, port numbers smaller than 1025 require root privileges.
This value does not need to be explicitly assigned. To explicitly set it, see options_plumber()
.
swagger
Deprecated. Please use docs
instead. See $setDocs(docs)
or $setApiSpec()
for more customization.
debug
If TRUE
, it will provide more insight into your API errors. Using this value will only last for the duration of the run. If a $setDebug()
has not been called, debug
will default to interactive()
at $run()
time. See $setDebug()
for more details.
swaggerCallback
An optional single-argument function that is
called back with the URL to an OpenAPI user interface when one becomes
ready. If missing, defaults to information previously set with $setDocsCallback()
.
This value will only be used while running the router.
...
Should be empty.
docs
Visual documentation value to use while running the API.
This value will only be used while running the router.
If missing, defaults to information previously set with setDocs()
.
For more customization, see $setDocs()
or pr_set_docs()
for examples.
quiet
If TRUE
, don't print routine startup messages.
mount()
Mount a Plumber router
Plumber routers can be “nested” by mounting one into another
using the mount()
method. This allows you to compartmentalize your API
by paths which is a great technique for decomposing large APIs into smaller files.
See also: pr_mount()
Plumber$mount(path, router)
path
a character string. Where to mount router.
router
a Plumber router. Router to be mounted.
\dontrun{ root <- pr() users <- Plumber$new("users.R") root$mount("/users", users) products <- Plumber$new("products.R") root$mount("/products", products) }
unmount()
Unmount a Plumber router
Plumber$unmount(path)
path
a character string. Where to unmount router.
registerHook()
Register a hook
Plumber routers support the notion of "hooks" that can be registered to execute some code at a particular point in the lifecycle of a request. Plumber routers currently support four hooks:
preroute(data, req, res)
postroute(data, req, res, value)
preserialize(data, req, res, value)
postserialize(data, req, res, value)
In all of the above you have access to a disposable environment in the data
parameter that is created as a temporary data store for each request. Hooks
can store temporary data in these hooks that can be reused by other hooks
processing this same request.
One feature when defining hooks in Plumber routers is the ability to modify
the returned value. The convention for such hooks is: any function that accepts
a parameter named value
is expected to return the new value. This could
be an unmodified version of the value that was passed in, or it could be a
mutated value. But in either case, if your hook accepts a parameter
named value
, whatever your hook returns will be used as the new value
for the response.
You can add hooks using the registerHook
method, or you can add multiple
hooks at once using the registerHooks
method which takes a name list in
which the names are the names of the hooks, and the values are the
handlers themselves.
See also: pr_hook()
, pr_hooks()
Plumber$registerHook( stage = c("preroute", "postroute", "preserialize", "postserialize", "exit"), handler )
stage
a character string. Point in the lifecycle of a request.
handler
a hook function.
\dontrun{ pr <- pr() pr$registerHook("preroute", function(req){ cat("Routing a request for", req$PATH_INFO, "...\n") }) pr$registerHooks(list( preserialize=function(req, value){ print("About to serialize this value:") print(value) # Must return the value since we took one in. Here we're not choosing # to mutate it, but we could. value }, postserialize=function(res){ print("We serialized the value as:") print(res$body) } )) pr$handle("GET", "/", function(){ 123 }) }
handle()
Define endpoints
The “handler” functions that you define in these handle calls are identical to the code you would have defined in your plumber.R file if you were using annotations to define your API. The handle() method takes additional arguments that allow you to control nuanced behavior of the endpoint like which filter it might preempt or which serializer it should use.
See also: pr_handle()
, pr_get()
, pr_post()
, pr_put()
, pr_delete()
Plumber$handle( methods, path, handler, preempt, serializer, parsers, endpoint, ... )
methods
a character string. http method.
path
a character string. Api endpoints
handler
a handler function.
preempt
a preempt function.
serializer
a serializer function.
parsers
a named list of parsers.
endpoint
a PlumberEndpoint
object.
...
additional arguments for PlumberEndpoint new
method (namely lines
, params
, comments
, responses
and tags
. Excludes envir
).
\dontrun{ pr <- pr() pr$handle("GET", "/", function(){ "<html><h1>Programmatic Plumber!</h1></html>" }, serializer=plumber::serializer_html()) }
removeHandle()
Remove endpoints
Plumber$removeHandle(methods, path, preempt = NULL)
methods
a character string. http method.
path
a character string. Api endpoints
preempt
a preempt function.
print()
Print representation of plumber router.
Plumber$print(prefix = "", topLevel = TRUE, ...)
prefix
a character string. Prefix to append to representation.
topLevel
a logical value. When method executed on top level
router, set to TRUE
.
...
additional arguments for recursive calls
A terminal friendly representation of a plumber router.
serve()
Serve a request
Plumber$serve(req, res)
req
request object
res
response object
route()
Route a request
Plumber$route(req, res)
req
request object
res
response object
call()
httpuv interface call function. (Required for httpuv)
Plumber$call(req)
req
request object
onHeaders()
httpuv interface onHeaders function. (Required for httpuv)
Plumber$onHeaders(req)
req
request object
onWSOpen()
httpuv interface onWSOpen function. (Required for httpuv)
Plumber$onWSOpen(ws)
ws
WebSocket object
setSerializer()
Sets the default serializer of the router.
See also: pr_set_serializer()
Plumber$setSerializer(serializer)
serializer
a serializer function
\dontrun{ pr <- pr() pr$setSerializer(serializer_unboxed_json()) }
setParsers()
Sets the default parsers of the router. Initialized to c("json", "form", "text", "octet", "multi")
Plumber$setParsers(parsers)
parsers
Can be one of:
A NULL
value
A character vector of parser names
A named list()
whose keys are parser names names and values are arguments to be applied with do.call()
A TRUE
value, which will default to combining all parsers. This is great for seeing what is possible, but not great for security purposes
If the parser name "all"
is found in any character value or list name, all remaining parsers will be added.
When using a list, parser information already defined will maintain their existing argument values. All remaining parsers will use their default arguments.
Example:
# provide a character string parsers = "json" # provide a named list with no arguments parsers = list(json = list()) # provide a named list with arguments; include `rds` parsers = list(json = list(simplifyVector = FALSE), rds = list()) # default plumber parsers parsers = c("json", "form", "text", "octet", "multi")
set404Handler()
Sets the handler that gets called if an incoming request can’t be served by any filter, endpoint, or sub-router.
See also: pr_set_404()
Plumber$set404Handler(fun)
fun
a handler function.
\dontrun{ pr <- pr() pr$set404Handler(function(req, res) {cat(req$PATH_INFO)}) }
setErrorHandler()
Sets the error handler which gets invoked if any filter or endpoint generates an error.
See also: pr_set_404()
Plumber$setErrorHandler(fun)
fun
a handler function.
\dontrun{ pr <- pr() pr$setErrorHandler(function(req, res, err) { message("Found error: ") str(err) }) }
setDocs()
Set visual documentation to use for API
See also: pr_set_docs()
, register_docs()
, registered_docs()
Plumber$setDocs(docs = get_option_or_env("plumber.docs", TRUE), ...)
docs
a character value or a logical value. See pr_set_docs()
for examples.
If using options_plumber()
, the value must be set before initializing your Plumber router.
...
Arguments for the visual documentation. See each visual documentation package for further details.
setDocsCallback()
Set a callback to notify where the API's visual documentation is located.
When set, it will be called with a character string corresponding to the API docs url. This allows RStudio to locate visual documentation.
If using options_plumber()
, the value must be set before initializing your Plumber router.
See also: pr_set_docs_callback()
Plumber$setDocsCallback( callback = get_option_or_env("plumber.docs.callback", NULL) )
callback
a callback function for taking action on the docs url. (Also accepts NULL
values to disable the callback
.)
setDebug()
Set debug value to include error messages.
See also: $getDebug()
and pr_set_debug()
Plumber$setDebug(debug = interactive())
debug
TRUE
provides more insight into your API errors.
getDebug()
Retrieve the debug
value. If it has never been set, the result of interactive()
will be used.
See also: $getDebug()
and pr_set_debug()
Plumber$getDebug()
filter()
Add a filter to plumber router
See also: pr_filter()
Plumber$filter(name, expr, serializer)
name
a character string. Name of filter
expr
an expr that resolve to a filter function or a filter function
serializer
a serializer function
setApiSpec()
Allows to modify router autogenerated OpenAPI Specification
Note, the returned value will be sent through serializer_unboxed_json()
which will turn all length 1 vectors into atomic values.
To force a vector to serialize to an array of size 1, be sure to call as.list()
on your value. list()
objects are always serialized to an array value.
See also: pr_set_api_spec()
Plumber$setApiSpec(api = NULL)
api
This can be
an OpenAPI Specification formatted list object
a function that accepts the OpenAPI Specification autogenerated by plumber
and returns a OpenAPI Specification formatted list object.
a path to an OpenAPI Specification
The value returned will not be validated for OAS compatibility.
getApiSpec()
Retrieve OpenAPI file
Plumber$getApiSpec()
addEndpoint()
addEndpoint has been deprecated in v0.4.0 and will be removed in a coming release. Please use handle()
instead.
Plumber$addEndpoint( verbs, path, expr, serializer, processors, preempt = NULL, params = NULL, comments )
verbs
verbs
path
path
expr
expr
serializer
serializer
processors
processors
preempt
preempt
params
params
comments
comments
addAssets()
addAssets has been deprecated in v0.4.0 and will be removed in a coming release. Please use mount
and PlumberStatic$new()
instead.
Plumber$addAssets(dir, path = "/public", options = list())
dir
dir
path
path
options
options
addFilter()
$addFilter()
has been deprecated in v0.4.0 and will be removed in a coming release. Please use $filter()
instead.
Plumber$addFilter(name, expr, serializer, processors)
name
name
expr
expr
serializer
serializer
processors
processors
addGlobalProcessor()
$addGlobalProcessor()
has been deprecated in v0.4.0 and will be removed in a coming release. Please use $registerHook
(s) instead.
Plumber$addGlobalProcessor(proc)
proc
proc
openAPIFile()
Deprecated. Retrieve OpenAPI file
Plumber$openAPIFile()
swaggerFile()
Deprecated. Retrieve OpenAPI file
Plumber$swaggerFile()
clone()
The objects of this class are cloneable with this method.
Plumber$clone(deep = FALSE)
deep
Whether to make a deep clone.
pr()
,
pr_run()
,
pr_get()
, pr_post()
,
pr_mount()
,
pr_hook()
, pr_hooks()
, pr_cookie()
,
pr_filter()
,
pr_set_api_spec()
, pr_set_docs()
,
pr_set_serializer()
, pr_set_parsers()
,
pr_set_404()
, pr_set_error()
,
pr_set_debug()
,
pr_set_docs_callback()
## ------------------------------------------------ ## Method `Plumber$mount` ## ------------------------------------------------ ## Not run: root <- pr() users <- Plumber$new("users.R") root$mount("/users", users) products <- Plumber$new("products.R") root$mount("/products", products) ## End(Not run) ## ------------------------------------------------ ## Method `Plumber$registerHook` ## ------------------------------------------------ ## Not run: pr <- pr() pr$registerHook("preroute", function(req){ cat("Routing a request for", req$PATH_INFO, "...\n") }) pr$registerHooks(list( preserialize=function(req, value){ print("About to serialize this value:") print(value) # Must return the value since we took one in. Here we're not choosing # to mutate it, but we could. value }, postserialize=function(res){ print("We serialized the value as:") print(res$body) } )) pr$handle("GET", "/", function(){ 123 }) ## End(Not run) ## ------------------------------------------------ ## Method `Plumber$handle` ## ------------------------------------------------ ## Not run: pr <- pr() pr$handle("GET", "/", function(){ "<html><h1>Programmatic Plumber!</h1></html>" }, serializer=plumber::serializer_html()) ## End(Not run) ## ------------------------------------------------ ## Method `Plumber$setSerializer` ## ------------------------------------------------ ## Not run: pr <- pr() pr$setSerializer(serializer_unboxed_json()) ## End(Not run) ## ------------------------------------------------ ## Method `Plumber$set404Handler` ## ------------------------------------------------ ## Not run: pr <- pr() pr$set404Handler(function(req, res) {cat(req$PATH_INFO)}) ## End(Not run) ## ------------------------------------------------ ## Method `Plumber$setErrorHandler` ## ------------------------------------------------ ## Not run: pr <- pr() pr$setErrorHandler(function(req, res, err) { message("Found error: ") str(err) }) ## End(Not run)
## ------------------------------------------------ ## Method `Plumber$mount` ## ------------------------------------------------ ## Not run: root <- pr() users <- Plumber$new("users.R") root$mount("/users", users) products <- Plumber$new("products.R") root$mount("/products", products) ## End(Not run) ## ------------------------------------------------ ## Method `Plumber$registerHook` ## ------------------------------------------------ ## Not run: pr <- pr() pr$registerHook("preroute", function(req){ cat("Routing a request for", req$PATH_INFO, "...\n") }) pr$registerHooks(list( preserialize=function(req, value){ print("About to serialize this value:") print(value) # Must return the value since we took one in. Here we're not choosing # to mutate it, but we could. value }, postserialize=function(res){ print("We serialized the value as:") print(res$body) } )) pr$handle("GET", "/", function(){ 123 }) ## End(Not run) ## ------------------------------------------------ ## Method `Plumber$handle` ## ------------------------------------------------ ## Not run: pr <- pr() pr$handle("GET", "/", function(){ "<html><h1>Programmatic Plumber!</h1></html>" }, serializer=plumber::serializer_html()) ## End(Not run) ## ------------------------------------------------ ## Method `Plumber$setSerializer` ## ------------------------------------------------ ## Not run: pr <- pr() pr$setSerializer(serializer_unboxed_json()) ## End(Not run) ## ------------------------------------------------ ## Method `Plumber$set404Handler` ## ------------------------------------------------ ## Not run: pr <- pr() pr$set404Handler(function(req, res) {cat(req$PATH_INFO)}) ## End(Not run) ## ------------------------------------------------ ## Method `Plumber$setErrorHandler` ## ------------------------------------------------ ## Not run: pr <- pr() pr$setErrorHandler(function(req, res, err) { message("Found error: ") str(err) }) ## End(Not run)
Plumber Endpoint
Plumber Endpoint
Defines a terminal handler in a Plumber router.
Parameters values are obtained from parsing blocks of lines in a plumber file. They can also be provided manually for historical reasons.
plumber::Hookable
-> plumber::PlumberStep
-> PlumberEndpoint
verbs
a character vector. http methods. For historical reasons we have to accept multiple verbs for a single path. Now it's simpler to just parse each separate verb/path into its own endpoint, so we just do that.
path
a character string. endpoint path
comments
endpoint comments
description
endpoint description
responses
endpoint responses
params
endpoint parameters
tags
endpoint tags
parsers
step allowed parsers
getTypedParams()
retrieve endpoint typed parameters
PlumberEndpoint$getTypedParams()
canServe()
ability to serve request
PlumberEndpoint$canServe(req)
req
a request object
a logical. TRUE
when endpoint can serve request.
matchesPath()
determines if route matches requested path
PlumberEndpoint$matchesPath(path)
path
a url path
a logical. TRUE
when endpoint matches the requested path.
new()
Create a new PlumberEndpoint
object
PlumberEndpoint$new( verbs, path, expr, envir, serializer, parsers, lines, params, comments, description, responses, tags, srcref )
verbs
Endpoint verb Ex: "GET"
, "POST"
path
Endpoint path. Ex: "/index.html"
, "/foo/bar/baz"
expr
Endpoint function or expression that evaluates to a function.
envir
Endpoint environment
serializer
Endpoint serializer. Ex: serializer_json()
parsers
Can be one of:
A NULL
value
A character vector of parser names
A named list()
whose keys are parser names names and values are arguments to be applied with do.call()
A TRUE
value, which will default to combining all parsers. This is great for seeing what is possible, but not great for security purposes
If the parser name "all"
is found in any character value or list name, all remaining parsers will be added.
When using a list, parser information already defined will maintain their existing argument values. All remaining parsers will use their default arguments.
Example:
# provide a character string parsers = "json" # provide a named list with no arguments parsers = list(json = list()) # provide a named list with arguments; include `rds` parsers = list(json = list(simplifyVector = FALSE), rds = list()) # default plumber parsers parsers = c("json", "form", "text", "octet", "multi")
lines
Endpoint block
params
Endpoint params
comments, description, responses, tags
Values to be used within the OpenAPI Spec
srcref
srcref
attribute from block
A new PlumberEndpoint
object
getPathParams()
retrieve endpoint path parameters
PlumberEndpoint$getPathParams(path)
path
endpoint path
getFunc()
retrieve endpoint function
PlumberEndpoint$getFunc()
getFuncParams()
retrieve endpoint expression parameters
PlumberEndpoint$getFuncParams()
getEndpointParams()
retrieve endpoint defined parameters
PlumberEndpoint$getEndpointParams()
setPath()
Updates $path
with a sanitized path
and updates the internal path meta-data
PlumberEndpoint$setPath(path)
path
Path to set $path
. If missing a beginning slash, one will be added.
clone()
The objects of this class are cloneable with this method.
PlumberEndpoint$clone(deep = FALSE)
deep
Whether to make a deep clone.
Static file router
Static file router
Creates a router that is backed by a directory of files on disk.
plumber::Hookable
-> plumber::Plumber
-> PlumberStatic
plumber::Hookable$registerHooks()
plumber::Plumber$addAssets()
plumber::Plumber$addEndpoint()
plumber::Plumber$addFilter()
plumber::Plumber$addGlobalProcessor()
plumber::Plumber$call()
plumber::Plumber$filter()
plumber::Plumber$getApiSpec()
plumber::Plumber$getDebug()
plumber::Plumber$handle()
plumber::Plumber$mount()
plumber::Plumber$onHeaders()
plumber::Plumber$onWSOpen()
plumber::Plumber$openAPIFile()
plumber::Plumber$registerHook()
plumber::Plumber$removeHandle()
plumber::Plumber$route()
plumber::Plumber$run()
plumber::Plumber$serve()
plumber::Plumber$set404Handler()
plumber::Plumber$setApiSpec()
plumber::Plumber$setDebug()
plumber::Plumber$setDocs()
plumber::Plumber$setDocsCallback()
plumber::Plumber$setErrorHandler()
plumber::Plumber$setParsers()
plumber::Plumber$setSerializer()
plumber::Plumber$swaggerFile()
plumber::Plumber$unmount()
new()
Create a new PlumberStatic
router
PlumberStatic$new(direc, options)
direc
a path to an asset directory.
options
options to be evaluated in the PlumberStatic
router environment
A new PlumberStatic
router
print()
Print representation of PlumberStatic()
router.
PlumberStatic$print(prefix = "", topLevel = TRUE, ...)
prefix
a character string. Prefix to append to representation.
topLevel
a logical value. When method executed on top level
router, set to TRUE
.
...
additional arguments for recursive calls
A terminal friendly representation of a PlumberStatic()
router.
clone()
The objects of this class are cloneable with this method.
PlumberStatic$clone(deep = FALSE)
deep
Whether to make a deep clone.
an object representing a step in the lifecycle of the treatment of a request by a plumber router.
plumber::Hookable
-> PlumberStep
srcref
from step block
lines
lines from step block
serializer
step serializer function
new()
Create a new PlumberStep()
object
PlumberStep$new(expr, envir, lines, serializer, srcref)
expr
step expr
envir
step environment
lines
step block
serializer
step serializer
srcref
srcref
attribute from block
A new PlumberStep
object
exec()
step execution function
PlumberStep$exec(req, res)
req, res
Request and response objects created by a Plumber request
registerHook()
step hook registration method
PlumberStep$registerHook( stage = c("preexec", "postexec", "aroundexec"), handler )
stage
a character string.
handler
a step handler function.
clone()
The objects of this class are cloneable with this method.
PlumberStep$clone(deep = FALSE)
deep
Whether to make a deep clone.
Create a new Plumber router
pr( file = NULL, filters = defaultPlumberFilters, envir = new.env(parent = .GlobalEnv) )
pr( file = NULL, filters = defaultPlumberFilters, envir = new.env(parent = .GlobalEnv) )
file |
Path to file to plumb |
filters |
A list of Plumber filters |
envir |
An environment to be used as the enclosure for the routers execution |
A new Plumber
router
## Not run: pr() %>% pr_run() ## End(Not run)
## Not run: pr() %>% pr_run() ## End(Not run)
plumber
uses the crypto R package sodium
, to encrypt/decrypt
req$session
information for each server request.
pr_cookie( pr, key, name = "plumber", expiration = FALSE, http = TRUE, secure = FALSE, same_site = FALSE, path = NULL )
pr_cookie( pr, key, name = "plumber", expiration = FALSE, http = TRUE, secure = FALSE, same_site = FALSE, path = NULL )
pr |
A Plumber API. Note: The supplied Plumber API object will also be updated in place as well as returned by the function. |
key |
The secret key to use. This must be consistent across all R sessions
where you want to save/restore encrypted cookies. It should be produced using
|
name |
The name of the cookie in the user's browser. |
expiration |
A number representing the number of seconds into the future
before the cookie expires or a |
http |
Boolean that adds the |
secure |
Boolean that adds the |
same_site |
A character specifying the SameSite policy to attach to the cookie.
If specified, one of the following values should be given: "Strict", "Lax", or "None".
If "None" is specified, then the |
path |
The URI path that the cookie will be available in future requests.
Defaults to the request URI. Set to |
The cookie's secret encryption key
value must be consistent to maintain
req$session
information between server restarts.
While it is very quick to get started with user session cookies using
plumber
, please exercise precaution when storing secure key information.
If a malicious person were to gain access to the secret key
, they would
be able to eavesdrop on all req$session
information and/or tamper with
req$session
information being processed.
Please:
Do NOT store keys in source control.
Do NOT store keys on disk with permissions that allow it to be accessed by everyone.
Do NOT store keys in databases which can be queried by everyone.
Instead, please:
Use a key management system, such as 'keyring' (preferred)
Store the secret in a file on disk with appropriately secure permissions,
such as "user read only" (Sys.chmod("myfile.txt", mode = "0600")
),
to prevent others from reading it.
Examples of both of these solutions are done in the Examples section.
'sodium': R bindings to 'libsodium'
'libsodium': A Modern and Easy-to-Use Crypto Library
'keyring': Access the system credential store from R
Set-Cookie flags: Descriptions of different flags for Set-Cookie
Cross-site scripting: A security exploit which allows an attacker to inject into a website malicious client-side code
## Not run: ## Set secret key using `keyring` (preferred method) keyring::key_set_with_value("plumber_api", password = plumber::random_cookie_key()) pr() %>% pr_cookie( keyring::key_get("plumber_api"), name = "counter" ) %>% pr_get("/sessionCounter", function(req) { count <- 0 if (!is.null(req$session$counter)){ count <- as.numeric(req$session$counter) } req$session$counter <- count + 1 return(paste0("This is visit #", count)) }) %>% pr_run() #### -------------------------------- ### ## Save key to a local file pswd_file <- "normal_file.txt" cat(plumber::random_cookie_key(), file = pswd_file) # Make file read-only Sys.chmod(pswd_file, mode = "0600") pr() %>% pr_cookie( readLines(pswd_file, warn = FALSE), name = "counter" ) %>% pr_get("/sessionCounter", function(req) { count <- 0 if (!is.null(req$session$counter)){ count <- as.numeric(req$session$counter) } req$session$counter <- count + 1 return(paste0("This is visit #", count)) }) %>% pr_run() ## End(Not run)
## Not run: ## Set secret key using `keyring` (preferred method) keyring::key_set_with_value("plumber_api", password = plumber::random_cookie_key()) pr() %>% pr_cookie( keyring::key_get("plumber_api"), name = "counter" ) %>% pr_get("/sessionCounter", function(req) { count <- 0 if (!is.null(req$session$counter)){ count <- as.numeric(req$session$counter) } req$session$counter <- count + 1 return(paste0("This is visit #", count)) }) %>% pr_run() #### -------------------------------- ### ## Save key to a local file pswd_file <- "normal_file.txt" cat(plumber::random_cookie_key(), file = pswd_file) # Make file read-only Sys.chmod(pswd_file, mode = "0600") pr() %>% pr_cookie( readLines(pswd_file, warn = FALSE), name = "counter" ) %>% pr_get("/sessionCounter", function(req) { count <- 0 if (!is.null(req$session$counter)){ count <- as.numeric(req$session$counter) } req$session$counter <- count + 1 return(paste0("This is visit #", count)) }) %>% pr_run() ## End(Not run)
Filters can be used to modify an incoming request, return an error, or return a response prior to the request reaching an endpoint.
pr_filter(pr, name, expr, serializer)
pr_filter(pr, name, expr, serializer)
pr |
A Plumber API. Note: The supplied Plumber API object will also be updated in place as well as returned by the function. |
name |
A character string. Name of filter |
expr |
An expr that resolve to a filter function or a filter function |
serializer |
A serializer function |
The Plumber router with the defined filter added
## Not run: pr() %>% pr_filter("foo", function(req, res) { print("This is filter foo") forward() }) %>% pr_get("/hi", function() "Hello") %>% pr_run() ## End(Not run)
## Not run: pr() %>% pr_filter("foo", function(req, res) { print("This is filter foo") forward() }) %>% pr_get("/hi", function() "Hello") %>% pr_run() ## End(Not run)
This collection of functions creates handlers for a Plumber router.
pr_handle(pr, methods, path, handler, preempt, serializer, endpoint, ...) pr_get(pr, path, handler, preempt, serializer, endpoint, ...) pr_post(pr, path, handler, preempt, serializer, endpoint, ...) pr_put(pr, path, handler, preempt, serializer, endpoint, ...) pr_delete(pr, path, handler, preempt, serializer, endpoint, ...) pr_head(pr, path, handler, preempt, serializer, endpoint, ...)
pr_handle(pr, methods, path, handler, preempt, serializer, endpoint, ...) pr_get(pr, path, handler, preempt, serializer, endpoint, ...) pr_post(pr, path, handler, preempt, serializer, endpoint, ...) pr_put(pr, path, handler, preempt, serializer, endpoint, ...) pr_delete(pr, path, handler, preempt, serializer, endpoint, ...) pr_head(pr, path, handler, preempt, serializer, endpoint, ...)
pr |
A Plumber API. Note: The supplied Plumber API object will also be updated in place as well as returned by the function. |
methods |
Character vector of HTTP methods |
path |
The endpoint path |
handler |
A handler function |
preempt |
A preempt function |
serializer |
A Plumber serializer |
endpoint |
A |
... |
Additional arguments for |
The generic pr_handle()
creates a handle for the given method(s). Specific
functions are implemented for the following HTTP methods:
GET
POST
PUT
DELETE
HEAD
Each function mutates the Plumber router in place and returns
the updated router.
A Plumber router with the handler added
## Not run: pr() %>% pr_handle("GET", "/hi", function() "Hello World") %>% pr_run() pr() %>% pr_handle(c("GET", "POST"), "/hi", function() "Hello World") %>% pr_run() pr() %>% pr_get("/hi", function() "Hello World") %>% pr_post("/echo", function(req, res) { if (is.null(req$body)) return("No input") list( input = req$body ) }) %>% pr_run() ## End(Not run)
## Not run: pr() %>% pr_handle("GET", "/hi", function() "Hello World") %>% pr_run() pr() %>% pr_handle(c("GET", "POST"), "/hi", function() "Hello World") %>% pr_run() pr() %>% pr_get("/hi", function() "Hello World") %>% pr_post("/echo", function(req, res) { if (is.null(req$body)) return("No input") list( input = req$body ) }) %>% pr_run() ## End(Not run)
Plumber routers support the notion of "hooks" that can be registered to execute some code at a particular point in the lifecycle of a request. Plumber routers currently support four hooks:
preroute(data, req, res)
postroute(data, req, res, value)
preserialize(data, req, res, value)
postserialize(data, req, res, value)
In all of the above you have access to a disposable environment in the data
parameter that is created as a temporary data store for each request. Hooks
can store temporary data in these hooks that can be reused by other hooks
processing this same request.
pr_hook(pr, stage, handler) pr_hooks(pr, handlers)
pr_hook(pr, stage, handler) pr_hooks(pr, handlers)
pr |
A Plumber API. Note: The supplied Plumber API object will also be updated in place as well as returned by the function. |
stage |
A character string. Point in the lifecycle of a request. |
handler |
A hook function. |
handlers |
A named list of hook handlers |
One feature when defining hooks in Plumber routers is the ability to modify
the returned value. The convention for such hooks is: any function that accepts
a parameter named value
is expected to return the new value. This could
be an unmodified version of the value that was passed in, or it could be a
mutated value. But in either case, if your hook accepts a parameter
named value
, whatever your hook returns will be used as the new value
for the response.
You can add hooks using the pr_hook
, or you can add multiple
hooks at once using pr_hooks
, which takes a named list in
which the names are the names of the hooks, and the values are the
handlers themselves.
A Plumber router with the defined hook(s) added
## Not run: pr() %>% pr_hook("preroute", function(req){ cat("Routing a request for", req$PATH_INFO, "...\n") }) %>% pr_hooks(list( preserialize = function(req, value){ print("About to serialize this value:") print(value) # Must return the value since we took one in. Here we're not choosing # to mutate it, but we could. value }, postserialize = function(res){ print("We serialized the value as:") print(res$body) } )) %>% pr_handle("GET", "/", function(){ 123 }) %>% pr_run() ## End(Not run)
## Not run: pr() %>% pr_hook("preroute", function(req){ cat("Routing a request for", req$PATH_INFO, "...\n") }) %>% pr_hooks(list( preserialize = function(req, value){ print("About to serialize this value:") print(value) # Must return the value since we took one in. Here we're not choosing # to mutate it, but we could. value }, postserialize = function(res){ print("We serialized the value as:") print(res$body) } )) %>% pr_handle("GET", "/", function(){ 123 }) %>% pr_run() ## End(Not run)
Plumber routers can be “nested” by mounting one into another
using the mount()
method. This allows you to compartmentalize your API
by paths which is a great technique for decomposing large APIs into smaller
files. This function mutates the Plumber router (pr()
) in place and
returns the updated router.
pr_mount(pr, path, router)
pr_mount(pr, path, router)
pr |
The host Plumber router. |
path |
A character string. Where to mount router. |
router |
A Plumber router. Router to be mounted. |
A Plumber router with the supplied router mounted
## Not run: pr1 <- pr() %>% pr_get("/hello", function() "Hello") pr() %>% pr_get("/goodbye", function() "Goodbye") %>% pr_mount("/hi", pr1) %>% pr_run() ## End(Not run)
## Not run: pr1 <- pr() %>% pr_get("/hello", function() "Hello") pr() %>% pr_get("/goodbye", function() "Goodbye") %>% pr_mount("/hi", pr1) %>% pr_run() ## End(Not run)
plumber
objectport
does not need to be explicitly assigned.
pr_run( pr, host = "127.0.0.1", port = get_option_or_env("plumber.port", NULL), ..., debug = missing_arg(), docs = missing_arg(), swaggerCallback = missing_arg(), quiet = FALSE )
pr_run( pr, host = "127.0.0.1", port = get_option_or_env("plumber.port", NULL), ..., debug = missing_arg(), docs = missing_arg(), swaggerCallback = missing_arg(), quiet = FALSE )
pr |
A Plumber API. Note: The supplied Plumber API object will also be updated in place as well as returned by the function. |
host |
A string that is a valid IPv4 or IPv6 address that is owned by this server, which the application will listen on. "0.0.0.0" represents all IPv4 addresses and "::/0" represents all IPv6 addresses. |
port |
A number or integer that indicates the server port that should be listened on. Note that on most Unix-like systems including Linux and Mac OS X, port numbers smaller than 1025 require root privileges. |
... |
Should be empty. |
debug |
If |
docs |
Visual documentation value to use while running the API.
This value will only be used while running the router.
If missing, defaults to information previously set with |
swaggerCallback |
An optional single-argument function that is called
back with the URL to an OpenAPI user interface when one becomes ready. If
missing, defaults to information set with |
quiet |
If |
## Not run: pr() %>% pr_run() pr() %>% pr_run( # manually set port port = 5762, # turn off visual documentation docs = FALSE, # do not display startup messages quiet = TRUE ) ## End(Not run)
## Not run: pr() %>% pr_run() pr() %>% pr_run( # manually set port port = 5762, # turn off visual documentation docs = FALSE, # do not display startup messages quiet = TRUE ) ## End(Not run)
This function allows a custom error message to be returned when a request cannot be served by an existing endpoint or filter.
pr_set_404(pr, fun)
pr_set_404(pr, fun)
pr |
A Plumber API. Note: The supplied Plumber API object will also be updated in place as well as returned by the function. |
fun |
A handler function |
The Plumber router with a modified 404 handler
## Not run: handler_404 <- function(req, res) { res$status <- 404 res$body <- "Oops" } pr() %>% pr_get("/hi", function() "Hello") %>% pr_set_404(handler_404) %>% pr_run() ## End(Not run)
## Not run: handler_404 <- function(req, res) { res$status <- 404 res$body <- "Oops" } pr() %>% pr_get("/hi", function() "Hello") %>% pr_set_404(handler_404) %>% pr_run() ## End(Not run)
Allows to modify OpenAPI Specification autogenerated by plumber
.
pr_set_api_spec(pr, api)
pr_set_api_spec(pr, api)
pr |
A Plumber API. Note: The supplied Plumber API object will also be updated in place as well as returned by the function. |
api |
This can be
The value returned will not be validated for OAS compatibility. |
Note, the returned value will be sent through serializer_unboxed_json()
which will turn all length 1 vectors into atomic values.
To force a vector to serialize to an array of size 1, be sure to call as.list()
on your value. list()
objects are always serialized to an array value.
The Plumber router with the new OpenAPI Specification object or function.
## Not run: # Set the API Spec to a function to use the auto-generated OAS object pr() %>% pr_set_api_spec(function(spec) { spec$info$title <- Sys.time() spec }) %>% pr_get("/plus/<a:int>/<b:int>", function(a, b) { a + b }) %>% pr_run() # Set the API Spec using an object pr() %>% pr_set_api_spec(my_custom_object) %>% pr_get("/plus/<a:int>/<b:int>", function(a, b) { a + b }) %>% pr_run() ## End(Not run)
## Not run: # Set the API Spec to a function to use the auto-generated OAS object pr() %>% pr_set_api_spec(function(spec) { spec$info$title <- Sys.time() spec }) %>% pr_get("/plus/<a:int>/<b:int>", function(a, b) { a + b }) %>% pr_run() # Set the API Spec using an object pr() %>% pr_set_api_spec(my_custom_object) %>% pr_get("/plus/<a:int>/<b:int>", function(a, b) { a + b }) %>% pr_run() ## End(Not run)
To hide any error messages in production, set the debug value to FALSE
.
The debug
value is enabled by default for interactive()
sessions.
pr_set_debug(pr, debug = interactive())
pr_set_debug(pr, debug = interactive())
pr |
A Plumber API. Note: The supplied Plumber API object will also be updated in place as well as returned by the function. |
debug |
|
The Plumber router with the new debug setting.
## Not run: # Will contain the original error message pr() %>% pr_set_debug(TRUE) %>% pr_get("/boom", function() stop("boom")) %>% pr_run() # Will NOT contain an error message pr() %>% pr_set_debug(FALSE) %>% pr_get("/boom", function() stop("boom")) %>% pr_run() ## End(Not run)
## Not run: # Will contain the original error message pr() %>% pr_set_debug(TRUE) %>% pr_get("/boom", function() stop("boom")) %>% pr_run() # Will NOT contain an error message pr() %>% pr_set_debug(FALSE) %>% pr_get("/boom", function() stop("boom")) %>% pr_run() ## End(Not run)
docs
should be either a logical or a character value matching a registered visual documentation.
Multiple handles will be added to Plumber
object. OpenAPI json
file will be served on paths /openapi.json
. Documentation
will be served on paths /__docs__/index.html
and /__docs__/
.
pr_set_docs(pr, docs = get_option_or_env("plumber.docs", TRUE), ...)
pr_set_docs(pr, docs = get_option_or_env("plumber.docs", TRUE), ...)
pr |
A Plumber API. Note: The supplied Plumber API object will also be updated in place as well as returned by the function. |
docs |
a character value or a logical value.
If using |
... |
Arguments for the visual documentation. See each visual documentation package for further details. |
The Plumber router with the new docs settings.
## Not run: ## View API using Swagger UI # Official Website: https://swagger.io/tools/swagger-ui/ # install.packages("swagger") if (require(swagger)) { pr() %>% pr_set_docs("swagger") %>% pr_get("/plus/<a:int>/<b:int>", function(a, b) { a + b }) %>% pr_run() } ## View API using Redoc # Official Website: https://github.com/Redocly/redoc if (require(redoc)) { pr() %>% pr_set_docs("redoc") %>% pr_get("/plus/<a:int>/<b:int>", function(a, b) { a + b }) %>% pr_run() } ## View API using RapiDoc # Official Website: https://github.com/mrin9/RapiDoc if (require(rapidoc)) { pr() %>% pr_set_docs("rapidoc") %>% pr_get("/plus/<a:int>/<b:int>", function(a, b) { a + b }) %>% pr_run() } ## Disable the OpenAPI Spec UI pr() %>% pr_set_docs(FALSE) %>% pr_get("/plus/<a:int>/<b:int>", function(a, b) { a + b }) %>% pr_run() ## End(Not run)
## Not run: ## View API using Swagger UI # Official Website: https://swagger.io/tools/swagger-ui/ # install.packages("swagger") if (require(swagger)) { pr() %>% pr_set_docs("swagger") %>% pr_get("/plus/<a:int>/<b:int>", function(a, b) { a + b }) %>% pr_run() } ## View API using Redoc # Official Website: https://github.com/Redocly/redoc if (require(redoc)) { pr() %>% pr_set_docs("redoc") %>% pr_get("/plus/<a:int>/<b:int>", function(a, b) { a + b }) %>% pr_run() } ## View API using RapiDoc # Official Website: https://github.com/mrin9/RapiDoc if (require(rapidoc)) { pr() %>% pr_set_docs("rapidoc") %>% pr_get("/plus/<a:int>/<b:int>", function(a, b) { a + b }) %>% pr_run() } ## Disable the OpenAPI Spec UI pr() %>% pr_set_docs(FALSE) %>% pr_get("/plus/<a:int>/<b:int>", function(a, b) { a + b }) %>% pr_run() ## End(Not run)
callback
to tell where the API visual documentation is locatedWhen set, it will be called with a character string corresponding to the API visual documentation url. This allows RStudio to locate visual documentation.
pr_set_docs_callback( pr, callback = get_option_or_env("plumber.docs.callback", NULL) )
pr_set_docs_callback( pr, callback = get_option_or_env("plumber.docs.callback", NULL) )
pr |
A Plumber API. Note: The supplied Plumber API object will also be updated in place as well as returned by the function. |
callback |
a callback function for taking action on the docs url. |
If using options_plumber()
, the value must be set before initializing your Plumber router.
The Plumber router with the new docs callback setting.
## Not run: pr() %>% pr_set_docs_callback(function(url) { message("API location: ", url) }) %>% pr_get("/plus/<a:int>/<b:int>", function(a, b) { a + b }) %>% pr_run() ## End(Not run)
## Not run: pr() %>% pr_set_docs_callback(function(url) { message("API location: ", url) }) %>% pr_get("/plus/<a:int>/<b:int>", function(a, b) { a + b }) %>% pr_run() ## End(Not run)
Set the error handler that is invoked if any filter or endpoint generates an error
pr_set_error(pr, fun)
pr_set_error(pr, fun)
pr |
A Plumber API. Note: The supplied Plumber API object will also be updated in place as well as returned by the function. |
fun |
An error handler function. This should accept |
The Plumber router with a modified error handler
## Not run: handler_error <- function(req, res, err){ res$status <- 500 list(error = "Custom Error Message") } pr() %>% pr_get("/error", function() log("a")) %>% pr_set_error(handler_error) %>% pr_run() ## End(Not run)
## Not run: handler_error <- function(req, res, err){ res$status <- 500 list(error = "Custom Error Message") } pr() %>% pr_get("/error", function() log("a")) %>% pr_set_error(handler_error) %>% pr_run() ## End(Not run)
By default, Plumber will parse JSON, text, query strings, octet streams, and multipart bodies. This function updates the default parsers for any endpoint that does not define their own parsers.
pr_set_parsers(pr, parsers)
pr_set_parsers(pr, parsers)
pr |
A Plumber API. Note: The supplied Plumber API object will also be updated in place as well as returned by the function. |
parsers |
Can be one of:
If the parser name Example: # provide a character string parsers = "json" # provide a named list with no arguments parsers = list(json = list()) # provide a named list with arguments; include `rds` parsers = list(json = list(simplifyVector = FALSE), rds = list()) # default plumber parsers parsers = c("json", "form", "text", "octet", "multi") |
Note: The default set of parsers will be completely replaced if any value is supplied. Be sure to include all of your parsers that you would like to include.
Use registered_parsers()
to get a list of available parser names.
The Plumber router with the new default PlumberEndpoint parsers
By default, Plumber serializes responses to JSON. This function updates the
default serializer to the function supplied via serializer
pr_set_serializer(pr, serializer)
pr_set_serializer(pr, serializer)
pr |
A Plumber API. Note: The supplied Plumber API object will also be updated in place as well as returned by the function. |
serializer |
A serializer function |
The Plumber router with the new default serializer
plumber
objectAdd a static route to the plumber
object
pr_static(pr, path, direc)
pr_static(pr, path, direc)
pr |
A Plumber API. Note: The supplied Plumber API object will also be updated in place as well as returned by the function. |
path |
The mounted path location of the static folder |
direc |
The local folder to be served statically |
## Not run: pr() %>% pr_static("/path", "./my_folder/location") %>% pr_run() ## End(Not run)
## Not run: pr() %>% pr_static("/path", "./my_folder/location") %>% pr_run() ## End(Not run)
Uses a cryptographically secure pseudorandom number generator from sodium::helpers()
to generate a 64 digit hexadecimal string. 'sodium' wraps around 'libsodium'.
random_cookie_key()
random_cookie_key()
Please see session_cookie
for more information on how to save the generated key.
A 64 digit hexadecimal string to be used as a key for cookie encryption.
register_docs()
is used by other packages like swagger
, rapidoc
, and redoc
.
When you load these packages, it calls register_docs()
to provide a user
interface that can interpret your plumber OpenAPI Specifications.
register_docs(name, index, static = NULL) registered_docs()
register_docs(name, index, static = NULL) registered_docs()
name |
Name of the visual documentation |
index |
A function that returns the HTML content of the landing page of the documentation.
Parameters (besides |
static |
A function that returns the path to the static assets (images, javascript, css, fonts) the Docs will use. |
## Not run: # Example from the `swagger` R package register_docs( name = "swagger", index = function(version = "3", ...) { swagger::swagger_spec( api_path = paste0( "window.location.origin + ", "window.location.pathname.replace(", "/\\(__docs__\\\\/|__docs__\\\\/index.html\\)$/, \"\"", ") + ", "\"openapi.json\"" ), version = version ) }, static = function(version = "3", ...) { swagger::swagger_path(version) } ) # When setting the docs, `index` and `static` function arguments can be supplied # * via `pr_set_docs()` # * or through URL query string variables pr() %>% # Set default argument `version = "3"` for the swagger `index` and `static` functions pr_set_docs("swagger", version = "3") %>% pr_get("/plus/<a:int>/<b:int>", function(a, b) { a + b }) %>% pr_run() ## End(Not run)
## Not run: # Example from the `swagger` R package register_docs( name = "swagger", index = function(version = "3", ...) { swagger::swagger_spec( api_path = paste0( "window.location.origin + ", "window.location.pathname.replace(", "/\\(__docs__\\\\/|__docs__\\\\/index.html\\)$/, \"\"", ") + ", "\"openapi.json\"" ), version = version ) }, static = function(version = "3", ...) { swagger::swagger_path(version) } ) # When setting the docs, `index` and `static` function arguments can be supplied # * via `pr_set_docs()` # * or through URL query string variables pr() %>% # Set default argument `version = "3"` for the swagger `index` and `static` functions pr_set_docs("swagger", version = "3") %>% pr_get("/plus/<a:int>/<b:int>", function(a, b) { a + b }) %>% pr_run() ## End(Not run)
A parser is responsible for decoding the raw body content of a request into
a list of arguments that can be mapped to endpoint function arguments.
For instance, parser_json()
parse content-type application/json
.
register_parser(alias, parser, fixed = NULL, regex = NULL, verbose = TRUE) registered_parsers()
register_parser(alias, parser, fixed = NULL, regex = NULL, verbose = TRUE) registered_parsers()
alias |
An alias to map parser from the |
parser |
The parser function to be added. This build the parser function. See Details for more information. |
fixed |
A character vector of fixed string to be matched against a request |
regex |
A character vector of regex string to be matched against a request |
verbose |
Logical value which determines if a warning should be displayed when alias in map are overwritten. |
When parser
is evaluated, it should return a parser function.
Parser matching is done first by content-type
header matching with fixed
then by using
regular expressions with regex
. Note that plumber strips ; charset*
from content-type
header before matching.
Plumber will try to use parser_json()
(if available) when no content-type
header is found and
the request body starts with {
or [
.
Functions signature should include value
, ...
and
possibly content_type
, filename
. Other parameters may be provided
if you want to use the headers from webutils::parse_multipart()
.
Parser function structure is something like below.
function(parser_arguments_here) { # return a function to parse a raw value function(value, ...) { # do something with raw value } }
registered_parsers()
: Return all registered parsers
# `content-type` header is mostly used to look up charset and adjust encoding parser_dcf <- function(...) { function(value, content_type = "text/x-dcf", ...) { charset <- get_character_set(content_type) value <- rawToChar(value) Encoding(value) <- charset read.dcf(value, ...) } } # Could also leverage existing parsers parser_dcf <- function(...) { parser_read_file(function(tmpfile) { read.dcf(tmpfile, ...) }) } # Register the newly created parser ## Not run: register_parser("dcf", parser_dcf, fixed = "text/x-dcf")
# `content-type` header is mostly used to look up charset and adjust encoding parser_dcf <- function(...) { function(value, content_type = "text/x-dcf", ...) { charset <- get_character_set(content_type) value <- rawToChar(value) Encoding(value) <- charset read.dcf(value, ...) } } # Could also leverage existing parsers parser_dcf <- function(...) { parser_read_file(function(tmpfile) { read.dcf(tmpfile, ...) }) } # Register the newly created parser ## Not run: register_parser("dcf", parser_dcf, fixed = "text/x-dcf")
A serializer is responsible for translating a generated R value into output
that a remote user can understand. For instance, the serializer_json
serializes R objects into JSON before returning them to the user. The list of
available serializers in plumber is global.
register_serializer(name, serializer, verbose = TRUE) registered_serializers()
register_serializer(name, serializer, verbose = TRUE) registered_serializers()
name |
The name of the serializer (character string) |
serializer |
The serializer function to be added.
This function should accept arguments that can be supplied when |
verbose |
Logical value which determines if a message should be printed when overwriting serializers |
There are three main building-block serializers:
serializer_headers
: the base building-block serializer that is required to have as_attachment()
work
serializer_content_type()
: for setting the content type. (Calls serializer_headers()
)
serializer_device()
: add endpoint hooks to turn a graphics device on and off in addition to setting the content type. (Uses serializer_content_type()
)
register_serializer()
: Register a serializer with a name
registered_serializers()
: Return a list of all registered serializers
# `serializer_json()` calls `serializer_content_type()` and supplies a serialization function print(serializer_json) # serializer_content_type() calls `serializer_headers()` and supplies a serialization function print(serializer_content_type)
# `serializer_json()` calls `serializer_content_type()` and supplies a serialization function print(serializer_json) # serializer_content_type() calls `serializer_headers()` and supplies a serialization function print(serializer_content_type)
Serializers are used in Plumber to transform the R object produced by a filter/endpoint into an HTTP response that can be returned to the client. See here for more details on Plumber serializers and how to customize their behavior.
serializer_headers(headers = list(), serialize_fn = identity) serializer_content_type(type, serialize_fn = identity) serializer_octet(..., type = "application/octet-stream") serializer_csv(..., type = "text/csv; charset=UTF-8") serializer_tsv(..., type = "text/tab-separated-values; charset=UTF-8") serializer_html(type = "text/html; charset=UTF-8") serializer_json(..., type = "application/json") serializer_unboxed_json(auto_unbox = TRUE, ..., type = "application/json") serializer_geojson(..., type = "application/geo+json") serializer_rds(version = "2", ascii = FALSE, ..., type = "application/rds") serializer_feather(type = "application/vnd.apache.arrow.file") serializer_parquet(type = "application/vnd.apache.parquet") serializer_yaml(..., type = "text/x-yaml; charset=UTF-8") serializer_text( ..., serialize_fn = as.character, type = "text/plain; charset=UTF-8" ) serializer_format(..., type = "text/plain; charset=UTF-8") serializer_print(..., type = "text/plain; charset=UTF-8") serializer_cat(..., type = "text/plain; charset=UTF-8") serializer_write_file(type, write_fn, fileext = NULL) serializer_htmlwidget(..., type = "text/html; charset=UTF-8") serializer_device(type, dev_on, dev_off = grDevices::dev.off) serializer_jpeg(..., type = "image/jpeg") serializer_png(..., type = "image/png") serializer_svg(..., type = "image/svg+xml") serializer_bmp(..., type = "image/bmp") serializer_tiff(..., type = "image/tiff") serializer_pdf(..., type = "application/pdf") serializer_agg_jpeg(..., type = "image/jpeg") serializer_agg_png(..., type = "image/png") serializer_agg_tiff(..., type = "image/tiff") serializer_svglite(..., type = "image/svg+xml")
serializer_headers(headers = list(), serialize_fn = identity) serializer_content_type(type, serialize_fn = identity) serializer_octet(..., type = "application/octet-stream") serializer_csv(..., type = "text/csv; charset=UTF-8") serializer_tsv(..., type = "text/tab-separated-values; charset=UTF-8") serializer_html(type = "text/html; charset=UTF-8") serializer_json(..., type = "application/json") serializer_unboxed_json(auto_unbox = TRUE, ..., type = "application/json") serializer_geojson(..., type = "application/geo+json") serializer_rds(version = "2", ascii = FALSE, ..., type = "application/rds") serializer_feather(type = "application/vnd.apache.arrow.file") serializer_parquet(type = "application/vnd.apache.parquet") serializer_yaml(..., type = "text/x-yaml; charset=UTF-8") serializer_text( ..., serialize_fn = as.character, type = "text/plain; charset=UTF-8" ) serializer_format(..., type = "text/plain; charset=UTF-8") serializer_print(..., type = "text/plain; charset=UTF-8") serializer_cat(..., type = "text/plain; charset=UTF-8") serializer_write_file(type, write_fn, fileext = NULL) serializer_htmlwidget(..., type = "text/html; charset=UTF-8") serializer_device(type, dev_on, dev_off = grDevices::dev.off) serializer_jpeg(..., type = "image/jpeg") serializer_png(..., type = "image/png") serializer_svg(..., type = "image/svg+xml") serializer_bmp(..., type = "image/bmp") serializer_tiff(..., type = "image/tiff") serializer_pdf(..., type = "application/pdf") serializer_agg_jpeg(..., type = "image/jpeg") serializer_agg_png(..., type = "image/png") serializer_agg_tiff(..., type = "image/tiff") serializer_svglite(..., type = "image/svg+xml")
headers |
|
serialize_fn |
Function to serialize the data. The result object will be converted to a character string. Ex: |
type |
The value to provide for the |
... |
extra arguments supplied to respective internal serialization function. |
auto_unbox |
automatically |
version |
the workspace format version to use. |
ascii |
a logical. If |
write_fn |
Function that should write serialized content to the temp file provided. |
fileext |
A non-empty character vector giving the file extension. This value will try to be inferred from the content type provided. |
dev_on |
Function to turn on a graphics device.
The graphics device |
dev_off |
Function to turn off the graphics device. Defaults to |
serializer_headers()
: Add a static list of headers to each return value. Will add Content-Disposition
header if a value is the result of as_attachment()
.
serializer_content_type()
: Adds a Content-Type
header to the response object
serializer_octet()
: Octet serializer. If content is received that does
not have a "raw"
type, then an error will be thrown.
serializer_csv()
: CSV serializer. See also: readr::format_csv()
serializer_tsv()
: TSV serializer. See also: readr::format_tsv()
serializer_html()
: HTML serializer
serializer_json()
: JSON serializer. See also: jsonlite::toJSON()
serializer_unboxed_json()
: JSON serializer with auto_unbox
defaulting to TRUE
. See also: jsonlite::toJSON()
serializer_geojson()
: GeoJSON serializer. See also geojsonsf::sf_geojson()
and [geojsonsf::sfc_geojson()
].
serializer_rds()
: RDS serializer. See also: base::serialize()
serializer_feather()
: feather serializer. See also: arrow::write_feather()
serializer_parquet()
: parquet serializer. See also: arrow::write_parquet()
serializer_yaml()
: YAML serializer. See also: yaml::as.yaml()
serializer_text()
: Text serializer. See also: as.character()
serializer_format()
: Text serializer. See also: format()
serializer_print()
: Text serializer. Captures the output of print()
serializer_cat()
: Text serializer. Captures the output of cat()
serializer_write_file()
: Write output to a temp file whose contents are read back as a serialized response. serializer_write_file()
creates (and cleans up) a temp file, calls the serializer (which should write to the temp file), and then reads the contents back as the serialized value. If the content type
starts with "text"
, the return result will be read into a character string, otherwise the result will be returned as a raw vector.
serializer_htmlwidget()
: htmlwidget serializer. See also: htmlwidgets::saveWidget()
serializer_device()
: Helper method to create graphics device serializers, such as serializer_png()
. See also: endpoint_serializer()
serializer_jpeg()
: JPEG image serializer. See also: grDevices::jpeg()
serializer_png()
: PNG image serializer. See also: grDevices::png()
serializer_svg()
: SVG image serializer. See also: grDevices::svg()
serializer_bmp()
: BMP image serializer. See also: grDevices::bmp()
serializer_tiff()
: TIFF image serializer. See also: grDevices::tiff()
serializer_pdf()
: PDF image serializer. See also: grDevices::pdf()
serializer_agg_jpeg()
: JPEG image serializer using ragg. See also: ragg::agg_jpeg()
serializer_agg_png()
: PNG image serializer using ragg. See also: ragg::agg_png()
serializer_agg_tiff()
: TIFF image serializer using ragg. See also: ragg::agg_tiff()
serializer_svglite()
: SVG image serializer using svglite. See also: svglite::svglite()
plumber
uses the crypto R package sodium
, to encrypt/decrypt
req$session
information for each server request.
session_cookie( key, name = "plumber", expiration = FALSE, http = TRUE, secure = FALSE, same_site = FALSE, path = NULL )
session_cookie( key, name = "plumber", expiration = FALSE, http = TRUE, secure = FALSE, same_site = FALSE, path = NULL )
key |
The secret key to use. This must be consistent across all R sessions
where you want to save/restore encrypted cookies. It should be produced using
|
name |
The name of the cookie in the user's browser. |
expiration |
A number representing the number of seconds into the future
before the cookie expires or a |
http |
Boolean that adds the |
secure |
Boolean that adds the |
same_site |
A character specifying the SameSite policy to attach to the cookie.
If specified, one of the following values should be given: "Strict", "Lax", or "None".
If "None" is specified, then the |
path |
The URI path that the cookie will be available in future requests.
Defaults to the request URI. Set to |
The cookie's secret encryption key
value must be consistent to maintain
req$session
information between server restarts.
While it is very quick to get started with user session cookies using
plumber
, please exercise precaution when storing secure key information.
If a malicious person were to gain access to the secret key
, they would
be able to eavesdrop on all req$session
information and/or tamper with
req$session
information being processed.
Please:
Do NOT store keys in source control.
Do NOT store keys on disk with permissions that allow it to be accessed by everyone.
Do NOT store keys in databases which can be queried by everyone.
Instead, please:
Use a key management system, such as 'keyring' (preferred)
Store the secret in a file on disk with appropriately secure permissions,
such as "user read only" (Sys.chmod("myfile.txt", mode = "0600")
),
to prevent others from reading it.
Examples of both of these solutions are done in the Examples section.
'sodium': R bindings to 'libsodium'
'libsodium': A Modern and Easy-to-Use Crypto Library
'keyring': Access the system credential store from R
Set-Cookie flags: Descriptions of different flags for Set-Cookie
Cross-site scripting: A security exploit which allows an attacker to inject into a website malicious client-side code
## Not run: ## Set secret key using `keyring` (preferred method) keyring::key_set_with_value("plumber_api", plumber::random_cookie_key()) # Load a plumber API plumb_api("plumber", "01-append") %>% # Add cookie support via `keyring` pr_cookie( keyring::key_get("plumber_api") ) %>% pr_run() #### -------------------------------- ### ## Save key to a local file pswd_file <- "normal_file.txt" cat(plumber::random_cookie_key(), file = pswd_file) # Make file read-only Sys.chmod(pswd_file, mode = "0600") # Load a plumber API plumb_api("plumber", "01-append") %>% # Add cookie support and retrieve secret key from file pr_cookie( readLines(pswd_file, warn = FALSE) ) %>% pr_run() ## End(Not run)
## Not run: ## Set secret key using `keyring` (preferred method) keyring::key_set_with_value("plumber_api", plumber::random_cookie_key()) # Load a plumber API plumb_api("plumber", "01-append") %>% # Add cookie support via `keyring` pr_cookie( keyring::key_get("plumber_api") ) %>% pr_run() #### -------------------------------- ### ## Save key to a local file pswd_file <- "normal_file.txt" cat(plumber::random_cookie_key(), file = pswd_file) # Make file read-only Sys.chmod(pswd_file, mode = "0600") # Load a plumber API plumb_api("plumber", "01-append") %>% # Add cookie support and retrieve secret key from file pr_cookie( readLines(pswd_file, warn = FALSE) ) %>% pr_run() ## End(Not run)
Validate an OpenAPI Spec using Swagger CLI which calls Swagger Parser.
validate_api_spec(pr, verbose = TRUE)
validate_api_spec(pr, verbose = TRUE)
pr |
A Plumber API |
verbose |
Logical that determines if a "is valid" statement is displayed. Defaults to |
If the api is deemed invalid, an error will be thrown.
This function is VERY and may be altered, changed, or removed in the future.
## Not run: pr <- plumb_api("plumber", "01-append") validate_api_spec(pr) ## End(Not run)
## Not run: pr <- plumb_api("plumber", "01-append") validate_api_spec(pr) ## End(Not run)