Title: Fake Web Apps for HTTP Testing
Version: 1.3.1
Description: Create a web app that makes it easier to test web clients without using the internet. It includes a web app framework with path matching, parameters and templates. Can parse various 'HTTP' request bodies. Can send 'JSON' data or files from the disk. Includes a web app that implements the 'httpbin.org' web service.
License: MIT + file LICENSE
URL: https://webfakes.r-lib.org/, https://github.com/r-lib/webfakes
BugReports: https://github.com/r-lib/webfakes/issues
Depends: R (≥ 3.6)
Imports: stats, tools, utils
Suggests: brotli, callr, covr, curl, digest, glue, httpuv, httr, jsonlite, processx, testthat (≥ 3.0.0), withr, xml2, zip (≥ 2.3.0)
Config/Needs/website: tidyverse/tidytemplate
Config/testthat/edition: 3
Encoding: UTF-8
RoxygenNote: 7.2.3
NeedsCompilation: yes
Packaged: 2024-04-25 08:50:55 UTC; gaborcsardi
Author: Gábor Csárdi [aut, cre], Posit Software, PBC [cph, fnd], Civetweb contributors [ctb] (see inst/credits/ciwetweb.md), Redoc contributors [ctb] (see inst/credits/redoc.md), L. Peter Deutsch [ctb] (src/md5.h), Martin Purschke [ctb] (src/md5.h), Aladdin Enterprises [cph] (src/md5.h), Maëlle Salmon ORCID iD [ctb]
Maintainer: Gábor Csárdi <csardi.gabor@gmail.com>
Repository: CRAN
Date/Publication: 2024-04-25 09:00:03 UTC

webfakes: Fake Web Apps for HTTP Testing

Description

Create a web app that makes it easier to test web clients without using the internet. It includes a web app framework with path matching, parameters and templates. Can parse various 'HTTP' request bodies. Can send 'JSON' data or files from the disk. Includes a web app that implements the 'httpbin.org' web service.

Author(s)

Maintainer: Gábor Csárdi csardi.gabor@gmail.com

Other contributors:

See Also

Useful links:


Web app that acts as a git http server

Description

It is useful for tests that need an HTTP git server.

Usage

git_app(
  git_root,
  git_cmd = "git",
  git_timeout = as.difftime(1, units = "mins"),
  filter = TRUE,
  cleanup = TRUE
)

Arguments

git_root

Path to the root of the directory tree to be served.

git_cmd

Command to call, by default it is "git". It may also be a full path to git.

git_timeout

A difftime object, time limit for the git command.

filter

Whether to support the filter capability in the server.

cleanup

Whether to clean up git_root when the app is garbage collected.

Examples


dir.create(tmp <- tempfile())
setwd(tmp)
system("git clone --bare https://github.com/cran/crayon")
system("git clone --bare https://github.com/cran/glue")
app <- git_app(tmp)
git <- new_app_process(app)
system(paste("git ls-remote", git$url("/crayon")))


webfakes glossary

Description

webfakes glossary

Webfakes glossary

The webfakes package uses vocabulary that is standard for web apps, especially those developed with Express.js, but not necessarily well known to all R package developers.

app

(Also: fake web app, webfakes app.) A web application that can be served by webfakes's web server, typically in another process, an app process. Sometimes we call it a fake web app, to emphasize that we use it for testing real web apps and APIs.

You can create a webfakes app with the new_app() function. A webfakes app is an R object that you can save to disk with saveRDS() , and you can also include it in your package.

You can start an with its ⁠$listen()⁠ method. Since the main R process runs that test suite code, you usually run them in a subprocess, see new_app_process() or local_app_process().

app process

(Also: web server process, webfakes subprocess.) An app process is an R subprocess, started from the main R process, to serve a webfakes app.

You can create an app process object with new_app_process() or local_app_process(). By default the actual process does not start yet, when you create it. You can start it explicitly with the ⁠$start⁠ method of the app process object, or by querying its URL with ⁠$url()⁠ or its port with ⁠$get_port()⁠.

For test cases, you typically start app processes at these places:

See the How-to for details about each.

handler

(Or handler function.) A handler is a route or a middleware.

