Yep. Rust's APIs do this right. Eg u32::to_be_bytes() / u32::to_le_bytes() and u32::from_be_bytes() / u32::from_le_bytes().
There's also methods for native byte order, but thats almost never the right thing to use.
I think Go does the same thing. I heard about this approach first from Rob Pike, who would rant about this to anyone who would listen. He said to think of "bytes on disk/network" and "an integer in RAM" as different types that you need to convert between. When you do, the API should specify the endian-ness of the bytes on disk / in the network. He argued you shouldn't do "byte swapping" at all based on endianness. Just parse the int, byte at a time and use the same code on every computer.
The real problem is that C makes it easy to convert between a pointer to an integer and a pointer to some bytes in RAM. Just never do that using pointer casting, and everything works out great.
https://doc.rust-lang.org/std/primitive.u32.html#method.to_b...