Application programming interfaces (APIs) enable computer systems to communicate with each other in shared format. API is a generic term to describe these communication protocols.
We deal with a lot of APIs. They come in all shapes and sizes, from fully restful systems to RPC style interfaces and everything in between; most are a mixture of the two. Some are complicated and some are simple. API documentation ranges from one page to several hundred, depending on the provider. Some require domain expertise before attempting to understand their contents, and others are simple enough you can write code for them in under an hour.
Software to car API comparison
For some reason I like to use car analogies. They seem to be relatable to most people, at least here in the Detroit area. We'll compare software APIs to their mechanical equivalent found in cars to better understand where APIs can be found and what their functions may be. Also, like cars, APIs require ongoing maintenance costs.
If we think about APIs in terms of a car, there are many layers that exist between the driver and the wheels on the road. The steering wheel and gas pedal are a generic interface that is common to all cars. As a driver, these functions are self-explanatory. You can get in a new (to you) car and can be on your way in short order. There are many small features that may differ from car to car, such as the placement of the turn signal or radio controls, but in general they are all similar. It doesn't take long to get adjusted to a new car's systems, thanks to these generic interfaces.
Beyond the steering wheel, there are several more car "APIs", each more specific and manufacturer centric than the general use-case of the human to car interface, the steering wheel. Some cars have mechanical gas pedals and others employ a digital solution. This is an implementation detail specific to the manufacturer, although still somewhat standard between the two options. The same theory applies in software, where there are several layers of interfaces between the user and the application, the application and the data, and the data and the storage technology.
The deeper we dive from the gas pedal to the engine and then to the drive-train, the more specific each level of interface becomes. Each level goes from a more generalized function, such a increasing the speed, to more specific function, such as changing the fuel to air ratio to affect a speed change. Each time we go one level deeper to a more specific function, it becomes harder to keep that function general enough to accommodate other use-cases. In the engine to car interface, that makes replacing a Ford engine with one from a Chevy rather hard. It can be done (maybe), but the time and effort involved would likely not outweigh the benefits. Just because you can, doesn't mean you should.
General and specific design
Software is constructed in layers. There is a visible layer, which may be the public API or user-interface, and there is an internal layer, hidden from the outside. The internal layer is often composed of several other layers, each at varying levels of specificity. It's important to design the internal and external APIs for the use-case that's appropriate for its level. This requires a balance between general and specific functionality. An often overlooked side effect of designing a general interface is loss of specificity.
Software is a series of tradeoffs. If we design an interface that is too general, we lose the ability to be specific. In this case there is loss of fine-grain detail. For simple applications, that may be acceptable. However, if we design an interface that is too specific, we generate many functions and data constructs that become hard to navigate for anyone outside of the original designers. Finding the balance can be tough and depends on the end goal of the design.
Each layer should strive for high cohesion and low coupling. Cohesion is the grouping of related functions and coupling is their interdependence on each other. In other words, the layer's functions should be grouped together based on a single related task and those functions should not depend on other, unrelated functions or data. This directly affects the software maintainability in the future. The ability to respond to changing software demands is directly related how easily the code can be changed.
Third-party integrations
Third-party integrations are ripe for these types of challenges. Especially third-party integrations with multiple providers of the same service type. Bill pay providers are a great example. Each bill pay provider allows an end-user to input bills and send payments. However, each provider has functionality that is specific to their offerings. As a third-party integrator, if we decide to only include common bill pay functions that all providers offer, we lose the specific features of each individual provider. From a design aspect, it is much easier to create a general API for our applications, but that limits the end-user's options. We choose the options that provide the most value to the end-user, which is a specific API and user interface for each third-party provider.
Cost verses business value
Software must deliver business value, otherwise it's wasted effort. Business value is the main driver of the software development process. APIs are great for integrating external data into your applications but there is a hidden cost: maintenance. Most people only evaluate the initial development cost and forego considering the ongoing cost of maintaining the integration. The cost in development time and resources for maintenance can eclipse the initial resource investment, depending on how deeply intertwined your application is to the API. Be aware of the total cost of ownership and not just the initial down payment when considering API integrations. There are less resource intensive options available, sometimes.