handler stack

This is a stack of handler functions, which are called by the app one after the other, passing the request and response objects to them. Handlers typically manipulate the request and/or response objects. A terminal handler instructs the app to return the response to the HTTP client. A non-terminal handler tells the app to keep calling handlers, by returning the string "next".

httpbin app

This is an example app, which implements the excellent ⁠https://httpbin.org/⁠ web service. You can use it to simulate certain HTTP responses. It is most handy for HTTP clients, but potentially useful for other tools as well.

Use httpbin_app() to create an instance of this app.

middleware

A middleware is a handler function that is not bound to a path. It is called by the router, like other handler functions. It may manipulate the request or the response, or can have a side effect. Some example built-in middleware functions in webfakes:

You can also write your own middleware functions.

path matching

The router performs path matching when it goes over the handler stack. If the HTTP method and path of a route match the HTTP method and URL of the request, then the handler is called, otherwise it is not. Paths can have parameters and be regular expressions. See ?new_regexp() for regular expressions and "Path parameters" in ?new_app() for parameters.

route

A route is a handler function that is bound to certain paths of you web app. If the request URL matches the path of the route, then the handler function is called, to give it a chance to send the appropriate response. Route paths may have parameters or they can be regular expressions in webfakes.

routing

Routing is the process of going over the handlers stack, and calling handler functions, one after the other, until one handles the request. If a handler function is a route, then the router only calls it if its path matches the request URL.


Format a time stamp for HTTP

Description

Format a time stamp for HTTP

Usage

http_time_stamp(t = Sys.time())

Arguments

t

Date-time value to format, defaults to the current date and time. It must be a POSIXct object.

Value

Character vector, formatted date-time.


Generic web app for testing HTTP clients

Description

A web app similar to ⁠https://httpbin.org⁠. See its specific docs. You can also see these docs locally, by starting the app:

httpbin <- new_app_process(httpbin_app())
browseURL(httpbin$url())

Usage

httpbin_app(log = interactive())

Arguments

log

Whether to log requests to the standard output.

Value

A webfakes_app.

Examples

app <- httpbin_app()
proc <- new_app_process(app)
url <- proc$url("/get")
resp <- curl::curl_fetch_memory(url)
curl::parse_headers_list(resp$headers)
cat(rawToChar(resp$content))
proc$stop()

App process that is cleaned up automatically

Description

You can start the process with an explicit ⁠$start()⁠ call. Alternatively it starts up at the first ⁠$url()⁠ or ⁠$get_port()⁠ call.

Usage

local_app_process(app, ..., .local_envir = parent.frame())

Arguments

app

webfakes_app object, the web app to run.

...

Passed to new_app_process().

.local_envir

The environment to attach the process cleanup to. Typically a frame. When this frame finishes, the process is stopped.

See Also

new_app_process() for more details.


Middleware that calls a CGI script

Description

You can use it as an unconditional middleware in app$use(), as a handler on app$get(), app$post(), etc., or you can call it from a handler. See examples below.

Usage

mw_cgi(command, args = character(), timeout = as.difftime(Inf, units = "secs"))

Arguments

command

External command to run.

args

Arguments to pass to the external command.

timeout

Timeout for the external command. If the command does not terminate in time, the web server kills it and returns an 500 response.

Value

A function with signature

function(req, res, env = character())

See RFC 3875 for details on the CGI protocol.

The request body (if any) is passed to the external command as standard intput. mw_cgi() sets CONTENT_LENGTH, CONTENT_TYPE, GATEWAY_INTERFACE, PATH_INFO, QUERY_STRING, REMOTE_ADDR, REMOTE_HOST, REMOTE_USER, REQUEST_METHOD, SERVER_NAME, SERVER_PORT, SERVER_PROTOCOL, SERVER_SOFTEWARE.

It does not currently set the AUTH_TYPE, PATH_TRANSLATED, REMOTE_IDENT, SCRIPT_NAME environment variables.

The standard output of the external command is used to set the response status code, the response headers and the response body. Example output from git's CGI:

