mazamascience / beakr Goto Github PK
View Code? Open in Web Editor NEWA Minimalist Web Framework for R
Home Page: https://mazamascience.github.io/beakr/
License: GNU General Public License v3.0
A Minimalist Web Framework for R
Home Page: https://mazamascience.github.io/beakr/
License: GNU General Public License v3.0
At the outset, our goal was to create a replacement for the deprecated jug package.
Some of the joy of using jug was that you didn't have to know much about unix or web servers and could just write some R code.
I have created two scripts to demonstrate what was possible with jug and what I would like to be possible with beakr:
local_executables/test_repeater_beakr.R
local_executables/test_repeater_jug.R
Looking at the diff shows how easy I was hoping it would be to convert our old web services:
$ diff test_repeater_jug.R test_repeater_beakr.R
8c8
< library(jug)
---
> library(beakr)
11c11
< jug() %>%
---
> newBeakr() %>%
15c15
< get("/", function(req, res, err) {
---
> GET("/", function(req, res, err) {
36c36
< get("/repeater", function(req, res, err) {
---
> GET("/repeater", function(req, res, err) {
88c88
< simple_error_handler_json() %>%
---
> errorHandler() %>%
92,93c92
< serve_it()
---
> startBeakr(daemon = FALSE)
The ** jug** version works as expected with a simple ability to walk through the debugger and quit with a single click on the stop button. It also generates desired output in a variety of formats and an informative, json formatted error message if times
> 10.
The beakr version doesn't currently work and I don't understand why. It also has a strange behavior where I have to click the stop button 3 times to get it to end.
We should talk at some point so that I can understand what has changed in the overall design and why. Perhaps there is a better way to rewrite the code I am familiar with. But it has to be a great improvement to justify any refactoring it will force on us. We have several complex, operational web services that currently depend on the deprecated jug package and my primarily goal is to support those going forward with a non-deprecated package.
I see a couple of good options at this point:
Apologies for the unsolicited question but, having tested and been impressed at the 'hello world' example, I'm wondering how this compares with the plumber
package. Context: @layik and I have used plumber as the basis of a package to visualise and serve geographic data, and am wondering if this package could have advantages as an R backend...
Thanks for sharing, looks like an impressive project with great potential!
I have pushed up beakr 0.4 to GitHub but cannot get the cors()
functionality to work. It may only be a documentation issue but, if so, that means that the core()
function arguments need a LOT more description.
I tried running the following in RStudio:
library(beakr)
newBeakr() %>%
cors() %>%
httpGET(path = "/hi", function(req, res, err) {
print("Hello, World!")
}) %>%
httpGET(path = "/bye", function(req, res, err) {
print("Farewell, my friends.")
}) %>%
handleErrors() %>%
listen(host = "127.0.0.1", port = 25118)
It works if I comment out the cors() %>%
line but fails if I uses it with the following error message:
Error in ans[ypos] <- rep(yes, length.out = len)[ypos] :
replacement has length zero
Here is my environment:
> sessionInfo()
R version 4.0.2 (2020-06-22)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Catalina 10.15.7
Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] beakr_0.4.0
loaded via a namespace (and not attached):
[1] Rcpp_1.0.6 rstudioapi_0.13 magrittr_2.0.1
[4] webutils_1.1 hms_0.5.3 lattice_0.20-41
[7] R6_2.5.0 rlang_0.4.10 stringr_1.4.0
[10] tools_4.0.2 rgdal_1.5-18 grid_4.0.2
[13] lambda.r_1.2.4 futile.logger_1.4.3 ellipsis_0.3.1
[16] tibble_3.0.6 lifecycle_0.2.0 crayon_1.3.4
[19] readr_1.4.0 formatR_1.7 later_1.1.0.1
[22] base64enc_0.1-3 vctrs_0.3.6 promises_1.1.1
[25] futile.options_1.0.1 sp_1.4-5 stringi_1.5.3
[28] compiler_4.0.2 pillar_1.4.7 MazamaCoreUtils_0.4.7
[31] jsonlite_1.7.2 httpuv_1.5.5 pkgconfig_2.0.3
The monitoring-data-service uses jug$set_header()
to modify the content-disposition
.
I think it highly appropriate that we have some debugging options but they shouldn't be global through the use of options("beakr.verbose" = FALSE)
. Instead, the R6 class should have a verbose
field with an associated getter and setter.
This sounds like an interesting package but how does it compare to other web frameworks like plumber, shiny and fiery? I think I'd like to know when to choose beakr.
We would like to have an overall naming scheme that uses nouns for classes and variables and verbs for methods and functions. Any exceptions to this rule, like static()
should adhere to some internal standard, i.e. dropping create
from createNewBeaker()
to get just newBeaker()
.
Developers should be able to specify their own error handling methods instead of using the default jsonError()
method called by handleErrors()
.
Several functions currently have examples in the form of preformatted code snippets. We aren't using @example
because we don't actually want to start up a web service.
To encourage people to use a new package it is really nice to have examples that can just be copy-pasted into the RStudio console where a user can observe what happens. The code examples are currently structured as pseudo-code where a user has to modify things before they can be run. This acts as a barrier to first-time users.
All examples should instead modify the existing example in README.md
using comment lines to explain rather than pseudo-code. The goal is to have all examples work if copy-pasted into the RStudio console.
library(beakr)
# Create a new beakr server
newBeakr() %>%
# Respond to GET requests at the "/hi" route
httpGET(path = "/hi", function(req, res, err) {
print("Hello, World!")
}) %>%
# Respond to GET requests at the "/bye" route
httpGET(path = "/bye", function(req, res, err) {
print("Farewell, my friends.")
}) %>%
# Start the server on port 25118
listen(host = "127.0.0.1", port = 25118)
This rename would match beakr$serverObject
and would make it obvious throughout the code base that we are referring to an R6 Router
object and not just the url path.
Router.R
has: "try-err" %in% class(result)
which won't match. It needs to be "try-error" %in% class(result)
The blog has a draft article titled "Web Frameworks for R" which is partly finished. It should be completed with brief assessments of the following packages:
This article is not supposed to be a detailed review but rather a brief comparison for those wondering whether to try it out or not. It can unabashedly advocate for beakr as having the right set of features for Mazama Science: we are comfortable with web protocols and html/css/javascript and need an R web framework that is simple, robust and flexible.
We need to have examples (at least in local_examples/
) that demonstrate how to use beakr as a replacement for jug in our existing web services. By far the most common use case is to attach functions to URL paths. The functions will typically:
req, res, err
File types that we currently serve include:
But we want to be able to serve up just about anything along with the proper mime type. (See the mime package.)
Although all the necessary roxygen2 comments seem to be in place, no documentation is shown in RStudio for the objects Beakr
, Request
, Response
, etc.
We need to figure out how to document R6 objects so that this documentation becomes visible in the installed package.
We need an article that walks people through the basics of setting up a dockerized web service.
I was surprised that startBeakr()
appears to default to daemon = TRUE
.
I think this is not the behavior we want as it requires the user to be familiar with UNIX systems and to trust themselves with killing processes. (I'm still not sure myself about how dangerous kiilAll()
might be.)
A better default would be daemon = FALSE
so that development and testing can consist of:
And we need to make sure that this new R6 style documentation mentions the default settings somewhere. I had to experiment and read the source code to understand what the default settings were for startBeakr
()`.
This version of beakr serves .png and .txt files fine. But when asked for a .html file it always returns "3c".
Here is a script that reproduces the error:
# ===== Create output files ====================================================
if ( FALSE ) {
# Create a .txt file in temp directory
dir.create("./output")
textString <-
"
<html>
<body>
<h1>Hi!</h1>
</body>
</html>
"
cat(textString, file = "output/hi.txt")
cat(textString, file = "output/hi.htm")
cat(textString, file = "output/hi.html")
}
# ===== beakr pipeline =========================================================
library(beakr)
# beakr pipeline
newBeakr() %>%
# Respond to GET requests at the "/hi" route
httpGET(path = "/hi", function(req, res, err) {
print("Hello, World!")
}) %>%
# Respond to GET requests at the "/bye" route
httpGET(path = "/bye", function(req, res, err) {
print("Farewell, my friends.")
}) %>%
# Host the directory of static files
serveStaticFiles() %>%
# Start the server on port 25118
listen(host = "127.0.0.1", port = 25118)
# * http://localhost:25118/output/hi.txt -- works
# * http://localhost:25118/output/hi.htm -- FAILS: returns "3c"
# * http://localhost:25118/output/hi.html -- FAILS: returns "3c"
This task is a good way to practice submitting a PR (GitHub Pull Request) to another open source project.
The plumber package README.md
file ends with:
Related Projects
- OpenCPU - A server designed for hosting R APIs with an eye towards scientific research.
- jug - (development discontinued) an R package similar to Plumber but uses a more programmatic approach to constructing the API.
You should read up on how to make a contribution, update the wording in the README.md
file to replace "jug - (development discontinued) " with "beakr - " and submit a pull request.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.