serializer_feather_stream() andparser_feather_stream() now supportArrowIPC Streams (pr_run() now correctly honors theapiPath option when mounting documentation (
Added CI testing for only depends packages by request of CRAN(#1006).
The port many now be specified as an environment variable.User-provided ports must be between 1024 and 49151 (followingIANAguidelines) and may not be a known unsafe port. plumber will nowthrow an error if an invalid port is requested. (
Added support for graphic devices provided by {ragg} and{svglite} (
parse_rds(),parse_feather(), andparse_parquet() no longer writes data to disk duringparsing (
Returning error messages are now turned off by default ratherthan being turned on if running interactively and turned off if not(@thomasp85,#962).
New serializers:
serializer_excel(): Return an object serialized bywritexl::write_xlsx (New request body parsers:
parser_excel(): Parse request body as an excel workbookusingreadxl::read_excel (@parse excel list(sheet=NA) to import all worksheets. Thisalways returns a list of frames, even if there is just oneworksheet.Mounts now have a dynamicreq$PATH_INFO instead of apre-computed value. (#888)
validate_api_spec() now uses@redocly/cli to validate the API spec. (#986)
AddedoperationId to each operation within theauto-generated OpenAPI output. The value is similar to thePATH-VERB, e.g. /users/create-POST.(#986)
Added support for graphic devices provided by ragg and svglite(@thomasp85#964)
?options_plumber. (parseUTF8 return value attributesrcfile on Windows. (#930)Static file handler now serves HEAD requests. (#798)
Introduces new GeoJSON serializer and parser. GeoJSON objects areparsed intosf objects andsf orsfc objects will be serialized into GeoJSON. (
Add new Octet-Stream serializer. This is a wrapper around theContent Type serializer with typeapplication/octet-stream.(#864)
Update feather serializer to use the arrow package. The newdefault feather MIME type isapplication/vnd.apache.arrow.file. (
Add parquet serializer and parser by using the arrow package(@pachadotdev#849)
Updated example14-future to usepromises::future_promise() and added an endpoint that uses{coro} to writesimpler async /{promises} code (#785)
Addpath argument topr_cookie()allowing Secure cookies to define where they are served (
OpenAPI specification collision when usingexamples.(@meztez#820)
Static handler returns Last-Modified response header.(#798)
OpenAPI response type detection had a scoping issue. Useserializer definedContent-Type header instead. (
The default shared secret filter returns error responses withoutthrowing an error. (#808)
Remove response bodies (and therefore the Content-Length header)for status codes which forbid it under the HTTP specification (e.g. 1xx,204, 304). (
Decode path URI before attempting to serve static assets (
Force json serialization of endpoint error responses instead ofusing endpoint serializer. (
When plumbing a Plumber file and using a Plumber router modifier(#* @plumber), an error will be thrown if the originalrouter is not returned. (#738)
options_plumber() now requires that all options arenamed. If no option name is provided, an error with be thrown.(#746)
Added optionplumber.trailingSlash. This option(which isdisabled by default) allows routes to beredirected to route definitions with a trailing slash. For example, if aGET request is submitted to/test?a=1 with no/test route is defined, but aGET/test/ route definition does exist, then the originalrequest will respond with a307 to reattempt againstGET/test/?a=1. This option will beenabled by default in a future release. This logic executed forbefore calling the404 handler. (#746)
Added an experimental optionplumber.methodNotAllowed. This option (which is enabled bydefault) allows for a status of405 to be returned if aninvalid method is used when requesting a valid route. This logicexecuted for before calling the default404 handler.(#746)
Passingedit = TRUE toplumb_api() willopen the API source file. (#699)
OpenAPI Specification can be set using a file path. (
Guess OpenAPI response content type from serializer. (
UndeprecatedPlumber$run(debug=, swaggerCallback=)and added the parameters forPlumber$run(docs=, quiet=) andpr_run(debug=, docs=, swaggerCallback=, quiet=). Now, allfour parameters will not produce lingering effects on thePlumber router. (
quiet = TRUE will suppress routine startupmessages.debug = TRUE, will display information when anerror occurs. Seepr_set_debug().docs will update the visual documentation. Seepr_set_docs().swaggerCallback to a function which will be calledwith a url to the documentation, orNULL to do nothing. Seepr_set_docs_callback().To update aPlumberEndpoint path afterinitialization, call the newPlumberEndpoint$setPath(path).This will update internal path matching meta data. (Active bindings werenot used to avoid breaking changes.) (
PlumberStep (andPlumberEndpoint andPlumberFilter) received a new field$srcrefand method$getFunc().$srcref will containthe correspondingsrcref information from original sourcefile.$getFunc() will return the evaluated function.(#782)
Allow for spaces in@apiTag and@tagwhen tag is surrounded by single or double quotes. (#685)
Ignore regular comments in block parsing. (
Block parsing comments, tags and responses ordering match plumberapi ordering. (#722)
Fixed bug wherehttpuv would return a status of500 with bodyAn exception occurred if noheaders were set on the response object. (#745)
Fixed bug where allpr_*() returned invisibly. Nowallpr_*() methods will print the router if displayed inthe console. (#740)
When callingPlumber$handle() and defining a newPlumberEndpoint,... will be checked forinvalid names. (
/__swagger__/ now always redirects to/__docs__/, even when Swagger isn’t the selected interface.Useoptions(plumber.legacyRedirects = FALSE) to disablethis behavior. (
Fixedavailable_apis() bug where all packagesprinted all available APIs. (
Fixed Plumber$routes resolution bugs. Routes arenow returned in lexicographical order. (
Plumber will now display a circular reference if one is foundwhile printing. (#738)
Changedfuture::plan() frommultiprocess tomultisession in example API14-future as “Strategy ‘multiprocess’ is deprecated infuture (>= 1.20.0)”. (#747)
Setting optionsplumber.docs.callback toNULL will also set deprecated but supported optionplumber.swagger.url. (#766)
Added support for promises in endpoints, filters, and hooks. Thisallows for multi-core execution when paired withfuture.Seeplumb_api("plumber", "13-promises") andplumb_api("plumber", "14-future") for exampleimplementations. (#248)
Added a Tidy API for more natural usage with magrittr’s%>%. For example, a plumber object can now be initiatedand run withpr() %>% pr_run(port = 8080). For moreexamples, seehere(@blairj09,#590)
Added support for#' @plumber tag to gainprogrammatic access to theplumber router viafunction(pr) {....}. Seesystem.file("plumber/06-sessions/plumber.R", package = "plumber")and how it adds cookie support from withinplumber.R.(@meztez and
Addedplumb_api() for standardizing where to locate(inst/plumber) and how to run(plumb_api(package, name)) plumber apis inside an Rpackage. To view the available Plumber APIs, callavailable_apis(). (#631)
Improved argument handling in Plumber Endpoint route definitions.Seesystem.file("plumber/17-arguments/plumber.R", package = "plumber")to view an example with expected output andplumb_api("plumber", "17-arguments") to retrieve the api.Improvements include:
req andresarguments in a route definition are nowalways Plumber requestand response objects. In the past, this was not guaranteed. (#666,#637)req$argsQuery,req$argsPath, andreq$argsBody have been added to access query, path, andreq$body parameters, respectively. For this reason, wesuggest defining routes with onlyreq andres(i.e.,function(req, res) {}) and accessing argument(s)under these new fields to avoid naming conflicts. (#637)req$argsQuery is 1st priority, thenreq$argsPath, thenreq$argsBody). (#666)req$args by filtersor creatingreq$argsBody will no longer throw an error.They will only be passed through via... (#666)API Documentation is now hosted at/__docs__. Ifswagger documentation is being used,/__swagger__ will redirect to/__docs__.(#654)
Added OpenAPI support for array parameters using syntaxname:[type] and new typelist (synonym df,data.frame). (@meztez,#532)
Added user provided OpenAPI Specification handler to Plumberrouter. Use$setApiSpec() to provide a function to alterthe Plumber generated OpenAPI Specification returned by Plumber routermethod$getApiSpec(). This also affects/openapi.json and/openapi.yaml (#365)(
Addedvalidate_api_spec() to validate a Plumber APIproduces a valid OpenAPI Specification. (Experimental!) (#633)
Addedas_attachment(value, filename) method whichallows routes to return a file attachment with a custom name.(#585)
Serializer functions can now returnPlumberEndpointpreexec andpostexec hooks in addition to aserializer function by usingendpoint_serializer(). This allows for image serializers toturn on their corresponding graphics device before the route executesand turn the graphics device off after the route executes.(#630)
PNG, JPEG, and SVG image serializers have been exported inmethodsserializer_png(),serializer_jpeg(),andserializer_svg() respectively. In addition to thesemethods,serializer_tiff(),serializer_bmp(),andserializer_pdf() have been added. Each graphics deviceserializer wraps aroundserializer_device(), which shouldbe used when making more graphics device serializers. (#630)
New serializers
serializer_yaml(): Return an object serialized byyaml (serializer_csv(): Return a comma separated value (serializer_tsv(): Return a tab separated value(#630)serializer_feather(): Return a object serialized byfeather (#626)serializer_text(): Return text content (#585)serializer_cat(): Return text content after callingcat() (#585)serializer_print(): Return text content after callingprint() (#585)serializer_format(): Return text content after callingformat() (#585)serializer_svg(): Return an image saved as an SVG(@pachamaltese,#398)serializer_headers(header_list): Method which sets alist of static headers for each serialized value. Heavily inspired from@ycphs (#455).(#585)serializer_write_file(): Method which wrapsserializer_content_type(), but orchestrates creating,writing serialized content to, reading from, and removing a temp file.(#660)Added support for request body parsing (
New request body parsers
parser_csv(): Parse request body as a commas separatedvalue (#584)parser_json(): Parse request body as JSON (parser_multi(): Parse multi part request bodies (parser_octet(): Parse request body octet stream (parser_form(): Parse request body as form input (parser_rds(): Parse request body as RDS file input(@meztez, #532)parser_text(): Parse request body plain text (parser_tsv(): Parse request body a tab separated value(#584)parser_yaml(): Parse request body asyaml(#584)parser_none(): Do not parse the request body(#584)parser_yaml(): Parse request body (parser_feather(): Parse request body usingfeather (#626)"all" to allow for using allparsers. (Not recommended in production!) (#584)The parsed request body values is stored atreq$body. (#663)
Ifmultipart/* content is parsed,req$body will contain named output fromwebutils::parse_multipart() and add the parsed value toeach part. Look here for access to all provided information (e.g.,name,filename,content_type,etc). In addition,req$argsBody (which is used for routeargument matching) will contain a named reduced form of this informationwhereparsed values (andfilenames) arecombined on the samename. (#663)
Generalize user interface integration. Plumber can now use otherOpenAPI compatible user interfaces likeRapiDoc(https://github.com/mrin9/RapiDoc) andRedoc(https://github.com/Redocly/redoc). Pending CRAN approbations,development R packages are available fromhttps://github.com/meztez/rapidoc/ and https://github.com/meztez/redoc/.(@meztez,#562)
Changed Swagger UI to useswagger R package todisplay the swagger page. (#365)
Added support for swagger for mounted routers (
Secret session cookies are now encrypted usingsodium. All priorreq$session information willbe lost. Please see?session_cookie for more information.(#404)
Session cookies set theHttpOnly flag by default tomitigate cross-site scripting (XSS). Please see?session_cookie for more information. (#404)
Wrapjsonlite::fromJSON to ensure thatjsonlite never reads input as a remote address (such as afile path or URL) and attempts to parse that. The only known way toexploit this behavior in plumber unless an API were using encryptedcookies and an attacker knew the encryption key in order to craftarbitrary cookies. (#325)
Whenplumb()ing a file (orPlumber$new(file)), the working directory is set to thefile’s directory before parsing the file. When running the Plumber API,the working directory will be set to file’s directory beforerunning.(#631)
Plumber’s OpenAPI Specification is now defined usingOpenAPI3, upgrading from Swagger Specification. (#365)
Plumber router$run() method argumentsswagger,swaggerCallback anddebug are now deprecated. User interface and url callbackare now enabled by default and managed through Plumber router$setDocs(),$setDocsCallback(), and$setDebug() methods and optionsplumber.docsandplumber.docs.callback. (
plumb() now returns an object of class"Plumber" (previously"plumber"). To check ifan object is a Plumber router, use new methodis_plumber().(#653)
PlumberStatic objects now have a class of"PlumberStatic" (previously"plumberstatic").(#653)
The source files used in plumbermust use theUTF-8 encoding if they contain non-ASCII characters (
options(plumber.debug) is not set anymore whenrunning the plumber application. Instead retrieve the debug value using$getDebug() on the Plumber router directly. Ex:function(req, res) { req$pr$getDebug() }. (#639)
PlumberEndpoint’s method$exec() nowhas a shape of$exec(req, res) (vs$exec(...)). This allows for fine tune control over thearguments being sent to the endpoint function.
When creating aPlumberFilter orPlumberEndpoint, an error will be thrown ifexpr does not evaluate to a function. (#666)
Shorthand serializers are now deprecated.@html,@json,@png,@jpeg,@svg should be replaced with the@serializersyntax. Ex:@serializer html or@serializer jpeg (#630)
plumber R6 object has been deprecated and renamed toPlumber.PlumberStatic’sinherited class has been updated toPlumber.(#653)
hookable R6 object has been deprecated and renamedtoHookable.Plumber andPlumberStep’sinherited class has been updatedtoHookable. (#653)
addSerializer() has been deprecated in favor ofregister_serializer() (#584)
getCharacterSet() has been deprecated in favor ofget_character_set() (#651)
randomCookieKey() has been deprecated in favor ofrandom_cookie_key() (#651)
sessionCookie() has been deprecated in favor ofsession_cookie() (#651)
DigitalOcean helper functions are now defunct(do_*()). The functionality and documentation on how todeploy to DigitalOcean has been moved toplumberDeploy(by@meztez)(#649)
Documentation is updated and now presented usingpkgdown (#570)
New hex logo! Thank you
Added helper methodis_plumber(pr) to determine ifan object is a Plumber router. (#653)
Added support for theSameSite Cookie attribute.(@chris-dudley,#640)
When callinginclude_file(), thecontent_type is automatically inferred from the fileextension ifcontent_type is not provided. (#631)
Whenplumb()ing a file, arguments supplied toparsers and serializers may be values defined earlier in the file.(@meztez,#620)
Updated Docker files. New Docker repo is nowrstudio/plumber.Updates heavily inspired from
Support HTTP 405 Code. (
Attached the Plumber router to the incoming request object atreq$pr. (
Documented plumber options. Addedoptions_plumber().(@meztez,#555)
Update documentation on R6 objects (
Fixplumb() function whenplumb()ing adirectory so thatplumber.R is not a requirement if a validentrypoint.R file is found. (
If cookie information is too large (> 4093 bytes), a warningwill be displayed. (#404)
Added new shorthand types for url parameters. (
Plumber files are now only evaluated once. Prior plumber behaviorsourced endpoint functions twice and non-endpoint code blocks once.(#328)
Improve speed ofcanServe() method of thePlumberEndpoint class (
Get more file extension content types using themimepackage. (#660)
Endpoints that produce images within apromises::promise() will now use the expected graphicsdevice. (#669)
Handle plus signs in URI as space characters instead of actualplus signs (@meztez,#618)
Paths that are missing a leading/ have a/ prepended to the path location. (#656)
Fix possible bugs due to mounted routers without leading slashes(@atheriel, #476#501).
Modified images serialization to use content-type serializer.Fixes issue with images pre/postserialize hooks (
Fix bug preventing error handling when a serializer fails (
Fix URL-decoding of query parameters and URL-encoding/decoding ofcookies. Both now usehttpuv::decodeURIComponent instead ofhttpuv::decodeURI. (
Fixed bug where functions defined earlier in the file could notbe found whenplumb()ing a file. (#416)
A multiline request body is now collapsed to a single line (
Bumped version of httpuv to >= 1.4.5.9000 to address anunexpected segfault (
Date response header is now supplied by httpuv and not plumber.Fixes non standard date response header issues when using differentlocales. (@shrektan,#319, #380)
Due to incompatibilities withmultipart body values,req$postBody will only be calculated if accessed. It isstrongly recommended to usereq$bodyRaw when trying tocreate content from the input body. (#665)
value argument(postroute,preserialize, andpostserialize) now modify the incoming value asdocumented.postserialize hook is now given theserialized data as itsvalue parameter.swaggerCallback parameter forrun() to supply a callback function for reporting the urlfor swagger page.@png and@jpeg now accept a parenthetical list of arguments thatwill be passed into thepng() orjpeg() call.This enables annotations like#' @png (width = 200, height=500).ByteCompile flagsetErrorHandlerPlumberStaticplumber.r andentrypoint.r whenplumb()ing a directory.swagger.jsonfile was hosted in such a way that a hosted validator service would nothave been able to access it. For now we just suppress validation ofswagger.json files. (#149)do_configure_https()do_provision() soyou can now call that on a single droplet multiple times.exit hook which can define a function thatwill be evaluated when the API is interrupted. e.g.pr <- plumb("plumber.R"); pr$registerHook("exit", function(){ print("Bye bye!") }). in string path segmentsAccess-Control-Allow-Origin HTTP header to*.This was previously done for convenience but we’ve decided to prioritizesecurity here by removing this default. You can still add this header toany route you want to be accessible from other origins.port parameter inrun(), or by setting theplumber.portoption.PlumberProcessor class and replacedwith a notion of hooks. SeeregisterHook andregisterHooks on the Plumber router.addGlobalProcessor method on Plumber routersnow takes a list which are added as hooks instead of a Processor. NotethatsessionCookie has also been updated to behaveaccordingly, meaning that the convention ofpr$addGlobalProcessor(sessionCookie("secret", "cookieName"))will continue to work for this release.sessionCookie now returns a list instead of aProcessor. Note thataddGlobalProcessor has also beenupdated to behave accordingly, meaning that the convention ofpr$addGlobalProcessor(sessionCookie("secret", "cookieName"))will continue to work for this release.addAssets method on Plumberrouters. UsePlumberStatic and themountmethod to attach a static router.addEndpoint method in favorof thehandle method for Plumber routers. Removed supportfor theprocessors,params, andcomments parameters are no longer supported.addFilter method on Plumberrouters in favor of the newfilter method. Removed supportfor the processor parameter.addGlobalProcessor methodon Plumber routers.setDefaultErrorHandler method onPlumber routers now takes a function that returns the error handlerfunction. The top-level function takes a single param nameddebug which is managed by thedebug parameterin therun() method.OPTIONS HTTP requests via the@options annotation.entrypoint.R whenplumb()ing a directory. If this file exists, it is expectedto return a Plumber router representing the API contained in thisdirectory. If it doesn’t exist, the behavior is unaltered. If bothplumber.R andentrypoint.R exist,entrypoint.R takes precedence.plumb() the current directory by default if noarguments are provided.debug parameter to therun methodwhich can be set toTRUE in order to get more insight intoyour API errors.plumb() now accepts an argumentdir,referring to a directory containingplumber.R, which may beprovided instead offile.do_provision(),do_deploy_api(),do_remove_api() anddo_configure_https() functions to provision and manage yourAPIs on a cloud server running on DigitalOcean.source() the referenced R file to plumb inside of a newenvironment that inherits directly from the GlobalEnv. This providesmore explicit control over exactly how this environment shouldbehave.@serializer htmlwidget to support rendering andreturning a self-contained htmlwidget from a plumber endpoint.+ character in a query string to aspace.addSerializer() nowexpects a function that returns a serializer, andResponse$new() now expects a serializer itself rather thana character string naming a serializer. Internally it is the serializeritself that is attached to the response rather than the name of theserializer. This allows for a serializer to customize its behavior.@serializerannotation – R code that will be passed in as an argument to theserializer factory. See example09-content-type.sessionCookie function to define a processor thatcan be used as a globalProcessor on a router to encrypt values fromreq$session and store them as an encrypted cookie in on the user’sbrowser.setCookie method to response which (primitively)allows you to set a cookie to be included in the response.addGlobalProcessor method onplumberclass to support a processor that runs a processor only a single time,before and then after all other filters and the endpoint.roxygen2 documentation for exportedfunctionsPlumberRouter R6 object to justPlumber.addEndpoint() andaddFilter() onthePlumber object.#* prefix.