A software application typically has a lot of dependencies. These dependencies need to be upgraded in order to keep up with the latest features and security patches. This is often difficult to do in a large software application that is constantly changing, so some of these dependencies may end up becoming legacy. One of the most common types of dependencies is an API integration where the software application makes a request to an external service and the external service returns a response. This means that there’s a good chance one of your API integrations will become legacy at some point.
But how exactly do you upgrade a legacy API integration? In this article, I provide a general guideline to help you along the process. This guideline is structured as a series of steps, starting with the following:
Write tests for your legacy API integration
Before beginning the actual upgrade, make sure that your application has automated tests for your legacy API integration. These tests should simulate the API flow by stubbing API calls to send a mock request object and return a mock response object.
If you don’t have any existing tests for your legacy API integration, take the time to write some. Likewise, if your tests make actual API calls, take the time to convert them to use mock data. This ensures that your existing legacy API integration is working as expected and gives you a nice fallback point in case an issue arises in the upgrade process. It also makes the rest of the upgrade process easier since you’ll be writing similar tests for your modern API integration in a future step. Once the tests are complete, we can move on to the second step.
Document request/response mappings between your legacy and modern API integrations
When upgrading from a legacy to a modern API integration, the request and response structures for the two integrations will likely appear very different. In particular, certain field names may have been renamed or removed entirely so it’s best to document these changes before proceeding with the actual upgrade. This is where you want to leverage the online documentation for both your legacy and modern API integrations.
I like to use a spreadsheet that consists of two sheets with the following structure:
- One sheet is named “Request Mappings” and consists of three columns for “Legacy API Field Name,” “Modern API Field Name” and “Notes.” An example of a full request payload is also documented towards the bottom of the sheet.
- A second sheet is named “Response Mappings” and consists of the same three columns for “Legacy API Field Name,” “Modern API Field Name” and “Notes.” An example of a successful response and another example of an error response are documented towards the bottom of the sheet.
This approach makes it easy for others to provide feedback because it organizes the changes by each individual data field while still showing the complete picture. Once you’ve documented all of the changes, we can proceed to the third step.
Implement the modern API integration
Now it’s finally time to implement the logic for your modern API integration! The actual implementation details are specific to your integration but I like to organize them in the following manner:
class MyAPI USE_LEGACY_API = true def call_api if USE_LEGACY_API call_legacy_api else call_modern_api end end private def call_legacy_api # implementation details for legacy api go here … end def call_modern_api # implementation details for modern api go here … end end
I’ve done a few things here:
- I’ve put the implementation details for the legacy and modern APIs into two separate private methods.
- I have a single public method that clients can invoke to trigger a call to the API service.
- There is a USE_LEGACY_API boolean constant that determines whether to invoke the legacy or the modern API integration. Currently, it is set to true so we invoke the legacy API integration.
The USE_LEGACY_API boolean constant lets us switch back and forth between the legacy and modern API integrations. Furthermore, it also makes it easier to write tests for your modern API integration. If you wrote tests for your legacy API integration back in step 1 of this guide, then you can use the same approach to write tests for your modern API integration in this step.
The key takeaway from this step is that we want to implement all of the business logic and tests for the modern API integration but we do not want any clients to invoke it yet. That’s why USE_LEGACY_API is set to true. Now we’re ready to move on to the fourth step.
Enable the modern API integration
Now we’re ready to enable the modern API Integration. This can simply be done by changing the USE_LEGACY_API constant from true to false like so:
class MyAPI USE_LEGACY_API = false def call_api if USE_LEGACY_API call_legacy_api else call_modern_api end end private def call_legacy_api # implementation details for legacy api go here … end def call_modern_api # implementation details for modern api go here … end end
After this, you’ll likely want to test the modern API integration in a staging environment. Once that looks good, you can deploy the change to a production environment and move on to the next step.
Monitor the modern API integration
Now that your modern API Integration is out in production, you’ll want to monitor it to make sure no issues arise. If you do encounter any problems, then it’s best to fix them as soon as possible. If there are too many problems, you also have the option of reverting back to using the legacy API integration by switching the USE_LEGACY_API from false back to true.
If the modern API integration looks like it works successfully, then we can move on to the final step.
Remove your legacy API integration
Once your modern API integration has been running in production without encountering any issues, it’s time to remove your legacy API integration. This includes removing the legacy implementation, corresponding tests and the actual legacy library itself from your application. The final implementation should look similar to the following:
class MyAPI def call_api call_modern_api end private def call_modern_api # implementation details for modern api go here … end end
After all of the legacy pieces are removed, you have finally completed the upgrade process!
Congratulations! Upgrading a legacy API integration is a difficult task so I hope this guide helped you succeed. Even if that wasn’t the case, I hope I was able to put you on the right path.