Status: 200 OK
Expires: Fri, 01 Jan 1980 00:00:00 GMT
Pragma: no-cache
Cache-Control: no-cache, max-age=0, must-revalidate
Content-Type: application/x-git-upload-pack-advertisement

000eversion 2
0015agent=git/2.42.0
0013ls-refs=unborn
0020fetch=shallow wait-for-done
0012server-option
0017object-format=sha1
0010object-info
0000

See Also

Other middleware: mw_cookie_parser(), mw_etag(), mw_json(), mw_log(), mw_multipart(), mw_range_parser(), mw_raw(), mw_static(), mw_text(), mw_urlencoded()

Examples

app <- new_app()
app$use(mw_cgi("echo", "Status: 200\n\nHello"))
app

app2 <- new_app()
app2$get("/greet", mw_cgi("echo", "Status: 200\n\nHello"))
app2

# Using `mw_cgi()` in a handler, you can pass extra environment variables
app3 <- new_app()
cgi <- mw_cgi("echo", "Status: 200\n\nHello")
app2$get("/greet", function(req, res) {
  cgi(req, res, env = c("EXTRA_VAR" = "EXTRA_VALUE"))
})
app3

Description

Adds the cookies as the cookies element of the request object.

Usage

mw_cookie_parser()

Details

It ignores cookies in an invalid format. It ignores duplicate cookies: if two cookies have the same name, only the first one is included.

Value

Handler function.

See Also

Other middleware: mw_cgi(), mw_etag(), mw_json(), mw_log(), mw_multipart(), mw_range_parser(), mw_raw(), mw_static(), mw_text(), mw_urlencoded()


Middleware that add an ETag header to the response

Description

If the response already has an ETag header, then it is kept.

Usage

mw_etag(algorithm = "crc32")

Arguments

algorithm

Checksum algorithm to use. Only "crc32" is implemented currently.

Details

This middleware handles the If-None-Match headers, and it sets the status code of the response to 304 if If-None-Match matches the ETag. It also removes the response body in this case.

Value

Handler function.

See Also

Other middleware: mw_cgi(), mw_cookie_parser(), mw_json(), mw_log(), mw_multipart(), mw_range_parser(), mw_raw(), mw_static(), mw_text(), mw_urlencoded()

Examples

app <- new_app()
app$use(mw_etag())
app

Middleware to parse a JSON body

Description

Adds the parsed object as the json element of the request object.

Usage

mw_json(type = "application/json", simplifyVector = FALSE, ...)

Arguments

type

Content type to match before parsing. If it does not match, then the request object is not modified.

simplifyVector

Whether to simplify lists to vectors, passed to jsonlite::fromJSON().

...

Arguments to pass to jsonlite::fromJSON(), that performs the JSON parsing.

Value

Handler function.

See Also

Other middleware: mw_cgi(), mw_cookie_parser(), mw_etag(), mw_log(), mw_multipart(), mw_range_parser(), mw_raw(), mw_static(), mw_text(), mw_urlencoded()

Examples

app <- new_app()
app$use(mw_json())
app

Log requests to the standard output or other connection

Description

A one line log entry for every request. The output looks like this:

GET http://127.0.0.1:3000/image 200 3 ms - 4742

and contains

Usage

mw_log(format = "dev", stream = "stdout")

Arguments

format

Log format. Not implemented currently.

stream

R connection to log to. "stdout" means the standard output, "stderr" is the standard error. You can also supply a connection object, but then you need to be sure that it will be valid when the app is actually running.

Value

Handler function.

See Also

Other middleware: mw_cgi(), mw_cookie_parser(), mw_etag(), mw_json(), mw_multipart(), mw_range_parser(), mw_raw(), mw_static(), mw_text(), mw_urlencoded()

Examples

app <- new_app()
app$use(mw_log())
app

Parse a multipart HTTP request body

Description

Adds the parsed form fields in the form element of the request and the parsed files to the files element.

Usage

mw_multipart(type = "multipart/form-data")

Arguments

type

Content type to match before parsing. If it does not match, then the request object is not modified.

Value

Handler function.

See Also

Other middleware: mw_cgi(), mw_cookie_parser(), mw_etag(), mw_json(), mw_log(), mw_range_parser(), mw_raw(), mw_static(), mw_text(), mw_urlencoded()

