How do I write a shim?
If a shim doesn’t already exist, the following steps will help you get started
- Learn about the custom API you want to write a shim for.
- If you take a look at the Markdown documents for some existing shims, such as RunKeeper or Misfit, you’ll get a good idea of the type of information you’ll need to learn about the custom API.
- Create a similar document for the API you’re working on to use as a reference.
- Your shim will convert some of the source data provided by the custom API into target data that conforms to Open mHealth schemas. Decide which some source data you will map and which schemas you will map it into.
- We recommend mapping all source data that has corresponding schemas.
- Your shim can also produce data that conforms to your own schemas, but your shim will gain wider adoption if it produces data that matches well known schemas.
- Add this information to your document to help you keep track of the measures you will map.
- Implement the mappers. You should use the Misfit shim as a guide on organising and writing mappers.
- The general approach taken in the mappers is to require data necessary to build the data point and treat everything else as optional. This follows the robustness principle.
- If you’re using Java, the mappers use the Open mHealth schema SDK to build objects that correspond to schemas. These objects are then serialized to create the output of the common API. The mappers leverage the following classes.
- JsonNodeMappingSupport: A utility class that makes it easy to extract pieces of typed data from source JSON data. The methods for required data throw exceptions on missing data, whereas those for optional data log missing information and return empty Optionals.
- DataPointMapper: An interface that takes one or more inputs to create data points. The purpose of taking more than one input isn’t to map collections. It’s to create data points that are composed from multiple inputs, such as a blood pressure data point that requires a user profile input to build headers and vital signs to build payloads.
- JsonNodeDataPointMapper: A specialization of DataPointMapper that takes Jackson JsonNode inputs.
- Implement the authentication to the custom API.
- This is typically OAuth 2.0, though sometimes OAuth 1.0a and sometimes a custom implementation entirely. Take a look at the Misfit shim for OAuth 2.0, the Withings shim for OAuth 1.0a, and the HealthVault shim for a custom implementation.
- If you’re using Java and the third-party API uses OAuth 1.0a or OAuth 2.0, extend OAuth1ShimBase or OAuth2ShimBase classes and implement the abstract methods. This lets you leverage common authentication code and tweak parameters based on the nuances of the custom API.
- Implement the data retrieval operation on the common API.
- The data retrieval operation is responsible for calling the custom API to get data. It must propagate the time frame filtering on the common API to the custom API, as well as paging and other parameters. This is a manual process with a case-by-case implementation, grounded on a solid understanding of the custom API.
- If you’re using Java, this retrieval operation is an abstract getData method implemented by each shim.
We are working on making Shimmer expose our Data Point API, which is the API exposed by the data storage component
. This will let an application treat a third-party API as a remote data storage component, with translation happening on the fly. This process is not a simple one, since it requires general and extensible strategies for resolving API mismatches in authentication, pagination, cardinality, filtering, and data formats, at a minimum. We will keep you up-to-date and ask for feedback using our mailing list.
We’re also considering making the shims themselves microservices, to help people create shims in different languages. If you have any feedback on the topic, please let us know on our mailing list.