diff --git a/NEWS.md b/NEWS.md index 8bb6209c9..b4c35410f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,6 +5,8 @@ plumber 1.0.0.9999 Development version * When calling `Plumber$handle()` and defining a new `PlumberEndpoint`, `...` will be checked for invalid names #677 +* `/__swagger__/` now always redirect to `/__docs__/`, even when Swagger isn't the selected interface. Use `options(plumber.legacyRedirects = FALSE)` to disable this behavior (. (@blairj09 #694) + plumber 1.0.0 -------------------------------------------------------------------------------- diff --git a/R/plumber-options.R b/R/plumber-options.R index a2919a362..aed685be2 100644 --- a/R/plumber-options.R +++ b/R/plumber-options.R @@ -29,9 +29,12 @@ #' \item{`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`.} +#' \item{`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`} #' } #' -#' @param port,docs,docs.callback,apiScheme,apiHost,apiPort,apiPath,apiURL,maxRequestSize,sharedSecret See details +#' @param port,docs,docs.callback,apiScheme,apiHost,apiPort,apiPath,apiURL,maxRequestSize,sharedSecret,legacyRedirects See details #' @return #' The complete, prior set of [options()] values. #' If a particular parameter is not supplied, it will return the current value. @@ -47,7 +50,8 @@ options_plumber <- function( apiPort = getOption("plumber.apiPort"), apiPath = getOption("plumber.apiPath"), maxRequestSize = getOption("plumber.maxRequestSize"), - sharedSecret = getOption("plumber.sharedSecret") + sharedSecret = getOption("plumber.sharedSecret"), + legacyRedirects = getOption("plumber.legacyRedirects") ) { options( plumber.apiScheme = apiScheme, @@ -59,6 +63,7 @@ options_plumber <- function( plumber.port = port, plumber.sharedSecret = sharedSecret, plumber.docs = docs, - plumber.docs.callback = docs.callback + plumber.docs.callback = docs.callback, + plumber.legacyRedirects = legacyRedirects ) } diff --git a/R/ui.R b/R/ui.R index 864c4d805..fd7757bb6 100644 --- a/R/ui.R +++ b/R/ui.R @@ -180,8 +180,6 @@ register_docs <- function(name, index, static = NULL) { stopifnot(is.function(index)) if (!is.null(static)) stopifnot(is.function(static)) - is_swagger <- isTRUE(name == "swagger") - docs_root <- paste0("/__docs__/") docs_paths <- c("/index.html", "/") @@ -213,12 +211,10 @@ register_docs <- function(name, index, static = NULL) { pr$mount(docs_root, docs_router) - # add legacy swagger redirects - if (is_swagger) { - redirect_info <- swagger_redirects() - for (path in names(redirect_info)) { - pr_get(pr, path, redirect_info[[path]]) - } + # add legacy swagger redirects (RStudio Connect) + redirect_info <- swagger_redirects() + for (path in names(redirect_info)) { + pr_get(pr, path, redirect_info[[path]]) } docs_url <- paste0(api_url, docs_root) @@ -228,12 +224,11 @@ register_docs <- function(name, index, static = NULL) { pr$unmount(docs_root) # remove legacy swagger redirects - if (is_swagger) { - redirect_info <- swagger_redirects() - for (path in names(redirect_info)) { - pr$removeHandle("GET", path) - } + redirect_info <- swagger_redirects() + for (path in names(redirect_info)) { + pr$removeHandle("GET", path) } + invisible() } @@ -261,10 +256,14 @@ swagger_redirects <- function() { res } } - list( - "/__swagger__/" = to_route("../__docs__/"), - "/__swagger__/index.html" = to_route("../__docs__/index.html") - ) + if (isTRUE(getOption("plumber.legacyRedirects", TRUE))) { + list( + "/__swagger__/" = to_route("../__docs__/"), + "/__swagger__/index.html" = to_route("../__docs__/index.html") + ) + } else { + list() + } } diff --git a/man/Plumber.Rd b/man/Plumber.Rd index e822fcc98..585a6d364 100644 --- a/man/Plumber.Rd +++ b/man/Plumber.Rd @@ -13,7 +13,7 @@ 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 \href{../articles/programmatic-usage.html}{here} for additional +See the \href{https://www.rplumber.io/articles/programmatic-usage.html}{Programmatic Usage} article for additional details on the methods available on this object. } \examples{ diff --git a/man/options_plumber.Rd b/man/options_plumber.Rd index fb8bb4df3..4c954d95c 100644 --- a/man/options_plumber.Rd +++ b/man/options_plumber.Rd @@ -14,11 +14,12 @@ options_plumber( apiPort = getOption("plumber.apiPort"), apiPath = getOption("plumber.apiPath"), maxRequestSize = getOption("plumber.maxRequestSize"), - sharedSecret = getOption("plumber.sharedSecret") + sharedSecret = getOption("plumber.sharedSecret"), + legacyRedirects = getOption("plumber.legacyRedirects") ) } \arguments{ -\item{port, docs, docs.callback, apiScheme, apiHost, apiPort, apiPath, apiURL, maxRequestSize, sharedSecret}{See details} +\item{port, docs, docs.callback, apiScheme, apiHost, apiPort, apiPath, apiURL, maxRequestSize, sharedSecret, legacyRedirects}{See details} } \value{ The complete, prior set of \code{\link[=options]{options()}} values. @@ -56,5 +57,8 @@ than maximum are rejected with http error 413. \code{0} means unlimited size. De \item{\code{plumber.sharedSecret}}{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. Defaults to \code{NULL}.} +\item{\code{plumber.legacyRedirects}}{Plumber will redirect legacy route \verb{/__swagger__/} and +\verb{/__swagger__/index.html} to \verb{../__docs__/} and \verb{../__docs__/index.html}. You can disable this +by settings this option to \code{FALSE}. Defaults to \code{TRUE}} } } diff --git a/man/parsers.Rd b/man/parsers.Rd index 03e5d8fca..2b956580a 100644 --- a/man/parsers.Rd +++ b/man/parsers.Rd @@ -54,13 +54,13 @@ non-default behavior. } \details{ Parsers are optional. When unspecified, only default endpoint parsers are enabled. -You can use \verb{@parser parser} tag to enable parser on endpoint. -Multiple parsers can be enabled on the same endpoint using multiple \verb{@parser parser} tags. +You can use \verb{@parser NAME} tag to enable parser on endpoint. +Multiple parsers can be enabled on the same endpoint using multiple \verb{@parser NAME} tags. User should be aware that \code{rds} parsing should only be done from a trusted source. Do not accept \code{rds} files blindly. -See \code{\link[=registered_parsers]{registered_parsers()}} for a list of registered parsers aliases. +See \code{\link[=registered_parsers]{registered_parsers()}} for a list of registered parsers names. } \section{Functions}{ \itemize{ diff --git a/man/plumb.Rd b/man/plumb.Rd index 59e0e5eaf..57ead3d4a 100644 --- a/man/plumb.Rd +++ b/man/plumb.Rd @@ -22,6 +22,6 @@ 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 \href{../articles/programmatic-usage.html}{here} for additional +See the \href{https://www.rplumber.io/articles/programmatic-usage.html}{Programmatic Usage} article for additional details on the methods available on this object. } diff --git a/man/pr_set_parsers.Rd b/man/pr_set_parsers.Rd index 33efa4219..125090637 100644 --- a/man/pr_set_parsers.Rd +++ b/man/pr_set_parsers.Rd @@ -42,5 +42,5 @@ default parsers for any endpoint that does not define their own parsers. } \details{ 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 \code{registered_parsers()} to get a list of available parsers aliases. +Use \code{registered_parsers()} to get a list of available parser names. } diff --git a/man/register_parser.Rd b/man/register_parser.Rd index d0a2c420e..0d92137d7 100644 --- a/man/register_parser.Rd +++ b/man/register_parser.Rd @@ -29,11 +29,10 @@ For instance, \code{\link[=parser_json]{parser_json()}} parse content-type \code \details{ When \code{parser} is evaluated, it should return a parser function. Parser matching is done first by \code{content-type} header matching with \code{fixed} then by using -regular expressions with \code{regex}. Note that plumber strip \verb{; charset*} from \code{content-type} header before -performing match. +regular expressions with \code{regex}. Note that plumber strips \verb{; charset*} from \code{content-type} header before matching. -It will try to use \code{\link[=parser_json]{parser_json()}} if available when no \code{content-type} header is found and -request body starts with \verb{\{} or \code{[}. +Plumber will try to use \code{\link[=parser_json]{parser_json()}} (if available) when no \code{content-type} header is found and +the request body starts with \verb{\{} or \code{[}. Functions signature should include \code{value}, \code{...} and possibly \code{content_type}, \code{filename}. Other parameters may be provided diff --git a/man/serializers.Rd b/man/serializers.Rd index 711493295..1e4321464 100644 --- a/man/serializers.Rd +++ b/man/serializers.Rd @@ -109,7 +109,7 @@ The graphics device \code{dev_on} function will receive any arguments supplied t \description{ 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 -\href{../articles/rendering-output.html#serializers-1}{here} for +\href{https://www.rplumber.io/articles/rendering-output.html#serializers-1}{here} for more details on Plumber serializers and how to customize their behavior. } \section{Functions}{