Child pages
  • APIs dos and don'ts

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

API dos and don'ts 

This page describes some common errors and mistakes when working with APIs.

Table of Contents

Dos

Create AbstractYourProjectAPIImpl. 

Create AbstractYourProjectAPIImpl. Always. There were not project yet, where a common abstract api implementation wasn't needed. And that common abstract api implementation should extends the one that we already have:

Code Block
public AbstractFooAPIImpl extends AbstractAPIImpl{

 

Don'ts

Don't create exception types for each api. 

At least don't let them extend Exception if you do. Why? Because having incompatible exception types will force one api, that uses another api to catch that api's exceptions, and re-throw them. This will leave to a lot of boilerplate code. Since API is generally syndication of services, it doesn't matter which API through an Exception. Example: 

Consider we have 2 APIs, which depend on each other. 

Code Block
public MessagingAPI extends API{
  MessageAO getMessage(MessageId id) throws MessagingAPIException;


public UserAPI extends API{
  UserAO getUser(UserId id) throws UserAPIException;


and the MessageAO like that:

Code Block
public class MessageAO{
  private UserAO sender;
  private UserAO recipient;
  private String headline;
  private String message;

now to synthesize this MessageAO the MessagingAPI would perform something like this. 

Code Block
try{
	Message message = messagingService.getMessage(...);
    message.setSender(userAPI.getUser(message.getSenderId());
    message.setRecipient(userAPI.getUser(message.getRecipientId());
}catch(MessagingServiceException e){
  throw new MessagingAPIException("Can't get message...");
}catch(UserAPIException e){
  throw new MessagingAPIException("Can't get user");
}

Obviously the second catch block is obsolete. If both APIs would declare to throw APIException, than it would be easy to throw the Exception through. 

Another advantage of declaring all exceptions as APIException is that than a general type of Exceptions can be used, like:

Code Block
public class BackendFailureException extends APIException{
  public BackendFailureException(Exception cause){
     super("Error in backend, can't continue", cause);
  }
}

This would allow you to handle all backend errors, which you can't handle anyway, at once place. 

Of course, you can still have MessagingAPIException, and you can still use it, and even catch it, but not having it in the throws clause helps a lot. 

So the proper way to do it would be:

Code Block
public MessagingAPI extends API{
  MessageAO getMessage(MessageId id) throws APIException, MessagingAPIException, MessageNotFoundException;


public UserAPI extends API{
  UserAO getUser(UserId id) throws APIException;

but:
 
public MessageAO getMessage(MessageId id) throws APIException{
  ....
  if (something_bad_happens){
     throw new MessagingAPIException(""); 
  }
}