Examples

app <- new_app()
app$use(mw_multipart())
app

Middleware to parse a Range header

Description

Adds the requested ranges to the ranges element of the request object. request$ranges is a data frame with two columns, from and to. Each row corresponds one requested interval.

Usage

mw_range_parser()

Details

When the last n bytes of the file are requested, the matrix row is set to c(0, -n). When all bytes after a p position are requested, the matrix row is set to c(p, Inf).

If the intervals overlap, then ranges is not set, i.e. the Range header is ignored.

If its syntax is invalid or the unit is not bytes, then the Range header is ignored.

Value

Handler function.

See Also

Other middleware: mw_cgi(), mw_cookie_parser(), mw_etag(), mw_json(), mw_log(), mw_multipart(), mw_raw(), mw_static(), mw_text(), mw_urlencoded()


Middleware to read the raw body of a request

Description

Adds the raw body, as a raw object to the raw field of the request.

Usage

mw_raw(type = "application/octet-stream")

Arguments

type

Content type to match. If it does not match, then the request object is not modified.

Value

Handler function.

See Also

Other middleware: mw_cgi(), mw_cookie_parser(), mw_etag(), mw_json(), mw_log(), mw_multipart(), mw_range_parser(), mw_static(), mw_text(), mw_urlencoded()

Examples

app <- new_app()
app$use(mw_raw())
app

Middleware function to serve static files

Description

The content type of the response is set automatically from the extension of the file. Note that this is a terminal middleware handler function. If a file is served, then the rest of the handler functions will not be called. If a file was not found, however, the rest of the handlers are still called.

Usage

mw_static(root, set_headers = NULL)

Arguments

root

Root path of the served files. Everything under this directory is served automatically. Directory lists are not currently supports.

set_headers

Callback function to call before a file is served.

Value

Handler function.

See Also

Other middleware: mw_cgi(), mw_cookie_parser(), mw_etag(), mw_json(), mw_log(), mw_multipart(), mw_range_parser(), mw_raw(), mw_text(), mw_urlencoded()

Examples

root <- system.file(package = "webfakes", "examples", "static", "public")
app <- new_app()
app$use(mw_static(root = root))
app

Middleware to parse a plain text body

Description

Adds the parsed object as the text element of the request object.

Usage

mw_text(default_charset = "utf-8", type = "text/plain")

Arguments

default_charset

Encoding to set on the text.

type

Content type to match before parsing. If it does not match, then the request object is not modified.

Value

Handler function.

See Also

Other middleware: mw_cgi(), mw_cookie_parser(), mw_etag(), mw_json(), mw_log(), mw_multipart(), mw_range_parser(), mw_raw(), mw_static(), mw_urlencoded()

Examples

app <- new_app()
app$use(mw_text())
app

Middleware to parse an url-encoded request body

Description

This is typically data from a form. The parsed data is added as the form element of the request object.

Usage

mw_urlencoded(type = "application/x-www-form-urlencoded")

Arguments

type

Content type to match before parsing. If it does not match, then the request object is not modified.

Value

Handler function.

See Also

Other middleware: mw_cgi(), mw_cookie_parser(), mw_etag(), mw_json(), mw_log(), mw_multipart(), mw_range_parser(), mw_raw(), mw_static(), mw_text()

Examples

app <- new_app()
app$use(mw_urlencoded())
app

Create a new web application

Description

Create a new web application

Usage

new_app()

Details

The typical workflow of creating a web application is:

  1. Create a webfakes_app object with new_app().

  2. Add middleware and/or routes to it.

  3. Start is with the webfakes_app$listen() method, or start it in another process with new_app_process().

  4. Make queries to the web app.

  5. Stop it via CTRL+C / ESC, or, if it is running in another process, with the ⁠$stop()⁠ method of new_app_process().

A web application can be

The webfakes API is very much influenced by the express.js project.

Create web app objects

new_app()

new_app() returns a webfakes_app object the has the methods listed on this page.

An app is an environment with S3 class webfakes_app.

The handler stack

