Giter Site home page Giter Site logo

plumber's People

Contributors

antoine-sachet avatar blairj09 avatar eitsupi avatar fvd avatar howardbaek avatar jcheng5 avatar jdtrat avatar josiahparry avatar m-muecke avatar maxheld83 avatar meztez avatar mhairi avatar mtoto avatar muschellij2 avatar pachadotdev avatar randyzwitch avatar robertdj avatar s-fleck avatar sambaala avatar schloerke avatar scottmmjackson avatar shapenaji avatar shrektan avatar svdwoude avatar thiyagu-p avatar trestletech avatar tylergrantsmith avatar vfulco avatar vspinu avatar wkmor1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

plumber's Issues

ggplot2 gives error, is it supported?

I have the following post_serv.R file.

# post_serv.R

library(ggplot2)
library(magrittr)

df <- data.frame(x = rnorm(10, 0, 1), y = rnorm(10, 0, 1))

#' @png
#' @get /plot
get_plot <- function(){
  ggplot() + geom_point(data=df, aes(x,y), alpha = 0.5)
  # plot(df$x, df$y, main="Recent Values")
}

This then gets run from Rstudio using plumber::plumb('~/Desktop/post_serv.R')$run(port=8000)

Then when I access via the browser I get this error:

{"error":["500 - Internal server error"],"message":["cannot open the connection"]}

When I use the standard plot function, everything seems to work just fine. Is ggplot2 not supported?

Support parsing JSON on POST

As far as I can tell, the only way to POST values to a plumber API is using & separated strings. ie:

 curl -i -X POST http://plumber.tres.tl/append/append -d "val=50" 

and there is no support yet for JSON formatted data, ie.:

curl -H "Content-Type: application/json" -X POST  http://plumber.tres.tl/append/append -d '{"val":50}'

