Never Call an API Directly from Your Code

At some point in your career you are going to need to do something that is not part of the language's framework. Most language frameworks can do many things right out of the box such as writing and reading files, network communications, etc. However there are many things that fall outside the scope of the framework. For example you may need to produce Microsoft Office documents or PDFs or communicate with an external source for information such as getting Stock Exchange information from Yahoo. The possibilities of what you will need are endless.

The point is that you will need to do so eventually. In most cases an API will exist and all you have to do is use that API to implement that functionality.

What's an API?

Let's backup for a moment What is an API? API stands for Application Programming Interface. The name says it all. It really just means that it is a set of components that allows you to access something programmatically. Let's say for example that you want to create Excel documents and rather than you creating that from scratch, a set of libraries exist that you can use programmatically. Many times libraries have APIs for different languages. For example there may an API for Java and one for .Net. 

APIs are really handy because they allow us to focus more on the application and less on communicating with external components. Many times APIs are highly simplified and provide a lot of power with very little effort. Most of the time it is cheaper and more feasible to use an existing API. In some cases the API may be a for fee licensed library and you may be faced with the decision to build or buy. In our case let's assume that our decision was to use a third party library, wether we bought it or got it for free is irrelevant.

An Example of an API

Let's say for example there is an API for Java that allows the creation of Excel documents. There is one or more out there but in the spirit of keeping things simple let's make one up. I don't want to lose focus of our purpose by diving into the details of the Apache POI for example.

Let's say that the API provides a class called XDocument. The XDocument has the following API.
createSheet

The createSheet method returns an object of the type XSheet XSheet has the the method
createRow

CreateRow returns and XRow which then allows creation of XCells and so on. You get the picture. 

So your code for creating a spreadsheet would look something like this. (This code is totally made up on the fly so take it more as pseudocode than actual java code)


import com.someorg.xdocs.*;

public class ExecFinancialReport{
    
    public void createReport(string filePath){
           
           XDocument xDocument = new XDocument(filePath);
           XSheet sheet = xDocument.createSheet();

           for(int i = 0; i < financialRecords.length(); i++){
               FinancialRow row = financialRecords[i]
               XRow row = sheet.createRow();
               row.insertCell(row.getDate());
               row.insertCell(row.getAmount());
           }
    }
}

Let's say that you have a task of creating over 150 reports using this library.  This means that you would need to reference this library from over 150 different files. So 150 files would have very similar code to that snippet above.


Scattered Calls to the API

Now you have 150 files that make a direct reference to that API. The API works perfectly and when you deliver your software everyone is happy because your application produces Excel documents. Everything works great for the next few years. After a few years, the old file format is no longer supported and now you must upgrade to a new version of the API or a totally different API. It turns out that you now have 150 files that you must modify, since the new API is different that the API. All of your import statements must be changed and even worse your algorithm also must be changed for how you use the API. For example everywhere you have

com.someorg.xdocs.*

Must be changed to 



com.someotherorg.ydocs.*

Also, the logic for creating the document must be changed, since the new API works differently than the old one and the individual types are not the same either.

In Retrospect What Could Have Been Done Better?

You could have created your own API in your own package path or namespace (.Net). That way all you would have to do is modify that package. This is a scenario where the adapter pattern makes perfect sense. If instead of relying directly on XDocument you would have relied on MyDocumentInterface (any custom interface you create instead of the third party) you could easily have swapped out concrete implementations with little effort.

Sure it would still take some work to implement a new implementation of MyDocumentInterface but you would only need to modify a few files and you would be done, instead of the 150 files in your application. So instead your code could look like this.
import com.myorg.MyXDcocument;

public class ExecFinancialReport{    
    public MyXDocument myXDocument;    
    public void createReport(string filePath){           
           myXDocument.createDocument(filePath);
           myXDocument.insertSheet();

           for(int i = 0; i < financialRecords.length(); i++){
               FinancialRow row = financialRecords[i];
               myXDocument.createRow();
               myXDocument.insertCell(row.getDate());
               myXDocument.insertCell(row.getAmount());
           }
    }
}

Notice in the code above that we didn't necessarily create a replacement for every component of the API. For instance we hid the concept of XSheet and XRow behind the myXDocument interface. Depending on your situation, you may need to add additional types. I will caution you to stay away from the third party types even as arguments, otherwise you will still be coupled to the third party library. The point however, is that your custom API does not and most times should match the external API identically. Chances are that you only need a subset of the overall functionality of the API. So why bother trying to translate the entire API?

By having the MyXDocument interface in place you can swap out implementations easily. You can do this through inversion of control and IoC containers such as Spring in Java or StructureMap and Unity in the .Net world. Take a look at this article on Dependency Injection if you want to know more about it.

If I can just replace my own API, why can't I replace the Third Party API?

You may be wondering why you can swap out your own implementation but not the original implementation. The problem at least in Java is that there is a high level of coupling in package paths. You can't easily swap out packages. I won't go into details but that would actually take a whole other post for discussion. You may be wondering why I didn't go into concrete details about the adapter pattern or any other pattern for example.

I think there are many examples on exactly how to implement those patterns. Take a look at this explanation if you would like to learn more about the adapter pattern. You may also consider taking a look at the facade pattern (pronounced fah-sahd pattern). The facade pattern is for simplifying a complex API. The point that I want to drive home is to be very cautious when using a library in your system. I'm overly exaggerating when I say to never use a third party library in your code.

What I do mean is that you should minimize the calls to it and create your own adapter. If you are ever faced with the decision that you will use a third party library ask yourself these questions:
Is it referenced by more than a handful of files?
Would it take a large effort to swap it out?
If you answer yes to either of these questions, I would really invest the time to understand the adapter pattern and implement it. The developers that inherit your code will have lots to thank you for.

Comments

Popular posts from this blog

Simple Example of Using Pipes with C#

Putting Files on the Rackspace File Cloud

Why I Hate Regular Expressions