Variant 3 — Plumber Drop-In (drogonR::pr_run)

If you already have a plumber service, the shim lets you run it under drogonR by changing one line. The shim parses the plumber router into drogonR routes and dispatches them through dr_serve(). Existing handlers, paths, and parameter types keep working.

For the overall picture see vignette("drogonR", package = "drogonR").


The one-line swap

Existing plumber code:

library(plumber)
pr <- pr() |>
  pr_get ("/users/<id:int>", function(id) list(id = id, ok = TRUE)) |>
  pr_post("/users",          function(req) {
    body <- jsonlite::fromJSON(req$postBody)
    list(created = body$name)
  })

plumber::pr_run(pr, port = 8080L, docs = FALSE)   # <-- before

Becomes:

drogonR::pr_run(pr, port = 8080L, docs = FALSE)   # <-- after

That’s the whole change. docs, swagger, swaggerCallback, quiet are silently accepted and ignored (the shim has no swagger surface, so the flags are inapplicable but valid). Other arguments — threads, workers, max_queue — forward to dr_serve().


What the shim supports


What the shim rejects

Each of these triggers an explicit error at pr_run() time, before any route is registered, so failure is loud:


A minimal end-to-end example

library(plumber)
library(drogonR)

pr <- pr() |>
  pr_get ("/health",                function() list(ok = TRUE)) |>
  pr_get ("/users/<id:int>",        function(id) {
    list(id = id, type = typeof(id))     # id arrives as integer
  }) |>
  pr_post("/echo",                  function(req) {
    list(received = jsonlite::fromJSON(req$postBody))
  })

drogonR::pr_run(pr, port = 8080L, docs = FALSE)

Three responses your client will see:

GET /health         -> {"ok":[true]}
GET /users/42       -> {"id":[42],"type":["integer"]}
POST /echo {"a":1}  -> {"received":{"a":[1]}}

The bracketed scalars are plumber’s default serialiser (auto_unbox = FALSE) — preserved on purpose so existing clients don’t break. To get unboxed JSON, return dr_json(x, auto_unbox = TRUE) from the handler; that bypasses the default serializer.


When to migrate to native

The shim is fine for steady-state plumber apps. Reach for the native API (vignette("mode-native")) if you want:

If your hot endpoint is C/C++-bound (model inference, embeddings), register that endpoint with dr_get_cpp() and leave the rest under the shim — see vignette("mode-cpp-shared", package = "drogonR").