I often get involved in discussions concerning the design of Web Service APIs. Invariably people get hung up on the implementation technology, WSDL, SOAP etc and loose sight of the underlying issues. Most people’s initial stab at a Web Service API is to think “oh, it’s like an local API call but with slower response times”. Well almost, but there is more to it than this.
Below I have identified five areas in which the design of local and remote APIs differ. I think these are useful when thinking about Web Services, what do you think? In addition I believe they can be reused in the future when Service Orientation becomes passé and is rebranded into something like Super Lightening Integration Metaphor (SLIM) or whatever …
API Consideration Areas
1. Calling Semantic
Call by value. Parameters and return values adopt a pass by value semantics (e.g. objects are serializable)
Both call by value and reference can be supported. The later may be desirable for performance purposes and is usually desirable for local APIs.
2. Function Granularity
Due to the communication overhead (principally latency) the API has to be designed so that the number of interactions/invocations is minimised. Typically this encourages a coarse grained API. This is also consistent with the calling semantics above.
Tens to Hundreds of invocations per second are possible. Beware if you are porting an application that used a local API previously.
Since calling is local, there is a minimal communication and invocation overhead. Millions of invocations per second are possible.
3. Security Issues
- Authentication – is the caller who they say they are (how do we prevent client identity being spoofed)
- Encryption – is some of the data being exchanged in each function invocation sensitive? The information may be transported via an untrusted channel. Plain text passwords are an obvious example, but there may be commercially sensitive information that also should not be passed in the clear.
With local invocation it isn’t usually necessary to worry about these issues.
4. Recovery Semantics
The API must be designed to support recovery following communication failure or the loss of messages. This applies to both function invocation and response.
Think of a simple banking application which has a ‘Debit Bank Account Transaction’ as an example here we wish to debit £10 from a customer account we need to ensure that the transaction or function call is executed once. Technically this is called idempotency.
The message used for the invocation of the function may get lost, or the invocation message may be received successful but the return response message gets lost on the way back.
There are two strategies for dealing with this;
- the use of a token for each unique invocation. The recipient can check to see if the request has been processed previously. See Synchronizer Token pattern (http://www.refactoring.com/catalog/introduceSynchronizerToken.html)
- the provision of a ‘query’ function. If the caller is unsure that function has been executed a request can be made to determine the state.
A local API doesn’t need to worry about these issues as communication is typically within a machine/server.
5. API State
To support scalability and recovery typically the API is designed to be stateless. The provider of the API is not in contact directly with the caller. The caller may crash without the provider realising. For stateful APIs there are recovery strategies, but typically these revolve around the use of timeouts which increase the complexity of the API implementation and use of more resources (as these need to be kept until the timeout has expired).
With local invocation, and typically as a result of adopting call by reference semantics, a stateful API can be implemented and is often desirable for performance reasons.