Skip to content

plumber v1.0.0

Compare
Choose a tag to compare
@schloerke schloerke released this 14 Sep 22:02
c051c6b

New features

Plumber router

  • Added support for promises in endpoints, filters, and hooks. This allows for multi-core execution when paired with future. See plumb_api("plumber", "13-promises") and plumb_api("plumber", "14-future") for example implementations. (#248)

  • Added a Tidy API for more natural usage with magrittr's %>%. For example, a plumber object can now be initiated and run with pr() %>% pr_run(port = 8080). For more examples, see here (@blairj09, #590)

  • Added support for #' @plumber tag to gain programmatic access to the plumber router via function(pr) {....}. See system.file("plumber/06-sessions/plumber.R", package = "plumber") and how it adds cookie support from within plumber.R. (@meztez and @blairj09, #568)

  • Added plumb_api() for standardizing where to locate (inst/plumber) and how to run (plumb_api(package, name)) plumber apis inside an R package. To view the available Plumber APIs, call available_apis(). (#631)

  • Improved argument handling in Plumber Endpoint route definitions. See system.file("plumber/17-arguments/plumber.R", package = "plumber") to view an example with expected output and plumb_api("plumber", "17-arguments") to retrieve the api. Improvements include:

    • The value supplied to req and res arguments in a route definition are now always Plumber request and response objects. In the past, this was not guaranteed. (#666, #637)
    • To assist with conflicts in argument names deriving from different locations, req$argsQuery, req$argsPath, and req$argsBody have been added to access query, path, and req$body parameters, respectively. For this reason, we suggest defining routes with only req and res (i.e., function(req, res) {}) and accessing argument(s) under these new fields to avoid naming conflicts. (#637)
    • An error is no longer thrown if multiple arguments are matched to an Plumber Endpoint route definition. Instead, Plumber now retains the first named argument according to the highest priority match (req$argsQuery is 1st priority, then req$argsPath, then req$argsBody). (#666)
    • Unnamed elements that are added to req$args by filters or creating req$argsBody will no longer throw an error. They will only be passed through via ... (#666)

OpenAPI

  • API Documentation is now hosted at /__docs__. If swagger documentation is being used, /__swagger__ will redirect to /__docs__. (#654)

  • Added OpenAPI support for array parameters using syntax name:[type] and new type list (synonym df, data.frame). (@meztez, #532)

  • Added user provided OpenAPI Specification handler to Plumber router. Use $setApiSpec() to provide a function to alter the Plumber generated OpenAPI Specification returned by Plumber router method $getApiSpec(). This also affects /openapi.json and /openapi.yaml (#365)(@meztez, #562)

  • Added validate_api_spec() to validate a Plumber API produces a valid OpenAPI Specification. (Experimental!) (#633)

Serializers

  • Added as_attachment(value, filename) method which allows routes to return a file attachment with a custom name. (#585)

  • Serializer functions can now return PlumberEndpoint preexec and postexec hooks in addition to a serializer function by using endpoint_serializer(). This allows for image serializers to turn on their corresponding graphics device before the route executes and turn the graphics device off after the route executes. (#630)

  • PNG, JPEG, and SVG image serializers have been exported in methods serializer_png(), serializer_jpeg(), and serializer_svg() respectively. In addition to these methods, serializer_tiff(), serializer_bmp(), and serializer_pdf() have been added. Each graphics device serializer wraps around serializer_device(), which should be used when making more graphics device serializers. (#630)

  • New serializers

    • serializer_yaml(): Return an object serialized by yaml (@meztez, #556)
    • serializer_csv(): Return a comma separated value (@pachamaltese, #520)
    • serializer_tsv(): Return a tab separated value (#630)
    • serializer_feather(): Return a object serialized by feather (#626)
    • serializer_text(): Return text content (#585)
    • serializer_cat(): Return text content after calling cat() (#585)
    • serializer_print(): Return text content after calling print() (#585)
    • serializer_format(): Return text content after calling format() (#585)
    • serializer_svg(): Return an image saved as an SVG (@pachamaltese, #398)
    • serializer_headers(header_list): Method which sets a list of static headers for each serialized value. Heavily inspired from @ycphs (#455). (#585)
    • serializer_write_file(): Method which wraps serializer_content_type(), but orchestrates creating, writing serialized content to, reading from, and removing a temp file. (#660)

Body parsing

  • Added support for request body parsing (@meztez, #532)

  • New request body parsers

    • parser_csv(): Parse request body as a commas separated value (#584)
    • parser_json(): Parse request body as JSON (@meztez, #532)
    • parser_multi(): Parse multi part request bodies (@meztez, #532) and (#663)
    • parser_octet(): Parse request body octet stream (@meztez, #532)
    • parser_form(): Parse request body as form input (@meztez, #532)
    • parser_rds(): Parse request body as RDS file input (@meztez, #532)
    • parser_text(): Parse request body plain text (@meztez, #532)
    • parser_tsv(): Parse request body a tab separated value (#584)
    • parser_yaml(): Parse request body as yaml (#584)
    • parser_none(): Do not parse the request body (#584)
    • parser_yaml(): Parse request body (@meztez, #556)
    • parser_feather(): Parse request body using feather (#626)
    • Pseudo parser named "all" to allow for using all parsers. (Not recommended in production!) (#584)
  • The parsed request body values is stored at req$body. (#663)

  • If multipart/* content is parsed, req$body will contain named output from webutils::parse_multipart() and add the parsed value to each part. Look here for access to all provided information (e.g., name, filename, content_type, etc). In addition, req$argsBody (which is used for route argument matching) will contain a named reduced form of this information where parsed values (and filenames) are combined on the same name. (#663)

Visual Documentation

Security improvements

  • Secret session cookies are now encrypted using sodium.
    All prior req$session information will be lost.
    Please see ?session_cookie for more information.
    (#404)

  • Session cookies set the HttpOnly flag by default to mitigate cross-site scripting (XSS).
    Please see ?session_cookie for more information.
    (#404)

  • Wrap jsonlite::fromJSON to ensure that jsonlite never reads
    input as a remote address (such as a file path or URL) and attempts to parse
    that. The only known way to exploit this behavior in plumber unless an
    API were using encrypted cookies and an attacker knew the encryption key in
    order to craft arbitrary cookies. (#325)

Breaking changes

  • When plumb()ing a file (or Plumber$new(file)), the working directory is set to the file's directory before parsing the file. When running the Plumber API, the working directory will be set to file's directory before running.(#631)

  • Plumber's OpenAPI Specification is now defined using
    OpenAPI 3,
    upgrading from Swagger Specification. (#365)

  • Plumber router $run() method arguments swagger, swaggerCallback and debug are now deprecated. User interface and url callback are now enabled by default and managed through Plumber router $setDocs(), $setDocsCallback(), and $setDebug() methods and options plumber.docs and plumber.docs.callback. (@meztez, #562)

  • plumb() now returns an object of class "Plumber" (previously "plumber"). To check if an object is a Plumber router, use new method is_plumber(). (#653)

  • PlumberStatic objects now have a class of "PlumberStatic" (previously "plumberstatic"). (#653)

  • The source files used in plumber must use the UTF-8 encoding if they contain
    non-ASCII characters (@shrektan, #312,
    #328).

  • options(plumber.debug) is not set anymore when running 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() now has a shape of $exec(req, res) (vs $exec(...)). This allows for fine tune control over the arguments being sent to the endpoint function.

  • When creating a PlumberFilter or PlumberEndpoint, an error will be thrown if expr does not evaluate to a function. (#666)

Deprecations

  • Shorthand serializers are now deprecated. @html, @json, @png, @jpeg, @svg should be replaced with the @serializer syntax. Ex: @serializer html or @serializer jpeg (#630)

  • plumber R6 object has been deprecated and renamed to Plumber. PlumberStatic's inherited class has been updated to Plumber. (#653)

  • hookable R6 object has been deprecated and renamed to Hookable. Plumber and PlumberStep's inherited class has been updated to Hookable. (#653)

  • addSerializer() has been deprecated in favor of register_serializer() (#584)

  • getCharacterSet() has been deprecated in favor of get_character_set() (#651)

  • randomCookieKey() has been deprecated in favor of random_cookie_key() (#651)

  • sessionCookie() has been deprecated in favor of session_cookie() (#651)

  • DigitalOcean helper functions are now defunct (do_*()). The functionality and documentation on how to deploy to DigitalOcean has been moved to plumberDeploy (by @meztez) (#649)

Minor new features and improvements

  • Documentation is updated and now presented using pkgdown (#570)

  • New hex logo! Thank you @allisonhorst ! (#570)

  • Added helper method is_plumber(pr) to determine if an object is a Plumber router. (#653)

  • Added support for the SameSite Cookie attribute. (@chris-dudley, #640)

  • When calling include_file(), the content_type is automatically inferred from the file extension if content_type is not provided. (#631)

  • When plumb()ing a file, arguments supplied to parsers and serializers may be values defined earlier in the file. (@meztez, #620)

  • Updated Docker files. New Docker repo is now rstudio/plumber. Updates heavily inspired from @mskyttner (#459). (#589)

  • Support HTTP 405 Code. (@meztez, #554)

  • Attached the Plumber router to the incoming request object at req$pr. (@meztez, #554)

  • Documented plumber options. Added options_plumber(). (@meztez, #555)

  • Update documentation on R6 objects (@meztez, #530)

  • Fix plumb() function when plumb()ing a directory so that plumber.R is not a requirement if a valid entrypoint.R file is found. (@blairj09, #471).

  • If cookie information is too large (> 4093 bytes), a warning will be displayed. (#404)

  • Added new shorthand types for url parameters. (@byzheng, #388)

  • Plumber files are now only evaluated once. Prior plumber behavior sourced endpoint functions twice and non-endpoint code blocks once. (#328)

  • Improve speed of canServe() method of the PlumberEndpoint class (@atheriel, #484)

  • Get more file extension content types using the mime package. (#660)

  • Endpoints that produce images within a promises::promise() will now use the expected graphics device. (#669)

Bug fixes

  • Handle plus signs in URI as space characters instead of actual plus 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 (@meztez, #518).

  • Fix bug preventing error handling when a serializer fails (@antoine-sachet, #490)

  • Fix URL-decoding of query parameters and URL-encoding/decoding of cookies. Both now use httpuv::decodeURIComponent instead of httpuv::decodeURI. (@antoine-sachet, #462)

  • Fixed bug where functions defined earlier in the file could not be found when plumb()ing a file. (#416)

  • A multiline request body is now collapsed to a single line (@robertdj, #270 #297).

  • Bumped version of httpuv to >= 1.4.5.9000 to address an unexpected segfault (@shapenaji, #289)

  • Date response header is now supplied by httpuv and not plumber. Fixes non standard date response header issues when using different locales. (@shrektan, #319, #380)

  • Due to incompatibilities with multipart body values, req$postBody will only be calculated if accessed. It is strongly recommended to use req$bodyRaw when trying to create content from the input body. (#665)