Open JHibbard opened 6 years ago
You can document response codes (see https://github.com/trestletech/plumber/blob/master/inst/examples/11-car-inventory/plumber.R#L46), but currently not the response structure.
I haven't figured out a great way to enable the documentation of the response structure. I'm thinking there may be something built around R6 that would allow us to document the structure of each object that we're going to serialize in/out, but a.) jsonlite doesn't play nicely with R6 custom serialization at this point AFAIK, and b.) I'm not convinced that this is the best path forward.
How would you want to document the structure of your objects?
Ah, that sounds tricky.
I'd like to define a named json schema that I can reuse; e.g. I might have a "cookie" definition that maps to a (swagger/open api) json schema with {'type':
A possible "quick fix" would be to allow a filter to be applied after an endpoint's function, on the response. Then you could inject this information into the swagger.json before it gets returned to callers. You could also use these post-filters to reformat JSON if you needed objects to be serialized in a very specific way.
Yeah, I'd be tempted to just allow extensions/modifications to the Swagger generation at that point.
My gut is that there's an elegant solution hiding in here somewhere using R6. It would be a little extra work on the API author to have to compose their APIs using these R6 objects, but I feel like the type safety you'd get in exchange would be worth it.
Unfortunately, that might require some extensions to jsonlite to get that to work, as -- last I checked -- it wasn't supported.
I'd be very interested in exploring this further and implementing this.
I'm not quite sure I completely understand the approach you have in mind with R6. Could you provide a minimal example of the annotation you'd envision for the response schema? Or would you generate that response schema entirely based upon an 'example' output from the endpoint-function?
I'd be interested in exploring this area too.
For typical complex return types (e.g. single-depth lists and tibbles) I'm wondering whether we could:
\item
in roxygen https://roxygen2.r-lib.org/articles/formatting.htmlI think I especially like that second idea... e.g. something like:
Plumber could either support declaring the dto using "normal R" or using a dto comment block
# doing this in "real R" would be easiest for coders to maintain:
cars_dto <- tibble(
id = integer(),
name = character(),
mpg = double(),
cyl = integer(),
# etc
)
# doing this in "plumber comment blocks" would be easiest to get strict descriptions (and type conversions):
#* @dto cars_dto {
#* id:integer
#* name:string
#* mpg:number
#* cyl:integer
#* # etc
#* }
Then the api code could look like
#* Return the cars
#* @get /cars
#* @return [cars_dto] the cars
function() {
datasets::mtcars
}
#* Return a car
#* @param id:integer the car
#* @get /cars/<id>
#* @return cars_dto the car
function(id) {
as.list(
datasets::mtcars[id, ]
)
}
Would have to think how that scaled/worked for other things (single values? vectors? nested data.frames? lists? lists of lists of data.frames of.... ?)
Whatever gets designed, it might also be nice to be able to use it to describe request bodies too...
#* add a car
#* @post /cars
#* @body cars_dto
#* @return [integer] the id of the added car
function(req, res) {
# code to add a car
}
~... and we could also consider methods listing their error code responses as well their 200s (https://swagger.io/docs/specification/describing-responses/)~ - I think current response codes are ok - only 200 would benefit from some structure (sometimes)
Note:
Have had a go at this in #892 - it seems to work - but don't know how much R developers will invest in these definitions. We do love our (very) dynamic typing!
Is it possible to annotate endpoints with their response type(s)/structure? The swagger codegen project released (Sep 2017) code to generate R clients from swagger specs but requires these endpoint specs to deserialize responses; this along with plumber would allow a top to bottom RESTful api solution for R!