> A good API should just accept either,e.g. the union of []byte and io.Reader.
could be done. Can you elaborate on how the fact that io.Reader is an interface lets you accept a []byte in the API? To my knowledge, the answer is: you can't. You have to wrap the []byte in an io.Reader, and you are at the exact problem described in the article.
I see what you’re saying. You’re correct that you can’t pass a []byte as an io.Reader, but you can implement io.Reader on a []byte in a way that lets you get the []byte back out via type switch (the problem in the article was that the standard library type didn’t let you access the internal []byte).
An idiomatic way to approach this would be to define a new interface, let's call it Bytes with a Bytes() []byte method.
Your function would accept an io.Reader but then the function body would typeswitch and check if the argument implements the Bytes interface. If it does, then call the Bytes() method. If it doesn't then call io.ReadAll() and continue to use the []byte in the rest of the impl.
The bytes.Buffer type already implements this Bytes() method with that signature. By the rules of Go this means it will be treated as an implementation of this Bytes interface, even if nobody defined that interface yet in the stdlib.
> A good API should just accept either,e.g. the union of []byte and io.Reader.
could be done. Can you elaborate on how the fact that io.Reader is an interface lets you accept a []byte in the API? To my knowledge, the answer is: you can't. You have to wrap the []byte in an io.Reader, and you are at the exact problem described in the article.