How do you design and implement a robust API client that gracefully handles transient network failures and rate limits?