Hi there, and thanks for all the fantastic work that we’re getting to use.
We’re in the process of writing a library to access popular shipping providers - think ActiveShipping
, but somewhat more modern and not archived. Here’s the gem if you’re interested (no need to read the gem, the question is entirely in this post):
We’re making heavy use of the Result
monad to wrap successful or unsuccesful API calls.
The API goes somewhat like this:
>>> ups_service.find_rates(shipment)
Success([rate1, rate2, rate3])
Now, for both Success
and Failure
, my colleagues are asking for debugging information because shipping APIs are complex and sometimes unpredictable, and it takes a lot of inspection to find out what went wrong. They would, specifically, like the shipment
object that was passed in as well as the request that was generated as well as the response obtained from the provider.
Currently, we have another object around the rates array that does this, so that we can do this:
>>> result = ups_service.find_rates(shipment)
Success(rates_result)
>>> result.value!.rates
[rate1, rate2, ...]
>>> result.value!.original_request
my_request
However, I believe it would be more ergonomic and nicer to be able to access the debugging info directly on the Result
object:
>>> result = ups_service.find_rates(shipment)
Success(rates_result)
>>> result.original_request
my_request
Is this possible? I’ve tried subclassing Result
, Success
and Failure
, but that seems to be pretty hard as all the syntactic sugar (constructor functions etc) need to be adapted as well, as the initialize
signature changes. I’m also not sure whether specialized Result
monad would play well in the rest of the Ecosystem. I was thinking of adding to_dry_result
to ameliorate this.
How do you go about these kinds of things? There’s one value that is really the thing you want, and a bunch of less important info that should go in the result as well.
What I’ve seen in the docs is using Arrays or Hashes for the value
that’s passed into the monad. That, however, is similar to the result container presented in the first example.
Caveat also: I’m not new to Ruby, but I am pretty new to functional programming and the Dry ecosystem. It’s entirely possible there’s a much better way of achieving what I want: An ergonomic API interface that lets library users get quickly at what they need.
Thank you for reading, and again: Thank you, I love your work!