An app has a stack of handlers. Each handler can be a route or middleware. The differences between the two are:

Routes

The following methods define routes. Each method corresponds to the HTTP verb with the same name, except for app$all(), which creates a route for all HTTP methods.

app$all(path, ...)
app$delete(path, ...)
app$get(path, ...)
app$head(path, ...)
app$patch(path, ...)
app$post(path, ...)
app$put(path, ...)
... (see list below)

webfakes also has methods for the less frequently used HTTP verbs: CONNECT, MKCOL, OPTIONS, PROPFIND, REPORT. (The method names are always in lowercase.)

If a request is not handled by any routes (or handler functions in general), then webfakes will send a simple HTTP 404 response.

Middleware

app$use() adds a middleware to the handler stack. A middleware is a handler function, see 'Handler functions' below. webfakes comes with middleware to perform common tasks:

app$use(..., .first = FALSE)

Handler functions

A handler function is a route or middleware. A handler function is called by webfakes with the incoming HTTP request and the outgoing HTTP response objects (being built) as arguments. The handler function may query and modify the members of the request and/or the response object. If it returns the string "next", then it is not a terminal handler, and once it returns, webfakes will move on to call the next handler in the stack.

A typical route:

app$get("/user/:id", function(req, res) {
  id <- req$params$id
  ...
  res$
    set_status(200L)$
    set_header("X-Custom-Header", "foobar")$
    send_json(response, auto_unbox = TRUE)
})

A typical middleware:

app$use(function(req, res) {
  ...
  "next"
})

Errors

If a handler function throws an error, then the web server will return a HTTP 500 text/plain response, with the error message as the response body.

Request and response objects

See webfakes_request and webfakes_response for the methods of the request and response objects.

Path specification

Routes are associated with one or more API paths. A path specification can be

Path parameters

Paths that are specified as parameterized strings or regular expressions can have parameters.

For parameterized strings the keys may contain letters, numbers and underscores. When webfakes matches an API path to a handler with a parameterized string path, the parameters will be added to the request, as params. I.e. in the handler function (and subsequent handler functions, if the current one is not terminal), they are available in the req$params list.

For regular expressions, capture groups are also added as parameters. It is best to use named capture groups, so that the parameters are in a named list.

If the path of the handler is a list of parameterized strings or regular expressions, the parameters are set according to the first matching one.

Templates

webfakes supports templates, using any template engine. It comes with a template engine that uses the glue package, see tmpl_glue().

app$engine() registers a template engine, for a certain file extension. The ⁠$render()⁠ method of webfakes_response can be called from the handler function to evaluate a template from a file.

app$engine(ext, engine)

An example template engine that uses glue might look like this:

app$engine("txt", function(path, locals) {
  txt <- readChar(path, nchars = file.size(path))
  glue::glue_data(locals, txt)
})

(The built-in tmpl_glue() engine has more features.)

This template engine can be used in a handler:

app$get("/view", function(req, res) {
 txt <- res$render("test")
 res$
   set_type("text/plain")$
   send(txt)
})

The location of the templates can be set using the views configuration parameter, see the ⁠$set_config()⁠ method below.

In the template, the variables passed in as locals, and also the response local variables (see locals in webfakes_response), are available.

Starting and stopping

app$listen(port = NULL, opts = server_opts(), cleanup = TRUE)

This method does not return, and can be interrupted with CTRL+C / ESC or a SIGINT signal. See new_app_process() for interrupting an app that is running in another process.

When port is NULL, the operating system chooses a port where the app will listen. To be able to get the port number programmatically, before the listen method blocks, it advertises the selected port in a webfakes_port condition, so one can catch it:

webfakes by default binds only to the loopback interface at 127.0.0.1, so the webfakes web app is never reachable from the network.

withCallingHandlers(
  app$listen(),
  "webfakes_port" = function(msg) print(msg$port)
)

Logging

