Looking for some API design advice.
I’m writing an API that streams a limited number of results, that may fail between any two results, and that that the consumer may wish to instruct to respond to failure by retrying with all progress intact.
Since channels have only one return value, I can’t just do val, err <- myChan
.
I could do msg <- myChan
, where msg
is a struct{Val T; Err error}
. I don’t like that it makes errors easier to ignore, makes property access a bit more verbose, and does some unnecessary allocation. I could avoid the second and lessen the third by flattening the Val
struct into the message struct, at the cost of maybe some clarity loss.
I could have two separate channels, one for results and one for errors, but this makes makes iteration convoluted—you can’t just use range
any more, you need a special “done” signal, etc. More opportunities to screw up, more noise while reading and writing. It also means you can’t write the API call inline.
I could do myChan, err := my.Api()
then set err
on failure, but besides a very counter-intuitive err
behavior, this makes the consumer code for retrying on error convoluted—they need to get back into the loop somehow.
I’m thinking message structs are the best option, but want to know if anybody has a better idea.