Return JSON and RData from an endpoint

Hello All,

I am working on writing an API using Plumber. I have a situation where I want to return say a results JSON object and RData together in a single API call.

library(plumber)
library(jsonlite)

#* @get /healthCheck
#* @serializer contentType list(type="text/plain; charset=UTF-8")
function(res) {
    res$status <- 200
    return("Ok")
}

#* @param data:file Input plain text file
#* @post /doJob
#* @serializer contentType list(type = "application/json")
function(data) {
    all_data <- read.table(header = TRUE,
                           sep = "\t",
                           text = as.character(data))

    avg <- mean(all_data[, 2])
    sdv <- sd(all_data[, 2])

    out_data <- list(avg = avg,
                     sdv = sdv)

    # Save RData
    tmp <- tempfile(fileext = ".RData")
    on.exit({
        if (file.exists(tmp)) {
            unlink(tmp)
        }
    }, add = TRUE)
    
    save(list = ls(all.names = TRUE), file = tmp, envir = environment())
    bin <- readBin(tmp, "raw", n = file.info(tmp)$size)

    return(jsonlite::toJSON(out_data))
}

See above for an example. An example input file will be a text file with numeric values in the second column.

df <- data.frame(x = c(10, 100, 1000),
                 y = c(12.8, 15.3, 22.1))
write.table(df, "test_data.txt", row.names = FALSE)

Running the following request:

curl -X POST "http://127.0.0.1:8000/doJob" -H "accept: application/json" -H "Content-Type: multipart/form-data" -F "data=@test_data.txt;type=text/plain"

Returns:

{
  "avg": [
    16.73333
  ],
  "sdv": [
    4.81283
  ]
}

However, I would like to retrieve RData in the same response, if possible. Wondering whether someone have any ideas how this can be achieved. Thanks in advance and let me know if the question isn't clear enough.

Cheers!

You could write the json content to a file. Compress both the .Rdata and json file into an archive and use plumber::as_attachment.

You could write a multipart/form-data serializer, currently not supported in plumber.

Other thing you could do, add a field to your json with the base64enc::base64encode content of readBin of the .RData file with parameter n = file.info(".Rdata")[["size"]].

1 Like

Thanks for the reply @meztez ! I ended up doing the third.

tmp <- tempfile(fileext = ".RData")
on.exit({
    if (file.exists(tmp)) {
        unlink(tmp)
    }
}, add = TRUE)
save(list = ls(all.names = TRUE), file = tmp, envir = environment())
bin <- readBin(tmp, "raw", n = file.info(tmp)$size)
out_data$r_data <- base64enc::base64encode(bin)

Thanks again for all the suggestions!