The function postBodyFilter filters using parseQS that splits on & and = and does not yet check for JSON formats (perhaps based on an initial { and ending }.

data.table syntax

If data.table syntax is used in a file, plumb("myfile.R") will fail.

here is an example "myfile.R"

library(data.table)
x <- as.data.table(BOD)
x[, demand]

#* @get /test
function() x

Now, when I try to plumb it I get an error

> p <- plumb("myfile.R")
Error in `[.data.frame`(x, i, j) : object 'demand' not found

Auto generate client

Given that we have the full API specification, we could auto generate client code/packages for R, JavaScript, etc.

plumb() a package

Is there a way to plumb an entire package? Basically creating the api in the package rather than an ad-hoc script plumber <- plumb(pkgname)

Enable CORS in Plumber

I am trying to make a POST request through my chrome browser, but its showing error of preflight request.
Please suggest a way to enable CORS at Plumber side.

Support for 'batch' mode, i.e. multiple lines of input data

I'm looking for a way to be able to pass in multiple lines of data in the form of

'curl --data "a=1&b=2\na=3&b=4\n..."

My specific use case would benefit a lot from being able to read in vectors of data in this way and then converting to a data frame within the function I am exposing as an API. To simplify, you can think of me simply passing in the contents of a .csv file.

You can see my attempt at reverse engineering your package here: https://github.com/FrankPortman/plumber.

I went into query-string.R and created a slightly modified parseQS function called parseQS2. I'm trying to mimic the exact format that parseQS returns, but in my case it's returning vectors of length > 1 in each sublist, as opposed to just 1 like you have. I then change the function in queryStringFilter from using parseQS to using parseQS2. However, it seems like when I pass in multiple lines of data, it is correctly doing the parseQS2 step (at least it looks that way from the traceback) but somewhere along the way some variables get dropped.

#* @post /test
function(a, b) {

  return(list(sum(as.numeric(a) + as.numeric(b)),
  as.numeric(a),
  as.numeric(b)))

}
curl --data "a=2&b=15 \n a=1&b=4 \n a=1&b=2" "http://localhost:1234/test"
[[4],[2],[2]]

It looks like only the first a and the last b is being evaluated.

curl --data "a=2&b=15 \n a=1&b=4" "http://localhost:1234/test"
[[6],[2],[4]

Before I dive deeper into this myself, are there any functions of specific pieces of code I would have to look into modifying in order to do something like this?

P.S. - I thought about approaching this problem from the other side (taking in only one line of named arguments but somehow encapsulating all the 'rows' I want to pass) but this approach seems cleaner if I can get it to work. Not sure if this is the best way of approaching my use case but if there is any interest from you/others on this functionality I'd be more than happy to discuss with you how this can potentially fit in with the package's architecture and help write tests for it so it can be merged eventually. For now, I'm just treating it as a one-off case for myself and am not too concerned with error handling so feel free to suggest something hacky.

Allowing 'source' to structure code

When a plumber server offers lots of functionality, the plumbed file is bound to get very large. It would be very helpful in terms of readability and maintainability if the code could be spread among several files, which are then just sourced into one big file.

Add arguments to res/req

Rather than the querystring parser(s) being special cases, make them filters that modify this special res/req$arguments object. Then use that object when injecting params into endpoints. Allows for custom additions to arguments to include, e.g. user, or session (which could also be attached to the req. But gives more options.

error when query string is too large

I'm developing an API that receives a JSON file, runs an algorithm and returns a JSON file as an output. Here is a small app that shows the problem I'm having.

myfile.R

#* @post /test2
test2 <- function(param){
list(param)
}
R -e "library(plumber); pr <- plumb('myfile.R'); pr\$run(port=1000)"

The point is that by changing the size of the query string, it gets a point where the request stops working. Here is what I'm getting as a result

A Query with 1000 characters

library(httr)

body = list(param = paste0(rep(0:9, 100), collapse=''))

r = POST(url, query = body, verbose())
content(r)

# > content(r)
# [[1]]
# [[1]][[1]]
# [1] "012345678901234567890123456789012345678901234567890123

A Query with 1000 characters doesn't work. The problem, that makes it hard to debug is It does work if I run the request locally.

body = list(param = paste0(rep(0:9, 500), collapse=''))

r = POST(url, query = body, verbose())
content(r)

# $error
# $error[[1]]
# [1] "404 - Resource Not Found"

Up-time and advice for running plumber on Windows

This is not an issue but a general question on the stability of this on a Windows Server.

I don't have any experience with this package, other than getting the examples to work, but it seems like an easy and good way to host an API (with low volume). My basic concern is that I have to restart the process all the time.

Does any one have experience with running plumber on a Windows (Virtual Server) and have some valuable advice to share? A Linux Server is not a possibility at my company.

json example in README isn't working

Starting server to listen on port 8000

<simpleError in (function (a, b) {    as.numeric(a) + as.numeric(b)})(): argument "a" is missing, with no default>

Warning in li["message"] <- err :
  number of items to replace is not a multiple of replacement length

I believe the CRAN version is outdated.

Support sub-routers

Plumber routers should be able to stack on one another by giving a prefix.

e.g.

prAcct <- plumb("accounts.R")
prSales <- plumb("sales.R")
pr$addRouter(prAcct, "/account")
pr$addRouter(prSales, "/sales")

Use attributes instead of comments

I suspect the implementation would be much simpler if instead of:

#' @get /mean
normalMean <- function(samples=10){
  data <- rnorm(samples)
  mean(data)
}

you did

normalMean <- function(samples=10){
  data <- rnorm(samples)
  mean(data)
}
expose(normalMean) <- "GET"

where you have

`expose<-` <- function(x, value) { 
  class(x) <- "api"
  attr(x, "method") <- "GET"
  x
}

or similar

Error: object of type 'closure' is not subsettable

Thanks for this cool library - exactly what I've been looking for. However - I've got a bit of an issue, I get the following error message:

{"error":["500 - Internal server error"],"message":["object of type 'closure' is not subsettable"]}

Or more detailed:

simpleError in data$PriceEUR: object of type 'closure' is not subsettable

Here's my code:

#' @get /predict
doPredict <- function(from, to, price, ndtf, type = "response") {
  getTree <- function(from, to) {
    varname <- paste0(from, "_", to);
    return(eval(parse(text=varname)));
  }

    tree <- getTree(from, to);

    # Creates a data frame from the parameters
    PriceEUR <- c(as.integer(price));
    NumDaysToFlight <- c(as.integer(ndtf));
    s  <- data.frame(PriceEUR, NumDaysToFlight);

    # Return the predicted value
    value <- predict(tree,1,s,type = type)
    return(value);
}

When I run this code locally - it works. Return type of the prediction call is an integer.

However, when called from the webserver, I get the error mentioned above. Am I doing something wrong or did I hit an issue?

Request of a -generated- list of Endpoints via the API

Hi,

This is a fantastic package. I'm using it for some dashboarding functionality, and what I'd like to offer the users is some documentation in the form of a list of Endpoint, i.e. a programmatic way to tell the users what functionality is present on the server currently running.

I can do this via a manually constructed list, which I then will have to maintain, and which may contain errors. So, how do I programmatically make a list of available Endpoints, the result of which I can serve to users?

Take care,
JFJanssen

Inconsistent plumbr vs plumber naming

Hey Jeff, just a heads up that it looks like you advertised on twitter a URL of http://plumbr.trestletech.com/ and in the tagline description of this repo you're also using the same url, but it's a 404 because of plumber vs plumbr.

I see there was a commit "Renamed to plumbr." so I suppose you intended to call it plumbr and ended up going with plumber? Anyway, just thought you should fix the URLs

Return CSV

What is the best way to return CSV?

The JSON is great, but I'm running into issues where the bandwidth is an issue. Thoughts?

Thanks!

Plumber just returning [true] for the initial example

Hi,

I am testing the suggested base example on RStudio in a a OSX Yosemite, but when accessing the API:
$ curl "http://localhost:8000/mean"

I keep getting the same response(via curl and browser):
[true]

Am I doing anything wrong?

Multiple cookie set incorrectly

Cookies are supposed to be one-per-line

Set-Cookie: cookie2=vale1; Expiration=...
Set-Cookie: cookie2=vale1; Expiration=...

Currently we're trying to set them all on one line which is invalid.

Not sure how this will fit into httpuv's notion that headers fit into a list.

Single process per R script/endpoint?

I have installed the package and am using the pm2 process manager and as far as I can tell it's just running a single R process no matter how many GET requests I make. Is there any way of spinning up a new R process for each new request?

Thanks!

Instructions for pm2 hosting setup are not working

I followed the directions on hosting plumber with pm2 here, however pm2 I get javascript errors as follows:

When R -e "library(plumber); r<-plumb('plumb-test.R');r\$run(port=8000)" was used I got

R -e "library(plumber);r <-plumb('plumb-test.R');r\$run(port=8000)"
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Unexpected string
    at Object.exports.runInThisContext (vm.js:76:16)
    at Module._compile (module.js:542:28)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Function._load (/usr/lib/node_modules/pm2/node_modules/pmx/lib/transaction.js:62:21)
    at Object.<anonymous> (/usr/lib/node_modules/pm2/lib/ProcessContainerFork.js:52:21)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)

When I saved the R code as a script and tried R -f plumb-start.R, I got:

ReferenceError: R is not defined
    at Object.<anonymous> (/usr/local/plumber/hello/plumb-hello:2:1)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Function._load (/usr/lib/node_modules/pm2/node_modules/pmx/lib/transaction.js:62:21)
    at Object.<anonymous> (/usr/lib/node_modules/pm2/lib/ProcessContainerFork.js:52:21)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)

Am I setting up something incorrectly? Or is this something that pm2 does not support? I'm using version 2.1.5 of pm2.

I have successfully been able to run the script as root... I'm not sure what I'm doing wrong.

Thanks.

XML Output instead of JSON

Hi,

I have formatted the output in XML and like to return the output as XML instead of JSON.

plumber now defaults to JSON. Is there any way to do that?

https

Do you expect that this would work in the same way over https?

Timeout with a long request

Hi !

We are generating a long report in PDF that takes around 3 minutes and we expose it via Plumber.
The HTTP connection close around 1 minutes 40 seconds (100 seconds).

So we have the logical error message because plumber try to send data to a closed connection:
ERROR: [on_request_read] connection reset by peer

I think it can be related to #12 and by the way rstudio/httpuv#49

There is a way to fix that in Plumber? May be by sending manually in Plumber something like that:

Keep-Alive: timeout=300
Connection: Keep-Alive

But in any case we want to avoid #12

Best regards,
Emmanuel

\" in JSON string - how to remove?

Hi, I'm trying to return JSON-LD from a GET.

No matter what gsub substitution I try , I can't seem to remove the slash quotes from the output.

so the output looks like the below:

["{ "@graph" : [ { "@id" : "http://example.com/dept/10", "http://example.com/dept/deptno" : { "@type" : "http://www.w3.org/2001/XMLSchema#integer", "@value" : "10" }, "http://example.com/dept/location" : "NEW YORK" }, { "@id" : "http://example.com/emp/7369", "http://example.com/emp/department" : { "@id" : "http://example.com/dept/10" }, "http://example.com/emp/name" : "SMITH", "http://example.com/emp/role" : { "@id" : "http://example.com/emp/general-office" } }, { "@id" : "http://example.com/emp/7370", "http://example.com/emp/department" : { "@id" : "http://example.com/dept/10" }, "http://example.com/emp/name" : "DOE", "http://example.com/emp/role" : { "@id" : "http://example.com/emp/engineering" } } ]}"]

Is there a way to format the string similar as the cat() function does where slashes from a character string are removed from the output?

Extracting a table as result

Hi,

I have an R code that connects with an API, gets content in the form of a table, and I transform that data, and modify, create columns, add filters, bind it with other content, and another table is produced towards the end. I am hoping to convert my code into an API and go further from there. I tried the Get method, and I keep failing. Since I can not paste the whole code, I am going share a summary of that code. Please try and help me out.

segment<- NULL #this has to be a variable for the API Get/Post 

toCall<- APIfunction("api credentials", segment) # my api to retrieve data, which currently works

df<- as.data.frame.list(toCall)

#This followed by some lines to transform data, remove unwanted columns/rows etc
#input from the above dataframe goes into the check function below
CheckFunction<- function1

CorrectFunction<- function2 #takes input from above function

rbind.results
structure the output
print(head(output))

I tried to write a Get query and call the final output and I get a 404 error.
I know this is not much to go with, but my hands are tied. Please help! Thank you!

Should the order in a .R file be preserved with regard to endpoints/filters

Currently, all filters would be evaluated before any endpoints unless an endpoint explicitly overrides that behavior. In things like Express/Restify, that's not true. You add filters and endpoints and the order is preserved. That seems like it might be more intuitive than the current behavior, but then introspection later is more confusing.

Using a key

Is there a way to implement an api key (like for example something you build the package with)?

Weird amount of slowness?

So I've been working on a project at https://github.com/Ironholds/sharder (it should be self-contained and locally runnable). You launch it and then run:

readLines("http://localhost:8000/mirror?https=0")

It's exceedingly slow to produce a response, so I filled it with little debugging flags (producing periods, printing timestamps, all the rest) and...none of them are slow. They churn through incredibly quickly. It does everything in main() in a fraction of a second. But for some reason it's incredibly slow to actually return and send out a response - as proof, I typed out this entire comment in less time than it took to run.

Any ideas?

Adding PDF support

Hi,

I try to send a pdf with my API in R and Plumber (Plumber is a very good idea :).

*pdf doesn't work.

I have to modify jsonSerializer in that way to have it working :

jsonSerializer` <- function(val, req, res, errorHandler){
tryCatch({

res$setHeader("Content-Type", "application/pdf")
res$body <- val

return(res$toResponse())

}, error=function(e){
errorHandler(req, res, e)
})
}

.globals$serializers[["json"]] <- `jsonSerializer

Do you have another (cleaner ;) way to do that ?
Thanks

let a few services continuously running (daemon) using plumber.

What would be the recommended way to create a daemon using plumber ?

## if plum is a script which contain all the commands
plum.R
## running from terminal using & should work
Rscript plum.R &

issues
Issue is what if I press this twice, and there are two conflicting scripts running on the same port.
What is someone else does the same.

Possible to check all plumber services running (given a port)?

jsonlite auto_unbox

I am trying to send back a JSON response like this:

{"status_code":101,"status_message":"Invalid object"}

Here is my code:

return (list(status_code=101, status_message="Invalid object"))

The response I get is:

{"status_code":[101],"status_message":["Invalid object"]}

I'd like to NOT have the brackets (array).

It seems like this is in the call to jsonlite::toJSON

library(jsonlite)
ret <- list(status_code=101, status_message="Invalid object"))
toJSON(ret)
{"status_code":[101],"status_message":["Invalid object"]} 
toJSON(ret, auto_unbox = TRUE)
{"status_code":101,"status_message":"Invalid object"} 

I tried defining a new serializer, but that seems like a hack.

Is there a way around this?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.