diff --git a/DESCRIPTION b/DESCRIPTION index dc28ee72e..737575a74 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -67,6 +67,7 @@ Collate: 'openapi-spec.R' 'openapi-types.R' 'paths.R' + 'plumber-options.R' 'plumber-response.R' 'plumber-static.R' 'plumber-step.R' diff --git a/NAMESPACE b/NAMESPACE index 65c320e45..a111c3ca3 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -16,6 +16,7 @@ export(include_file) export(include_html) export(include_md) export(include_rmd) +export(options_plumber) export(parser_json) export(parser_multi) export(parser_octet) diff --git a/NEWS.md b/NEWS.md index 75cdec3df..0552f533c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -48,6 +48,8 @@ plumber 0.5.0 ### New features +* Document plumber options. Add `options_plumber`. (@meztez, #555) + * Add yaml support, serializer and parser. (@meztez, #556) * Added Swagger support for array parameters using syntax `name:[type]` and new type `list` (synonym df, data.frame). (@meztez, #532) diff --git a/R/plumber-options.R b/R/plumber-options.R new file mode 100644 index 000000000..4f82e7c7a --- /dev/null +++ b/R/plumber-options.R @@ -0,0 +1,61 @@ + +#' How to use Plumber options +#' +#' @section Options: +#' There are a number of global options that affect Plumber's behavior. These can +#' be set globally with [options()] or with [options_plumber()]. +#' +#' \describe{ +#' \item{plumber.apiHost (defaults to `host` defined by `run` method, or an empty string +#' when used outside a running router)}{Host used to build UI url and server url for +#' OpenAPI specification.} +#' \item{plumber.debug (defaults to `FALSE`)}{Provides more insight into your API errors. Alternatively, +#' use parameter `debug` of plumber router `run` method} +#' \item{plumber.maxRequestSize (defaults to `0`)}{Maximum length in bytes of request body. Body larger +#' than maximum are rejected with http error 413. `0` means unlimited size.} +#' \item{plumber.postBody (defaults to `TRUE`)}{Copy post body content to `req$postBody` using system encoding. +#' This should be set to `FALSE` if you do not need it. Default is `TRUE` to preserve compatibility with +#' previous version behavior.} +#' \item{plumber.port (defaults to `NULL`)}{Port Plumber will attempt to use to start http server. +#' If the port is already in use, server will not be able to start.} +#' \item{plumber.sharedSecret (defaults to `NULL`)}{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.} +#' \item{plumber.swagger.url (defaults to `NULL`)}{A function. Called with +#' a single parameter corresponding to ui url after Plumber server is ready. This can be used +#' by RStudio to open UI when API is ran for the editor.} +#' } +#' @aliases plumber-options +"_PACKAGE" + +#' Set plumber options +#' @param apiHost see [plumber-options] +#' @param debug see [plumber-options] +#' @param maxRequestSize see [plumber-options] +#' @param postBody see [plumber-options] +#' @param port see [plumber-options] +#' @param sharedSecret see [plumber-options] +#' @param swagger.url see [plumber-options] +#' @details +#' Sets plumber options. Call without arguments to get current +#' values. +#' @export +options_plumber <- function( + apiHost = getOption("plumber.apiHost"), + debug = getOption("plumber.debug"), + maxRequestSize = getOption("plumber.maxRequestSize"), + postBody = getOption("plumber.postBody"), + port = getOption("plumber.port"), + sharedSecret = getOption("plumber.sharedSecret"), + swagger.url = getOption("plumber.swagger.url") +) { + options( + plumber.apiHost = apiHost, + plumber.debug = debug, + plumber.maxRequestSize = maxRequestSize, + plumber.postBody = postBody, + plumber.port = port, + plumber.sharedSecret = sharedSecret, + plumber.swagger.url = swagger.url + ) +} diff --git a/man/options_plumber.Rd b/man/options_plumber.Rd new file mode 100644 index 000000000..9211109e6 --- /dev/null +++ b/man/options_plumber.Rd @@ -0,0 +1,38 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/plumber-options.R +\name{options_plumber} +\alias{options_plumber} +\title{Set plumber options} +\usage{ +options_plumber( + apiHost = getOption("plumber.apiHost"), + debug = getOption("plumber.debug"), + maxRequestSize = getOption("plumber.maxRequestSize"), + postBody = getOption("plumber.postBody"), + port = getOption("plumber.port"), + sharedSecret = getOption("plumber.sharedSecret"), + swagger.url = getOption("plumber.swagger.url") +) +} +\arguments{ +\item{apiHost}{see \link{plumber-options}} + +\item{debug}{see \link{plumber-options}} + +\item{maxRequestSize}{see \link{plumber-options}} + +\item{postBody}{see \link{plumber-options}} + +\item{port}{see \link{plumber-options}} + +\item{sharedSecret}{see \link{plumber-options}} + +\item{swagger.url}{see \link{plumber-options}} +} +\description{ +Set plumber options +} +\details{ +Sets plumber options. Call without arguments to get current +values. +} diff --git a/man/plumber-package.Rd b/man/plumber-package.Rd new file mode 100644 index 000000000..653a7ad3a --- /dev/null +++ b/man/plumber-package.Rd @@ -0,0 +1,66 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/plumber-options.R +\docType{package} +\name{plumber-package} +\alias{plumber-package} +\alias{_PACKAGE} +\alias{plumber-options} +\title{How to use Plumber options} +\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. +} +\section{Options}{ + +There are a number of global options that affect Plumber's behavior. These can +be set globally with \code{\link[=options]{options()}} or with \code{\link[=options_plumber]{options_plumber()}}. + +\describe{ +\item{plumber.apiHost (defaults to \code{host} defined by \code{run} method, or an empty string +when used outside a running router)}{Host used to build UI url and server url for +OpenAPI specification.} +\item{plumber.debug (defaults to \code{FALSE})}{Provides more insight into your API errors. Alternatively, +use parameter \code{debug} of plumber router \code{run} method} +\item{plumber.maxRequestSize (defaults to \code{0})}{Maximum length in bytes of request body. Body larger +than maximum are rejected with http error 413. \code{0} means unlimited size.} +\item{plumber.postBody (defaults to \code{TRUE})}{Copy post body content to \code{req$postBody} using system encoding. +This should be set to \code{FALSE} if you do not need it. Default is \code{TRUE} to preserve compatibility with +previous version behavior.} +\item{plumber.port (defaults to \code{NULL})}{Port Plumber will attempt to use to start http server. +If the port is already in use, server will not be able to start.} +\item{plumber.sharedSecret (defaults to \code{NULL})}{Shared secret used to filter incoming request. +When \code{NULL}, secret is not validated. Otherwise, Plumber compares secret with http header +\code{PLUMBER_SHARED_SECRET}. Failure to match results in http error 400.} +\item{plumber.swagger.url (defaults to \code{NULL})}{A function. Called with +a single parameter corresponding to ui url after Plumber server is ready. This can be used +by RStudio to open UI when API is ran for the editor.} +} +} + +\seealso{ +Useful links: +\itemize{ + \item \url{https://www.rplumber.io (site) + https://github.com/rstudio/plumber (dev)} + \item Report bugs at \url{https://github.com/rstudio/plumber/issues} +} + +} +\author{ +\strong{Maintainer}: Barret Schloerke \email{barret@rstudio.com} + +Authors: +\itemize{ + \item Jeff Allen \email{cran@trestletech.com} [conceptor] +} + +Other contributors: +\itemize{ + \item Bruno Tremblay \email{bruno.tremblay@lacapitale.com} [contributor] + \item Frans van Dunné \email{frans@ixpantia.com} [contributor] + \item Sebastiaan Vandewoude \email{sebastiaanvandewoude@gmail.com} [contributor] + \item RStudio [copyright holder, funder] +} + +} diff --git a/tests/testthat/test-options.R b/tests/testthat/test-options.R new file mode 100644 index 000000000..cb365e1de --- /dev/null +++ b/tests/testthat/test-options.R @@ -0,0 +1,44 @@ +context("Options") + +test_that("Options set and get", { + option_value <- getOption("plumber.postBody") + options_plumber(postBody = FALSE) + expect_false(getOption("plumber.postBody")) + options_plumber(postBody = NULL) + expect_null(getOption("plumber.postBody")) + options(plumber.postBody = option_value) +}) + +test_that("all options used are `options_plumber()` parameters", { + skip_on_cran() # only test in CI / locally + + ## `./R` will not exist when shiny is installed + r_folder <- "../../R" + if ( + # not local structure + !dir.exists(r_folder) || + # must contain many files, not just the three files typically found in installed folder + length(dir(r_folder)) < 10 + ) { + skip("Not testing locally. Skipping") + } + + matches <- character() + for (r_file in dir(r_folder, full.names = T)) { + file_content <- paste0(readLines(r_file, warn = F), collapse = "") + match <- stringi::stri_match_all_regex(file_content, "getOption\\([^,\\)]+,?\\)?")[[1]][,1] + match <- gsub("\\s", "", match) + if (length(match) > 0 && !is.na(match)) { + matches <- c(matches, match) + } + } + options_used <- unique(sort(gsub("getOption|\\(|\"|,|'|\\)", "", matches))) + plumber_options_used <- grep("^plumber", options_used, value = TRUE) + ### code to match formals + options_plumber_formals <- paste0("plumber.", sort(names(formals(optionsPlumber)))) + + expect_equal( + plumber_options_used, + options_plumber_formals + ) +})