| Title: | Accept POST Data and URL Parameters in 'shiny' (Same-Port Integration) |
|---|---|
| Description: | Handle POST requests on a custom path (e.g., /ingress) inside the same 'shiny' HTTP server using user interface functions and HTTP responses. Expose latest payload as a reactive and provide helpers for query parameters. |
| Authors: | Pawan Rama Mali [aut, cre] |
| Maintainer: | Pawan Rama Mali <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.3.0 |
| Built: | 2026-05-26 06:59:16 UTC |
| Source: | https://github.com/pawanramamali/shinypayload |
Get URL query parameters in Shiny
params_get(session, keys = NULL)params_get(session, keys = NULL)
session |
Shiny session |
keys |
Optional character vector of keys to pull; if NULL return all |
A named list containing the URL query parameters. If keys is
specified, only those parameters are returned. If no parameters exist or
the specified keys are not found, returns an empty list or list with
NULL values respectively.
if (interactive()) { server <- function(input, output, session) { # Get all query parameters all_params <- params_get(session) # Get specific parameters user_params <- params_get(session, keys = c("user_id", "token")) # Use in outputs output$params_display <- renderText({ params <- params_get(session) if (length(params) > 0) { paste("Parameters:", jsonlite::toJSON(params)) } else { "No parameters provided" } }) } }if (interactive()) { server <- function(input, output, session) { # Get all query parameters all_params <- params_get(session) # Get specific parameters user_params <- params_get(session, keys = c("user_id", "token")) # Use in outputs output$params_display <- renderText({ params <- params_get(session) if (length(params) > 0) { paste("Parameters:", jsonlite::toJSON(params)) } else { "No parameters provided" } }) } }
Create a batch reactive that collects payloads and processes them in groups
payload_batch( path = "/ingress", session, batch_size = 10, batch_timeout_ms = 5000, process_func = NULL, intervalMillis = 500 )payload_batch( path = "/ingress", session, batch_size = 10, batch_timeout_ms = 5000, process_func = NULL, intervalMillis = 500 )
path |
The URL path used in payload_ui() or payload_methods() (default "/ingress") |
session |
The Shiny session object |
batch_size |
Number of payloads to collect before processing (default 10) |
batch_timeout_ms |
Maximum time to wait for batch completion in ms (default 5000) |
process_func |
Function to process the batch of payloads |
intervalMillis |
Polling interval in milliseconds (default 500) |
A reactive expression that returns processed batch results
if (interactive()) { server <- function(input, output, session) { # Process sensor data in batches of 5 sensor_batch <- payload_batch("/api/sensors", session, batch_size = 5, process_func = function(payloads) { temperatures <- sapply(payloads, function(p) p$payload$temperature) list( count = length(temperatures), avg_temp = mean(temperatures, na.rm = TRUE), max_temp = max(temperatures, na.rm = TRUE), timestamp = Sys.time() ) } ) } }if (interactive()) { server <- function(input, output, session) { # Process sensor data in batches of 5 sensor_batch <- payload_batch("/api/sensors", session, batch_size = 5, process_func = function(payloads) { temperatures <- sapply(payloads, function(p) p$payload$temperature) list( count = length(temperatures), avg_temp = mean(temperatures, na.rm = TRUE), max_temp = max(temperatures, na.rm = TRUE), timestamp = Sys.time() ) } ) } }
Create a conditional reactive that updates only when conditions are met
payload_conditional( path = "/ingress", session, condition_func, intervalMillis = 300 )payload_conditional( path = "/ingress", session, condition_func, intervalMillis = 300 )
path |
The URL path used in payload_ui() or payload_methods() (default "/ingress") |
session |
The Shiny session object |
condition_func |
Function that returns TRUE when reactive should update |
intervalMillis |
Polling interval in milliseconds (default 300) |
A reactive expression that updates only when condition is met
if (interactive()) { server <- function(input, output, session) { # Only update when temperature exceeds threshold high_temp_alert <- payload_conditional("/api/sensors", session, condition_func = function(payload) { !is.null(payload$payload$temperature) && payload$payload$temperature > 30 } ) # Only update during business hours business_hours_data <- payload_conditional("/api/data", session, condition_func = function(payload) { hour <- as.numeric(format(Sys.time(), "%H")) hour >= 9 && hour <= 17 } ) } }if (interactive()) { server <- function(input, output, session) { # Only update when temperature exceeds threshold high_temp_alert <- payload_conditional("/api/sensors", session, condition_func = function(payload) { !is.null(payload$payload$temperature) && payload$payload$temperature > 30 } ) # Only update during business hours business_hours_data <- payload_conditional("/api/data", session, condition_func = function(payload) { hour <- as.numeric(format(Sys.time(), "%H")) hour >= 9 && hour <= 17 } ) } }
Configure Cross-Origin Resource Sharing (CORS)
payload_cors_config( enabled = FALSE, origins = "*", methods = c("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"), headers = c("Content-Type", "Authorization", "X-Requested-With", "X-Request-ID"), credentials = FALSE, max_age = 86400 )payload_cors_config( enabled = FALSE, origins = "*", methods = c("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"), headers = c("Content-Type", "Authorization", "X-Requested-With", "X-Request-ID"), credentials = FALSE, max_age = 86400 )
enabled |
Enable or disable CORS (default FALSE) |
origins |
Allowed origins. Use "*" for any origin, or provide a character vector of specific domains (default "*") |
methods |
HTTP methods to allow (default includes common methods) |
headers |
Headers to allow in requests (default includes common headers) |
credentials |
Allow credentials in cross-origin requests (default FALSE) |
max_age |
Maximum time (in seconds) browsers should cache preflight results (default 86400 = 24 hours) |
Invisibly returns TRUE, called for side effects
if (interactive()) { # Enable CORS for all origins payload_cors_config(enabled = TRUE) # Restrict to specific origins payload_cors_config( enabled = TRUE, origins = c("https://myapp.com", "https://staging.myapp.com"), credentials = TRUE ) # Disable CORS payload_cors_config(enabled = FALSE) }if (interactive()) { # Enable CORS for all origins payload_cors_config(enabled = TRUE) # Restrict to specific origins payload_cors_config( enabled = TRUE, origins = c("https://myapp.com", "https://staging.myapp.com"), credentials = TRUE ) # Disable CORS payload_cors_config(enabled = FALSE) }
Get current CORS configuration
payload_cors_status()payload_cors_status()
A list containing current CORS settings
if (interactive()) { status <- payload_cors_status() cat("CORS enabled:", status$enabled, "\n") cat("Allowed origins:", paste(status$origins, collapse = ", "), "\n") }if (interactive()) { status <- payload_cors_status() cat("CORS enabled:", status$enabled, "\n") cat("Allowed origins:", paste(status$origins, collapse = ", "), "\n") }
Clear data processing configuration
payload_data_clear(clear_hooks = TRUE, clear_limits = TRUE)payload_data_clear(clear_hooks = TRUE, clear_limits = TRUE)
clear_hooks |
Whether to clear transformation hooks (default TRUE) |
clear_limits |
Whether to clear payload size limits (default TRUE) |
No return value, updates global configuration
if (interactive()) { # Clear all data processing configuration payload_data_clear() # Clear only transformation hooks payload_data_clear(clear_limits = FALSE) }if (interactive()) { # Clear all data processing configuration payload_data_clear() # Clear only transformation hooks payload_data_clear(clear_limits = FALSE) }
Configure data processing and transformation settings
payload_data_config(transformation_hooks = NULL, max_payload_size = NULL)payload_data_config(transformation_hooks = NULL, max_payload_size = NULL)
transformation_hooks |
List of functions to apply to parsed data. Each function should accept (data, content_type, req) and return transformed data |
max_payload_size |
Maximum payload size in bytes (optional, for validation) |
No return value, updates global configuration
if (interactive()) { # Add a transformation hook to convert timestamps timestamp_hook <- function(data, content_type, req) { if (is.list(data) && !is.null(data$timestamp)) { data$timestamp <- as.POSIXct(data$timestamp, origin = "1970-01-01") } return(data) } # Add a validation hook validation_hook <- function(data, content_type, req) { if (is.list(data) && is.null(data$user_id)) { stop("user_id is required") } return(data) } payload_data_config( transformation_hooks = list(timestamp_hook, validation_hook), max_payload_size = 1024 * 1024 # 1MB limit ) }if (interactive()) { # Add a transformation hook to convert timestamps timestamp_hook <- function(data, content_type, req) { if (is.list(data) && !is.null(data$timestamp)) { data$timestamp <- as.POSIXct(data$timestamp, origin = "1970-01-01") } return(data) } # Add a validation hook validation_hook <- function(data, content_type, req) { if (is.list(data) && is.null(data$user_id)) { stop("user_id is required") } return(data) } payload_data_config( transformation_hooks = list(timestamp_hook, validation_hook), max_payload_size = 1024 * 1024 # 1MB limit ) }
Get current data processing configuration
payload_data_status()payload_data_status()
A list containing current data processing settings
if (interactive()) { config <- payload_data_status() cat("Transformation hooks:", length(config$transformation_hooks %||% list()), "\n") cat("Max payload size:", config$max_payload_size %||% "unlimited", "\n") }if (interactive()) { config <- payload_data_status() cat("Transformation hooks:", length(config$transformation_hooks %||% list()), "\n") cat("Max payload size:", config$max_payload_size %||% "unlimited", "\n") }
Configure development and debugging settings
payload_debug_config( debug_mode = FALSE, log_level = "INFO", max_log_entries = 1000 )payload_debug_config( debug_mode = FALSE, log_level = "INFO", max_log_entries = 1000 )
debug_mode |
Enable debug mode with verbose logging (default FALSE) |
log_level |
Logging level: "DEBUG", "INFO", "WARN", "ERROR" (default "INFO") |
max_log_entries |
Maximum number of log entries to keep (default 1000) |
No return value, updates global configuration
if (interactive()) { # Enable debug mode for development payload_debug_config(debug_mode = TRUE, log_level = "DEBUG") # Production settings payload_debug_config(debug_mode = FALSE, log_level = "WARN") }if (interactive()) { # Enable debug mode for development payload_debug_config(debug_mode = TRUE, log_level = "DEBUG") # Production settings payload_debug_config(debug_mode = FALSE, log_level = "WARN") }
Get development and debugging status
payload_debug_status()payload_debug_status()
A list containing current debug settings
if (interactive()) { status <- payload_debug_status() cat("Debug mode:", status$debug_mode, "\n") cat("Log level:", status$log_level, "\n") }if (interactive()) { status <- payload_debug_status() cat("Debug mode:", status$debug_mode, "\n") cat("Log level:", status$log_level, "\n") }
Generate the absolute URL for the payload endpoint
payload_endpoint_url(session, path = "/ingress")payload_endpoint_url(session, path = "/ingress")
session |
The Shiny session object |
path |
The URL path (default "/ingress") |
A character string containing the complete URL (including protocol, hostname, port, and path) where POST requests should be sent to reach this endpoint.
if (interactive()) { server <- function(input, output, session) { url <- payload_endpoint_url(session, "/data") print(paste("Send POST requests to:", url)) } }if (interactive()) { server <- function(input, output, session) { url <- payload_endpoint_url(session, "/data") print(paste("Send POST requests to:", url)) } }
Configure health check endpoint
payload_health_config(enabled = TRUE, path = "/health")payload_health_config(enabled = TRUE, path = "/health")
enabled |
Enable or disable health check endpoint (default TRUE) |
path |
URL path for health check (default "/health") |
Invisibly returns TRUE, called for side effects
if (interactive()) { # Use custom health check path payload_health_config(enabled = TRUE, path = "/api/health") # Disable health checks payload_health_config(enabled = FALSE) }if (interactive()) { # Use custom health check path payload_health_config(enabled = TRUE, path = "/api/health") # Disable health checks payload_health_config(enabled = FALSE) }
Get current health check configuration
payload_health_status()payload_health_status()
A list containing current health check settings
if (interactive()) { status <- payload_health_status() cat("Health check enabled:", status$enabled, "\n") cat("Health check path:", status$path, "\n") }if (interactive()) { status <- payload_health_status() cat("Health check enabled:", status$enabled, "\n") cat("Health check path:", status$path, "\n") }
Get historical payloads for a specific endpoint
payload_history(path = "/ingress", limit = NULL, since = NULL)payload_history(path = "/ingress", limit = NULL, since = NULL)
path |
The URL path used in payload_ui() or payload_methods() (default "/ingress") |
limit |
Maximum number of historical entries to return (default NULL for all) |
since |
Only return payloads received after this timestamp (POSIXct or character) |
A list of historical payload entries, each containing:
id (unique identifier), timestamp, payload, and meta
if (interactive()) { # Get last 10 payloads recent_payloads <- payload_history("/api/data", limit = 10) # Get payloads from last hour since_time <- Sys.time() - 3600 recent_payloads <- payload_history("/api/data", since = since_time) # Process historical data for (entry in recent_payloads) { cat("ID:", entry$id, "Time:", entry$timestamp, "\n") print(entry$payload) } }if (interactive()) { # Get last 10 payloads recent_payloads <- payload_history("/api/data", limit = 10) # Get payloads from last hour since_time <- Sys.time() - 3600 recent_payloads <- payload_history("/api/data", since = since_time) # Process historical data for (entry in recent_payloads) { cat("ID:", entry$id, "Time:", entry$timestamp, "\n") print(entry$payload) } }
Clear payload history for specific endpoint or all endpoints
payload_history_clear(path = NULL)payload_history_clear(path = NULL)
path |
The URL path to clear history for, or NULL to clear all (default NULL) |
Number of entries that were cleared
if (interactive()) { # Clear history for specific endpoint cleared_count <- payload_history_clear("/api/data") # Clear all history total_cleared <- payload_history_clear() }if (interactive()) { # Clear history for specific endpoint cleared_count <- payload_history_clear("/api/data") # Clear all history total_cleared <- payload_history_clear() }
Configure payload history retention policies
payload_history_config(max_items = 100, max_age_hours = 24)payload_history_config(max_items = 100, max_age_hours = 24)
max_items |
Maximum number of payload entries to keep per endpoint (default 100) |
max_age_hours |
Maximum age in hours for payload entries (default 24) |
No return value, updates global configuration
if (interactive()) { # Keep more history items but for shorter time payload_history_config(max_items = 500, max_age_hours = 12) # Long-term storage with fewer items payload_history_config(max_items = 50, max_age_hours = 168) # 1 week }if (interactive()) { # Keep more history items but for shorter time payload_history_config(max_items = 500, max_age_hours = 12) # Long-term storage with fewer items payload_history_config(max_items = 50, max_age_hours = 168) # 1 week }
Get payload history statistics
payload_history_stats(path = NULL)payload_history_stats(path = NULL)
path |
The URL path to get statistics for, or NULL for all endpoints (default NULL) |
A list containing statistics: total_entries, oldest_timestamp, newest_timestamp, endpoints (if path is NULL), and size_estimate
if (interactive()) { # Get stats for specific endpoint stats <- payload_history_stats("/api/data") cat("Total entries:", stats$total_entries, "\n") # Get overall stats overall_stats <- payload_history_stats() cat("Total endpoints:", length(overall_stats$endpoints), "\n") }if (interactive()) { # Get stats for specific endpoint stats <- payload_history_stats("/api/data") cat("Total entries:", stats$total_entries, "\n") # Get overall stats overall_stats <- payload_history_stats() cat("Total endpoints:", length(overall_stats$endpoints), "\n") }
Get a reactive that polls for new payload data
payload_last(path = "/ingress", session, intervalMillis = 300, scope = c("global", "session"))payload_last(path = "/ingress", session, intervalMillis = 300, scope = c("global", "session"))
path |
The URL path used in payload_ui() (default "/ingress") |
session |
The Shiny session object |
intervalMillis |
Polling interval in milliseconds (default 300) |
scope |
Data scope: "global" (shared across sessions, default) or "session" (isolated per session) |
A reactive expression (class "reactive") that returns a list with two
elements when new data is available: payload (the parsed request body)
and meta (metadata including timestamp, remote address, headers, etc.),
or NULL if no data has been received yet.
if (interactive()) { server <- function(input, output, session) { # Global scope - data shared across all sessions global_data <- payload_last("/data", session) # Session scope - data isolated to this session only session_data <- payload_last("/user-data", session, scope = "session") observeEvent(global_data(), { data <- global_data() if (!is.null(data)) { print(data$payload) print(data$meta$timestamp) } }) } }if (interactive()) { server <- function(input, output, session) { # Global scope - data shared across all sessions global_data <- payload_last("/data", session) # Session scope - data isolated to this session only session_data <- payload_last("/user-data", session, scope = "session") observeEvent(global_data(), { data <- global_data() if (!is.null(data)) { print(data$payload) print(data$meta$timestamp) } }) } }
Get recent log entries
payload_logs(level = NULL, limit = 50, since = NULL)payload_logs(level = NULL, limit = 50, since = NULL)
level |
Filter by log level (optional) |
limit |
Maximum number of entries to return (default 50) |
since |
Only return logs after this timestamp (optional) |
A list of log entries
if (interactive()) { # Get last 20 log entries recent_logs <- payload_logs(limit = 20) # Get only error logs error_logs <- payload_logs(level = "ERROR") # Get logs from last hour recent_logs <- payload_logs(since = Sys.time() - 3600) }if (interactive()) { # Get last 20 log entries recent_logs <- payload_logs(limit = 20) # Get only error logs error_logs <- payload_logs(level = "ERROR") # Get logs from last hour recent_logs <- payload_logs(since = Sys.time() - 3600) }
Clear log entries
payload_logs_clear(level = NULL)payload_logs_clear(level = NULL)
level |
Clear only logs of this level (optional, clears all if NULL) |
Number of log entries that were cleared
if (interactive()) { # Clear all logs cleared_count <- payload_logs_clear() # Clear only debug logs debug_cleared <- payload_logs_clear(level = "DEBUG") }if (interactive()) { # Clear all logs cleared_count <- payload_logs_clear() # Clear only debug logs debug_cleared <- payload_logs_clear(level = "DEBUG") }
Enhanced HTTP methods support for multiple endpoints
payload_methods(base_ui, endpoints)payload_methods(base_ui, endpoints)
base_ui |
The original UI (tagList, fluidPage, or a function(req) returning UI) |
endpoints |
A list of endpoint configurations. Each element should be a list with:
|
A function that takes a request object and returns either the regular UI (for GET requests) or an HTTP response (for other HTTP methods). This function should be passed to shinyApp() as the ui parameter.
if (interactive()) { endpoints <- list( list(path = "/api/data", methods = c("POST", "PUT"), token = "secret"), list(path = "/api/delete", methods = "DELETE", token = "admin-token"), list(path = "/webhooks", methods = c("POST", "PATCH")) ) ui <- payload_methods(fluidPage(h1("My App")), endpoints) shinyApp(ui, server, uiPattern = ".*") }if (interactive()) { endpoints <- list( list(path = "/api/data", methods = c("POST", "PUT"), token = "secret"), list(path = "/api/delete", methods = "DELETE", token = "admin-token"), list(path = "/webhooks", methods = c("POST", "PATCH")) ) ui <- payload_methods(fluidPage(h1("My App")), endpoints) shinyApp(ui, server, uiPattern = ".*") }
Enqueue a payload for async processing
payload_queue(path, payload, priority = c("normal", "high", "low"), correlation_id = NULL)payload_queue(path, payload, priority = c("normal", "high", "low"), correlation_id = NULL)
path |
The endpoint path this payload is associated with |
payload |
The payload data to queue |
priority |
Queue priority: "high", "normal", or "low" (default "normal") |
correlation_id |
Optional correlation ID for tracking |
A list with success status and queue_id if successful
if (interactive()) { # Enqueue a payload result <- payload_queue("/api/process", list(data = "test")) if (result$success) { cat("Queued with ID:", result$queue_id, "\n") } }if (interactive()) { # Enqueue a payload result <- payload_queue("/api/process", list(data = "test")) if (result$success) { cat("Queued with ID:", result$queue_id, "\n") } }
Clear queue items
payload_queue_clear(include_dead_letter = FALSE)payload_queue_clear(include_dead_letter = FALSE)
include_dead_letter |
Also clear dead letter queue (default FALSE) |
Number of items cleared
if (interactive()) { # Clear pending queue items cleared <- payload_queue_clear() # Clear everything including dead letter cleared <- payload_queue_clear(include_dead_letter = TRUE) }if (interactive()) { # Clear pending queue items cleared <- payload_queue_clear() # Clear everything including dead letter cleared <- payload_queue_clear(include_dead_letter = TRUE) }
Configure async queue processing
payload_queue_config( enabled = FALSE, max_size = 1000, retry_attempts = 3, retry_delay_ms = 1000 )payload_queue_config( enabled = FALSE, max_size = 1000, retry_attempts = 3, retry_delay_ms = 1000 )
enabled |
Enable or disable queue processing (default FALSE) |
max_size |
Maximum queue size (default 1000) |
retry_attempts |
Number of retry attempts for failed processing (default 3) |
retry_delay_ms |
Delay between retries in milliseconds (default 1000) |
Invisibly returns TRUE, called for side effects
if (interactive()) { # Enable queue with custom settings payload_queue_config( enabled = TRUE, max_size = 500, retry_attempts = 5 ) }if (interactive()) { # Enable queue with custom settings payload_queue_config( enabled = TRUE, max_size = 500, retry_attempts = 5 ) }
Get dead letter queue items
payload_queue_dead_letter(limit = 50)payload_queue_dead_letter(limit = 50)
limit |
Maximum number of items to return (default 50) |
A list of failed queue items
if (interactive()) { dead_items <- payload_queue_dead_letter() for (item in dead_items) { cat("Failed item:", item$id, "Error:", item$error, "\n") } }if (interactive()) { dead_items <- payload_queue_dead_letter() for (item in dead_items) { cat("Failed item:", item$id, "Error:", item$error, "\n") } }
Process queued payloads
payload_queue_process(processor, max_items = 10)payload_queue_process(processor, max_items = 10)
processor |
A function that accepts (path, payload, meta) and processes it. Should return TRUE on success, FALSE on failure. |
max_items |
Maximum number of items to process (default 10) |
A list with processing results
if (interactive()) { # Process queued items result <- payload_queue_process(function(path, payload, meta) { cat("Processing payload for", path, "\n") # Your processing logic here TRUE # Return TRUE on success }) cat("Processed:", result$processed, "items\n") }if (interactive()) { # Process queued items result <- payload_queue_process(function(path, payload, meta) { cat("Processing payload for", path, "\n") # Your processing logic here TRUE # Return TRUE on success }) cat("Processed:", result$processed, "items\n") }
Get queue status and statistics
payload_queue_status()payload_queue_status()
A list containing queue statistics
if (interactive()) { status <- payload_queue_status() cat("Pending items:", status$pending, "\n") cat("Dead letter items:", status$dead_letter, "\n") }if (interactive()) { status <- payload_queue_status() cat("Pending items:", status$pending, "\n") cat("Dead letter items:", status$dead_letter, "\n") }
Configure custom response handler for an endpoint
payload_response_config(path, handler)payload_response_config(path, handler)
path |
The URL path to configure response handler for |
handler |
A function that accepts (payload, req) and returns a list with:
|
Invisibly returns TRUE, called for side effects
if (interactive()) { # Set custom response handler payload_response_config("/api/process", function(payload, req) { list( status = 201L, body = list( received = TRUE, id = paste0("item_", sample(10000:99999, 1)), timestamp = Sys.time() ) ) }) # Remove handler (use default response) payload_response_config("/api/process", NULL) }if (interactive()) { # Set custom response handler payload_response_config("/api/process", function(payload, req) { list( status = 201L, body = list( received = TRUE, id = paste0("item_", sample(10000:99999, 1)), timestamp = Sys.time() ) ) }) # Remove handler (use default response) payload_response_config("/api/process", NULL) }
Get current response handlers
payload_response_status()payload_response_status()
A list of configured response handlers by path
if (interactive()) { status <- payload_response_status() cat("Configured handlers for:", paste(names(status$handlers), collapse = ", "), "\n") }if (interactive()) { status <- payload_response_status() cat("Configured handlers for:", paste(names(status$handlers), collapse = ", "), "\n") }
Configure JSON Schema validation for an endpoint
payload_schema_config(path, schema)payload_schema_config(path, schema)
path |
The URL path to configure schema validation for |
schema |
JSON Schema as a character string, list, or path to a schema file. Pass NULL to remove schema validation. |
Invisibly returns TRUE, called for side effects
if (interactive()) { # Set JSON Schema for validation payload_schema_config("/api/data", '{ "type": "object", "required": ["name", "value"], "properties": { "name": {"type": "string"}, "value": {"type": "number"} } }') # Remove schema validation payload_schema_config("/api/data", NULL) }if (interactive()) { # Set JSON Schema for validation payload_schema_config("/api/data", '{ "type": "object", "required": ["name", "value"], "properties": { "name": {"type": "string"}, "value": {"type": "number"} } }') # Remove schema validation payload_schema_config("/api/data", NULL) }
Get current JSON Schema configurations
payload_schema_status()payload_schema_status()
A list of configured schemas by path
if (interactive()) { status <- payload_schema_status() cat("Schemas configured for:", paste(status$configured_paths, collapse = ", "), "\n") }if (interactive()) { status <- payload_schema_status() cat("Schemas configured for:", paste(status$configured_paths, collapse = ", "), "\n") }
Clear rate limit records for specific IP or all IPs
payload_security_clear_rate_limits(ip_address = NULL)payload_security_clear_rate_limits(ip_address = NULL)
ip_address |
Specific IP address to clear, or NULL for all (default NULL) |
Number of IP records that were cleared
if (interactive()) { # Clear rate limits for specific IP cleared <- payload_security_clear_rate_limits("192.168.1.10") # Clear all rate limit records total_cleared <- payload_security_clear_rate_limits() }if (interactive()) { # Clear rate limits for specific IP cleared <- payload_security_clear_rate_limits("192.168.1.10") # Clear all rate limit records total_cleared <- payload_security_clear_rate_limits() }
Configure security settings for payload endpoints
payload_security_config( hmac_secret = NULL, ip_whitelist = NULL, ip_blacklist = NULL, rate_limit_enabled = FALSE, rate_limit_requests = 100, rate_limit_window_seconds = 3600 )payload_security_config( hmac_secret = NULL, ip_whitelist = NULL, ip_blacklist = NULL, rate_limit_enabled = FALSE, rate_limit_requests = 100, rate_limit_window_seconds = 3600 )
hmac_secret |
Secret key for HMAC signature validation (optional) |
ip_whitelist |
Character vector of allowed IP addresses (optional) |
ip_blacklist |
Character vector of denied IP addresses (optional) |
rate_limit_enabled |
Enable rate limiting (default FALSE) |
rate_limit_requests |
Maximum requests per window (default 100) |
rate_limit_window_seconds |
Time window in seconds (default 3600 = 1 hour) |
No return value, updates global security configuration
if (interactive()) { # Enable HMAC signature validation payload_security_config(hmac_secret = "your-webhook-secret") # IP whitelist for production payload_security_config(ip_whitelist = c("192.168.1.10", "10.0.0.5")) # Rate limiting payload_security_config( rate_limit_enabled = TRUE, rate_limit_requests = 50, rate_limit_window_seconds = 1800 ) }if (interactive()) { # Enable HMAC signature validation payload_security_config(hmac_secret = "your-webhook-secret") # IP whitelist for production payload_security_config(ip_whitelist = c("192.168.1.10", "10.0.0.5")) # Rate limiting payload_security_config( rate_limit_enabled = TRUE, rate_limit_requests = 50, rate_limit_window_seconds = 1800 ) }
Get current security configuration
payload_security_status()payload_security_status()
A list containing current security settings
if (interactive()) { config <- payload_security_status() cat("Rate limiting enabled:", config$rate_limit_enabled, "\n") cat("IP whitelist count:", length(config$ip_whitelist %||% character(0)), "\n") }if (interactive()) { config <- payload_security_status() cat("Rate limiting enabled:", config$rate_limit_enabled, "\n") cat("IP whitelist count:", length(config$ip_whitelist %||% character(0)), "\n") }
Create a streaming reactive for real-time payload updates
payload_stream( path = "/ingress", session, filter_func = NULL, transform_func = NULL, intervalMillis = 100, max_items = 50 )payload_stream( path = "/ingress", session, filter_func = NULL, transform_func = NULL, intervalMillis = 100, max_items = 50 )
path |
The URL path used in payload_ui() or payload_methods() (default "/ingress") |
session |
The Shiny session object |
filter_func |
Optional function to filter payloads. Should return TRUE to include payload |
transform_func |
Optional function to transform payloads before returning |
intervalMillis |
Polling interval in milliseconds (default 100 for real-time) |
max_items |
Maximum number of items to keep in stream (default 50) |
A reactive expression that returns a list of recent payloads matching the filter
if (interactive()) { server <- function(input, output, session) { # Stream all payloads all_stream <- payload_stream("/api/data", session) # Stream only error events error_stream <- payload_stream("/api/data", session, filter_func = function(payload) { !is.null(payload$payload$level) && payload$payload$level == "error" } ) # Stream with transformation temp_stream <- payload_stream("/api/sensors", session, filter_func = function(payload) { !is.null(payload$payload$type) && payload$payload$type == "temperature" }, transform_func = function(payload) { list( timestamp = payload$meta$timestamp, temp_celsius = payload$payload$value, temp_fahrenheit = payload$payload$value * 9/5 + 32 ) } ) } }if (interactive()) { server <- function(input, output, session) { # Stream all payloads all_stream <- payload_stream("/api/data", session) # Stream only error events error_stream <- payload_stream("/api/data", session, filter_func = function(payload) { !is.null(payload$payload$level) && payload$payload$level == "error" } ) # Stream with transformation temp_stream <- payload_stream("/api/sensors", session, filter_func = function(payload) { !is.null(payload$payload$type) && payload$payload$type == "temperature" }, transform_func = function(payload) { list( timestamp = payload$meta$timestamp, temp_celsius = payload$payload$value, temp_fahrenheit = payload$payload$value * 9/5 + 32 ) } ) } }
Get comprehensive system status and diagnostics
payload_system_status()payload_system_status()
A list containing detailed system information
if (interactive()) { status <- payload_system_status() print(status) }if (interactive()) { status <- payload_system_status() print(status) }
Wrap an existing UI with an integrated POST handler on the same port
payload_ui(base_ui, path = "/ingress", token = NULL, response_handler = NULL)payload_ui(base_ui, path = "/ingress", token = NULL, response_handler = NULL)
base_ui |
The original UI (tagList, fluidPage, or a function(req) returning UI) |
path |
The URL path to handle POST requests (default "/ingress") |
token |
Optional authentication token for POST requests |
response_handler |
Optional function to customize responses. Should accept (payload, req) and return a list with: status, body, content_type, headers (all optional) |
A function that takes a request object and returns either the regular UI (for GET requests) or an HTTP response (for POST requests). This function should be passed to shinyApp() as the ui parameter.
if (interactive()) { ui <- payload_ui( fluidPage(h1("My App")), path = "/data", token = "secret123" ) shinyApp(ui, server, uiPattern = ".*") # With custom response handler ui <- payload_ui( fluidPage(h1("My App")), path = "/api/process", response_handler = function(payload, req) { list( status = 201L, body = list(received = TRUE, id = sample(10000:99999, 1)) ) } ) }if (interactive()) { ui <- payload_ui( fluidPage(h1("My App")), path = "/data", token = "secret123" ) shinyApp(ui, server, uiPattern = ".*") # With custom response handler ui <- payload_ui( fluidPage(h1("My App")), path = "/api/process", response_handler = function(payload, req) { list( status = 201L, body = list(received = TRUE, id = sample(10000:99999, 1)) ) } ) }
Configure multipart/file upload settings
payload_upload_config(max_size = 10 * 1024 * 1024)payload_upload_config(max_size = 10 * 1024 * 1024)
max_size |
Maximum upload size in bytes (default 10MB) |
Invisibly returns TRUE, called for side effects
if (interactive()) { # Allow uploads up to 50MB payload_upload_config(max_size = 50 * 1024 * 1024) }if (interactive()) { # Allow uploads up to 50MB payload_upload_config(max_size = 50 * 1024 * 1024) }
Get current upload configuration
payload_upload_status()payload_upload_status()
A list containing upload settings
if (interactive()) { status <- payload_upload_status() cat("Max upload size:", status$max_size_mb, "MB\n") }if (interactive()) { status <- payload_upload_status() cat("Max upload size:", status$max_size_mb, "MB\n") }
Setup POST endpoint in server function - MUST be called in server
setup_payload_endpoint(path = "/ingress", session, token = NULL)setup_payload_endpoint(path = "/ingress", session, token = NULL)
path |
The URL path to handle POST requests (default "/ingress") |
session |
The Shiny session object |
token |
Optional authentication token for POST requests |
No return value, called for side effects. Registers a POST endpoint handler with the Shiny session that will process incoming requests.