1

TLDR: Should TIMEOUT be a public property on my static class, or a parameter to every function?


Background: I am releasing a c# client-api library that facilitates communicating with our REST api.

The client-api consists of an object model and one large static class with a bunch of request extension methods for various types. 10 or so .Get() variations, a few .Post(), .Put(), etc.

This static class full of extension methods is preconfigured with our server URL, and some other static configuration constants related to the connection. Because all the functionality is exposed via extension methods, there's no need to create an instance of this class. Any configuration is done via static properties and affects all requests made by the application.

Problem:

Right now, all requests use a default timeout of 3 seconds (which seems generous to us, as our API is meant to be very responsive.) Some users with a bad connection though might want to wait longer for a response.

Our quick-fix solution is to expose the DEFAULT_TIMEOUT at a public static property on the class which can be set once on initialization, but is the proper thing to do to add a new optional parameter to every single one of our dozens of methods?

.Get(int timeout = DEFAULT_TIMEOUT) { ... }
.Get(..., int timeout = DEFAULT_TIMEOUT) { ... }
.Get(..., ..., int timeout = DEFAULT_TIMEOUT) { ... }
.Get(..., ..., ..., int timeout = DEFAULT_TIMEOUT) { ... }
...
.Post(..., int timeout = DEFAULT_TIMEOUT) { ... }
.Put(..., int timeout = DEFAULT_TIMEOUT) { ... }
.Save(..., int timeout = DEFAULT_TIMEOUT) { ... }
...

On the one hand, we want to be flexible to whatever the consumer of our client-api library might need, but on the other hand, I won't want to get in the habit of polluting every method with every optional parameter that might impact a request (server url, authorization tokens, etc.)

What I don't want, is for the user to feel the need to do this:

ClientAPI.DEFAULT_TIMEOUT = 5000;
Thing found = new Thing(){ id = "19473" }.Get();
found.count += 1;
ClientAPI.DEFAULT_TIMEOUT = 20000;
found.Put();
ClientAPI.DEFAULT_TIMEOUT = 8000;
List<Widgets> widgets = found.GetSubresource("widgets");
...etc

Is it reasonable to assume users won't be micromanaging timeouts for individual requests like that?

  • 2
    You should probably use CancellationToken instead of just an integer. That way, the caller has more control over the cancellation. And in .Net 4.5, you can easily create CancellationToken that is automatically canceled after a timeout. – svick Dec 6 '13 at 21:00
  • @svick that sounds very flexible indeed. Out library is mostly a custom wrapper around the open source RestSharp and Newtonsoft Json.NET libraries to help users with their own simple applications communicate more easily with our server's public Rest API. I think if a user is advanced enough to use require the level of control CancellationTokens provide, then there's no harm in requesting that they simply implement their own low level code that interfaces our public REST API directly. – Alain Dec 6 '13 at 21:13
3

Is it reasonable to assume users won't be micromanaging timeouts for individual requests like that?

Well it really depends on the services being provided. Some operations might be very slow and he client might be able to anticipate that (for example, requesting all transactions on some account for the last 5 years) and the user is willing to wait. Other operations might not be so slow, or the user might prefer to fail/abort/skip them if they are too slow. I would think it's better to give them the option: maybe set a "global" default when they first create the client object, and allow them to override with an optional parameter, as in your example.

  • 1
    These are very good points. Even a quick and simple method like Put() might take might take a very long time in instances where they have a large payload and a slow upload speed. They'd need be able to extend the timeouts for just these calls and the library would feel badly designed without the ability to add that parameter as part of the function call. – Alain Dec 6 '13 at 21:00
2

I would hate to have only a global static setting because then you can have but a single timeout setting in an app and there might be times where you want to make that highly variable throughout the app. This is one reason I tend to prefer to avoid static API client implementations in favor if instance-based implementations.

One way to handle this would be to add a little fluent configuration. So your consumers can insert something. IE you could do:

var r = ClientAPI.WithTimeout(30).GetResource()

And have pretty decent semantics without cluttering every method call with a bunch of optional parameters.

  • I think this way is less convenient for the user of the library, but more convenient for its developer. But when developing a library, you should focus more on users' needs, I think. – svick Dec 6 '13 at 21:02
  • +1 This is a really neat idea. Unfortunately, my ClientAPI is a static class of extension methods (it's non-instantiable itself) so this syntax could never work. They'd have to do something like myMetaData.WithTimeout(30).Put(), which seems awkward since it's the Put method that is to be modified with a timeout, not the MetaData object. – Alain Dec 6 '13 at 21:03
  • @svick -- I'm not so sure. Or at least this developer rather enjoys fluent interfaces. – Wyatt Barnett Dec 7 '13 at 3:21
  • @Alain -- you could call it ExecutePut() and the semantics work. – Wyatt Barnett Dec 7 '13 at 3:23
1

Well, if you insist on managing the timeout functionality for your API, I think the static setting makes the most sense.

But, personally, I feel like the better thing to do is allow the users of you API determine the best way to handle timeouts. You have no way of knowing how many different ways users will want to define how timeouts should be handled. Same with caching, for example. API consumers should be responsible for that kind of thing.

Take the load off your shoulders and move on to your next feature. :)

  • +1, Unfortunately, the client-api I provide is meant to abstract away the nitty gritty low level tasks of making HTTP REST requests, parsing JSON, etc, so if the user has any chance of controlling certain pieces of low level behavior (like timeouts), I have to expose that through my API. I'm just trying to avoid minor configuration options dominating all my function signatures. – Alain Dec 6 '13 at 21:06
0

I would suggest having your wrapper class be non-static, with timeout being implemented as an instance field. That's how, for example, HttpClient.TimeOut works. Users can create a static instance of the service class if they wish. If needed for backwards compatibility, it would be easy for you to create a static class which behaves identically to the current class (i.e., the static class would have a static instance of your new class, and would call into it for everything).

This approach has numerous advantages:
1. Avoids polluting the method signature.
2. Makes testing and dependency injection easier.
3. Reduces coupling.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.