webfakes can write an access log that contains an entry for all incoming requests, and also an error log for the errors that happen while the server is running. This is the default behavior for local app (the ones started by app$listen() and for remote apps (the ones started via new_app_process():

See server_opts() for changing the default logging behavior.

Shared app data

app$locals

It is often useful to share data between handlers and requests in an app. app$locals is an environment that supports this. E.g. a middleware that counts the number of requests can be implemented as:

app$use(function(req, res) {
  locals <- req$app$locals
  if (is.null(locals$num)) locals$num <- 0L
  locals$num <- locals$num + 1L
  "next"
})

webfakes_response objects also have a locals environment, that is initially populated as a copy of app$locals.

Configuration

app$get_config(key)
app$set_config(key, value)

Currently used configuration values:

Value

A new webfakes_app.

See Also

webfakes_request for request objects, webfakes_response for response objects.

Examples

# see example web apps in the `/examples` directory in
system.file(package = "webfakes", "examples")

app <- new_app()
app$use(mw_log())

app$get("/hello", function(req, res) {
  res$send("Hello there!")
})

app$get(new_regexp("^/hi(/.*)?$"), function(req, res) {
  res$send("Hi indeed!")
})

app$post("/hello", function(req, res) {
  res$send("Got it, thanks!")
})

app

# Start the app with: app$listen()
# Or start it in another R session: new_app_process(app)

Run a webfakes app in another process

Description

Runs an app in a subprocess, using callr::r_session.

Usage

new_app_process(
  app,
  port = NULL,
  opts = server_opts(remote = TRUE),
  start = FALSE,
  auto_start = TRUE,
  process_timeout = NULL,
  callr_opts = NULL
)

Arguments

app

webfakes_app object, the web app to run.

port

Port to use. By default the OS assigns a port.

opts

Server options. See server_opts() for the defaults.

start

Whether to start the web server immediately. If this is FALSE, and auto_start is TRUE, then it is started as neeed.

auto_start

Whether to start the web server process automatically. If TRUE and the process is not running, then ⁠$start()⁠, ⁠$get_port()⁠ and ⁠$url()⁠ start the process.

process_timeout

How long to wait for the subprocess to start, in milliseconds.

callr_opts

Options to pass to callr::r_session_options() when setting up the subprocess.

Value

A webfakes_app_process object.

Methods

The webfakes_app_process class has the following methods:

get_app()
get_port()
stop()
get_state()
local_env(envvars)
url(path = "/", query = NULL)

get_app() returns the app object.

get_port() returns the port the web server is running on.

stop() stops the web server, and also the subprocess. If the error log file is not empty, then it dumps its contents to the screen.

get_state() returns a string, the state of the web server:

local_env() sets the given environment variables for the duration of the app process. It resets them in ⁠$stop()⁠. Webfakes replaces {url} in the value of the environment variables with the app URL, so you can set environment variables that point to the app.

url() returns the URL of the web app. You can use the path parameter to return a specific path.

See Also

local_app_process() for automatically cleaning up the subprocess.

Examples

app <- new_app()
app$get("/foo", function(req, res) {
  res$send("Hello world!")
})

proc <- new_app_process(app)
url <- proc$url("/foo")
resp <- curl::curl_fetch_memory(url)
cat(rawToChar(resp$content))

proc$stop()

Create a new regular expression to use in webfakes routes

Description

Note that webfakes uses PERL regular expressions.

Usage

new_regexp(x)

Arguments

x

String scalar containing a regular expression.

Details

As R does not have data type or class for regular expressions, you can use new_regexp() to mark a string as a regular expression, when adding routes.

Value

String with class webfakes_regexp.

See Also

The 'Path specification' and 'Path parameters' chapters of the manual of new_app().

Examples

new_regexp("^/api/match/(?<pattern>.*)$")

Helper function to use httr's OAuth2.0 functions non-interactively, e.g. in test cases

Description

To perform an automatic acknowledgement and log in for a local OAuth2.0 app, run by httr, wrap the expression that obtains the OAuth2.0 token in oauth2_httr_login().

Usage

oauth2_httr_login(expr)

Arguments

expr

Expression that calls httr::oauth2.0_token(), either directly, or indirectly.

Details

In interactive sessions, oauth2_httr_login() overrides the browser option, and when httr opens a browser page, it calls oauth2_login() in a subprocess.

In non-interactive sessions, httr does not open a browser page, only messages the user to do it manually. oauth2_httr_login() listens for these messages, and calls oauth2_login() in a subprocess.

Value

The return value of expr.

See Also

See ?vignette("oauth", package = "webfakes") for a case study that uses this function.

Other OAuth2.0 functions: oauth2_login(), oauth2_resource_app(), oauth2_third_party_app()


Helper function to log in to a third party OAuth2.0 app without a browser

Description

It works with oauth2_resource_app(), and any third party app, including the fake oauth2_third_party_app().

Usage

oauth2_login(login_url)

Arguments

login_url

The login URL of the third party app.

Details

See test-oauth.R in webfakes for an example.

Value

A named list with

See Also

Other OAuth2.0 functions: oauth2_httr_login(), oauth2_resource_app(), oauth2_third_party_app()


Fake OAuth 2.0 resource and authorization app

Description

The webfakes package comes with two fake apps that allow to imitate the OAuth2.0 flow in your test cases. (See Aaron Parecki’s tutorial for a good introduction to OAuth2.0.) One app (oauth2_resource_app()) is the API server that serves both as the resource and provides authorization. oauth2_third_party_app() plays the role of the third-party app. They are useful when testing or demonstrating code handling OAuth2.0 authorization, token caching, etc. in a package. The apps can be used in your tests directly, or you could adapt one or both of them to better mimic a particular OAuth2.0 flow.

Usage

oauth2_resource_app(
  access_duration = 3600L,
  refresh_duration = 7200L,
  refresh = TRUE,
  seed = NULL,
  authorize_endpoint = "/authorize",
  token_endpoint = "/token"
)

Arguments

access_duration

After how many seconds should access tokens expire.

refresh_duration

After how many seconds should refresh tokens expire (ignored if refresh is FALSE).

refresh

Should a refresh token be returned (logical).

seed

Random seed used when creating tokens. If NULL, we rely on R to provide a seed. The app uses its own RNG stream, so it does not affect reproducibility of the tests.

authorize_endpoint

The authorization endpoint of the resource server. Change this from the default if the real app that you are faking does not use ⁠/authorize⁠.

token_endpoint

The endpoint to request tokens. Change this if the real app that you are faking does not use ⁠/token⁠.

Details

The app has the following endpoints:

Notes

For more details see vignette("oauth", package = "webfakes").

Value

a webfakes app

webfakes app

oauth2_resource_app()

App representing the API server (resource/authorization)

See Also

Other OAuth2.0 functions: oauth2_httr_login(), oauth2_login(), oauth2_third_party_app()


App representing the third-party app

Description

The webfakes package comes with two fake apps that allow to imitate the OAuth2.0 flow in your test cases. (See Aaron Parecki’s tutorial for a good introduction to OAuth2.0.) One app (oauth2_resource_app()) is the API server that serves both as the resource and provides authorization. oauth2_third_party_app() plays the role of the third-party app. They are useful when testing or demonstrating code handling OAuth2.0 authorization, token caching, etc. in a package. The apps can be used in your tests directly, or you could adapt one or both of them to better mimic a particular OAuth2.0 flow.

Usage

oauth2_third_party_app(name = "Third-Party app")

Arguments

name

Name of the third-party app

Details

Endpoints:

For more details see vignette("oauth", package = "webfakes").

Value

webfakes app

See Also

Other OAuth2.0 functions: oauth2_httr_login(), oauth2_login(), oauth2_resource_app()


Webfakes web server options

Description

Webfakes web server options

Usage

server_opts(
  remote = FALSE,
  port = NULL,
  num_threads = 1,
  interfaces = "127.0.0.1",
  enable_keep_alive = FALSE,
  access_log_file = remote,
  error_log_file = TRUE,
  tcp_nodelay = FALSE,
  throttle = Inf
)

Arguments

remote

Meta-option. If set to TRUE, webfakes uses slightly different defaults, that are more appropriate for a background server process.

port

Port to start the web server on. Defaults to a randomly chosen port.

num_threads

Number of request handler threads to use. Typically you don't need more than one thread, unless you run test cases in parallel or you make concurrent HTTP requests.

interfaces

The network interfaces to listen on. Being a test web server, it defaults to the localhost. Only bind to a public interface if you know what you are doing. webfakes was not designed to serve public web pages.

enable_keep_alive

Whether the server keeps connections alive.

access_log_file

TRUE, FALSE, or a path. See 'Logging' below.

error_log_file

TRUE, FALSE, or a path. See 'Logging' below.

tcp_nodelay

if TRUE then packages will be sent as soon as possible, instead of waiting for a full buffer or timeout to occur.

throttle

Limit download speed for clients. If not Inf, then it is the maximum number of bytes per second, that is sent to as connection.

Value

List of options that can be passed to webfakes_app$listen() (see new_app()), and new_app_process().

Logging

⁠<log-dir>⁠ is set to the contents of the WEBFAKES_LOG_DIR environment variable, if it is set. Otherwise it is set to ⁠<tmpdir>/webfakes⁠ for local apps and ⁠<tmpdir>/<pid>/webfakes⁠ for remote apps (started with new_app_procss()).

⁠<tmpdir>⁠ is the session temporary directory of the main process.

⁠<pid>⁠ is the process id of the subprocess.

Examples

# See the defaults
server_opts()

glue based template engine

Description

Use this template engine to create pages with glue templates. See glue::glue() for the syntax.

Usage

tmpl_glue(
  sep = "",
  open = "{",
  close = "}",
  na = "NA",
  transformer = NULL,
  trim = TRUE
)

Arguments

sep

Separator used to separate elements.

open

The opening delimiter. Doubling the full delimiter escapes it.

close

The closing delimiter. Doubling the full delimiter escapes it.

na

Value to replace NA values with. If NULL missing values are propagated, that is an NA result will cause NA output. Otherwise the value is replaced by the value of na.

transformer

A function taking three parameters code, envir and data used to transform the output of each block before during or after evaluation.

trim

Whether to trim the input template with glue::trim() or not.

Value

Template function.

Examples

# See th 'hello' app at
hello_root <- system.file(package = "webfakes", "examples", "hello")
hello_root

app <- new_app()
app$engine("txt", tmpl_glue())
app$use(mw_log())


app$get("/view", function(req, res) {
  txt <- res$render("test")
  res$
    set_type("text/plain")$
    send(txt)
})

# Switch to the app's root: setwd(hello_root)
# Now start the app with: app$listen(3000L)
# Or start it in another process: new_process(app)

A webfakes request object

Description

webfakes creates a webfakes_request object for every incoming HTTP request. This object is passed to every matched route and middleware, until the response is sent. It has reference semantics, so handlers can modify it.

Details

Fields and methods:

Body parsing middleware adds additional fields to the request object. See mw_raw(), mw_text(), mw_json(), mw_multipart() and mw_urlencoded().

See Also

webfakes_response for the webfakes response object.

Examples

# This is how you can see the request and response objects:
app <- new_app()
app$get("/", function(req, res) {
  browser()
  res$send("done")
})
app

# Now start this app on a port:
# app$listen(3000)
# and connect to it from a web browser: http://127.0.0.1:3000
# You can also use another R session to connect:
# httr::GET("http://127.0.0.1:3000")
# or the command line curl tool:
# curl -v http://127.0.0.1:3000
# The app will stop while processing the request.

A webfakes response object

Description

webfakes creates a webfakes_response object for every incoming HTTP request. This object is passed to every matched route and middleware, until the HTTP response is sent. It has reference semantics, so handlers can modify it.

Details

Fields and methods:

Usually you need one of the send() methods, to send out the HTTP response in one go, first the headers, then the body.

Alternatively, you can use ⁠$write()⁠ to send the response in parts.

See Also

webfakes_request for the webfakes request object.

Examples

# This is how you can see the request and response objects:
app <- new_app()
app$get("/", function(req, res) {
  browser()
  res$send("done")
})
app

# Now start this app on a port:
# app$listen(3000)
# and connect to it from a web browser: http://127.0.0.1:3000
# You can also use another R session to connect:
# httr::GET("http://127.0.0.1:3000")
# or the command line curl tool:
# curl -v http://127.0.0.1:3000
# The app will stop while processing the request.