[Plumber] How to check if certain serializer is already added

For my Plumber API, I use a custom serializer because the output of one my endpoints is always consumed in R. The serializer code is below:

##### R object serializer ####
# Custom serializer when output is always consumed in R
# Based on https://shrektan.com/post/2018/11/14/use-base-serializer-in-the-plumber-api/
plumber::addSerializer("r_obj_serializer", function() {
  function(val, req, res, errorHandler) {
    tryCatch({
      res$setHeader("Content-Type", "application/octet-stream")
      res$body <- base::serialize(val, NULL, ascii = FALSE)
      return(res$toResponse())
    }, error = function(e) {
      errorHandler(req, res, e)
    })
  }
})

And the endpoint looks like:

##### GET /api/v0/test #####
#* Endpoint that bypasses serialization
#* @serializer r_obj_serializer
#* @get /api/v0/test
function(res){
  message("Came here")
  set.seed(123)
  v <- rnorm(1e8)
  return(v)
}

This part works well. The issue occurs when I am coding, and I start the plumber API multiple times using below code to test my latest edits:

plumber::plumb("~/server.R")$run(port = 9002, host = "0.0.0.0")

On each run, I keep getting the error:

 Error in plumber::addSerializer("r_obj_serializer", function() { : 
  Already have a serializer by the name of r_obj_serializer 

The way I get around this error is to restart R session every time I have a local edit and want to start the plumber API. However that causes an additional delay in my development workflow.

Is there a way by which I can check if a serializer already exists, and I would avoid adding the serializer again and again.

Currently no standard way of doing it. I've added a feature request here: https://github.com/rstudio/plumber/issues/482

What you can do until the bug is fixed...

##### R object serializer ####
# Custom serializer when output is always consumed in R
# Based on https://shrektan.com/post/2018/11/14/use-base-serializer-in-the-plumber-api/
if (is.null(plumber:::.globals$serializers[["r_obj_serializer"]])) {
  plumber::addSerializer("r_obj_serializer", function() {
    function(val, req, res, errorHandler) {
      tryCatch({
        res$setHeader("Content-Type", "application/octet-stream")
        res$body <- base::serialize(val, NULL, ascii = FALSE)
        return(res$toResponse())
      }, error = function(e) {
        errorHandler(req, res, e)
      })
    }
  })
}

Hope this helps!

@barret

I made the following edit to your if condition and it worked after that:

# if (!is.null(.globals$serializers[[name]])) { # ===> becomes
if (is.null(plumber:::.globals$serializers[[<name>]])) {

i.e.

  • add serializer on is.null condition
  • specify .globals as an internally scoped object of plumber package

Would be great if you could incorporate the changes to your response.

1 Like

@kritisen Thank you for the fixes!

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.