I’m wrapping a (stateless, hit-every-time) REST API and my design was challenged with an alternative opinion - which is great! I get to have a more serious think about design and what might work best. I have an internal function which does the actual talking to the server, e.g. .get_from_API() which needs to know the URL, auth key, and query parameters. I originally designed my package to fetch these from environment variables depending on the API instance (e.g. ‘prod’ vs ‘dev’) and the user (their user-specific key). Individual endpoint wrappers essentially boil down to

get_this <- function(something) {
    .get_from_API(construct_endpoint(something))
}

I asked the following question on some of the social sites I use:


Is there a good reason to use one of these vs the other when wrapping an API?

A:

get_this(x, ...) # GET
get_that(x, ...) # GET
set_this(x, y, ...) # SET
set_that(x, y, ...) # SET

with something like this within each of these

greedy_con <- .connect(Sys.getenv(implicit_api_vars), ...)

OR

B:

lazy_con <- .connect(explicit_api_vars, ...)
this(lazy_con, x, ...) # GET
that(lazy_con, x, ...) # GET
this(lazy_con, x) <- y # SET
that(lazy_con, x) <- y # SET

(Or some third option)?


The motivation for the second option may have come from python where methods on objects are much more common. Indeed, the canonical python version of this wrapper uses

lazy_con = NameOfAPI(url = {}, key = {})

lazy_con.this()
lazy_con.that()

In R we have dispatch (e.g. S3) so I could assign a class mycon to lazy_con and methods this.mycon() and that.mycon() but this seems very overengineered. Apparently BioConductor also uses this method syntax but there the standard is S4 dispatch (and typically larger data) so a more explicit object might make more sense.

Methods on classes seems to be a common frustration for me in python and rust where I’m constantly trying to use some function (e.g. abs(x-y)) which is actually a method ((x-y).abs()) but I think I understand why they’re built that way.

So far the responses seem to lean entirely towards hiding the complexity of the connection away. That said, adopting the ‘setter’ assignment syntax would mean I could do away with the explicit ‘get’ in the getter function names.

Do you have an opinion on this? Let me know!