API Design: Design for Easy Configuration
API's often need some kind of configuration before being able to perform its service. A persistence API may need a JDBC driver, database url, user name and password, plus perhaps some object-to-table mappings. A dependency injection container needs instantiation configurations. Etc.
Some of the most common API configuration mechanisms are:
- Method Calls on Components
- JVM Parameters
- Command Line Arguments
- Property Files
- XML Files
- A Domain Specific Language
Which of these configuration mechanisms is most appropriate for your API depends on several factors, like:
- How much configuration is needed?
- Is configuration an implementation choice or deployment choice?
- Is the configuration mechanism easy to learn, easy to use and concise?
- Which limitations does the configuration mechanism have?
I'll try to address each of these questions below. Keep in mind that you'll have to answer these questions from scratch with each new API you are developing. The correct choice for one API may not be the correct choice for another.
How Much Configuration is Needed?
In many cases, the less configuration you need, the closer towards the top of the list of configuration options you may settle. If all that is needed is a boolean flag set to either true or false, perhaps a method call will do.
If, however, the configuration needed is a bit more complex and verbose, for instance hierarchical, then a set of configuration objects or XML might be more appropriate.
Is Configuration an Implementation Choice or Deployment Choice?
Some API configuration choices are implementation specific and some configuration choices are deployment specific. For instance, a URL to a database, or a file path to a file needed by the application may change depending on where the application is deployed. But whether you choose to use an FTP API in active or passive mode may be an implementation issue, not a deployment issue.
Implementation configuration choices are often best to do via code. That way no external configuration files are needed for configurations that are really part of the code.
Deployment configuration parameters must almost always be exernalized from the application code, and separated into configuration files, databases etc. However, even if the client of the API will externalize the configuration of your API, it may still be more appropriate to allow your API to be configured via code. Then the user of your API can externalize these settings in whatever configuration mechanism they deem appropriate for their application.
Is the configuration mechanism easy to learn, easy to use and concise?
If you want your API to be as easy to learn and use, this should also be reflected in the choice of configuration mechanism.
For instance, Spring's configuration mechanism was in the outset XML files. The XML files were rather verbose, and not too easy to read. It was, however, flexible, and allowed the XML files to be used for application configuration as well as wiring up components. In addition most developers know XML, so they didn't have to learn the XML syntax. They only needed to learn the meaning of Spring's XML elements and attributes.
In contrast, for Butterfly DI Container I chose to implement a small domain specific language (DSL) for the configuration of the container. I chose this after having considered XML, annotations and method calls. The DSL (Butterfly Container Script - BCS) is much more concise than Spring's XML, and reads much more like a combination of a property file and Java code. In that respect the DSL is supposedly easier to learn, use and read than Spring's XML. However, it was much harder for me to implement than just using XML. I had to write a parser for the DSL, which was a bit of a challenge. But it was well worth it!
Which Limitations does the Configuration Mechanism Have?
The choice of configuration mechanism may impose undesirable limitations on your configuration possibilities.
I have seen several API's choose Java annotations as configuration mechanism. For instance, a persistence API may allow the user to mark the classes to be persisted with annotations saying which fields should be stored in which columns, and what table objects of this class should be persisted in.
Annotations, however, are class static. This means that it is not possible to have two different configurations of the same class. You can have only one. This is a serious limitation of annotations.
Similarly, ordinary property files may also impose some kind of limitations on your configuration options. For instance, it will be hard to configure hierarchical settings. For this purpose an XML file would be much more suitable.