REST APIs for the health-tech space: How to build your API

Alex Venetidis
Terra
Published in
9 min readMar 31, 2023

tl; dr

  • Use OAuth2 or other secure authentication mechanisms to protect user data.
  • Design clear and consistent naming conventions for endpoints and URL paths using appropriate HTTP methods.
  • Use query parameters for filtering
  • Implement versioning to avoid breaking changes for existing users.
  • Provide endpoints for accessing historical data for metrics such as heart rate, HRV, and sleep.
  • Implement webhooks to provide a more efficient and scalable method of accessing data by notifying third-party applications of updates rather than requiring them to poll for new information constantly.

Intro

Fitness and wearable technology have become increasingly popular in recent years, with more and more people using devices to track their health and fitness metrics.

To allow third-party developers to access this data, many companies have created REST APIs that provide access to users’ historical data and real-time updates through webhooks.

In this article, we will discuss the best practices for designing REST APIs for health and wearable companies, focusing on authentication, REST endpoints, and webhooks.

🔓 Authentication

Authentication is crucial to any REST API, especially regarding sensitive user data like health and fitness metrics. 💪 As mentioned, OAuth2 is the preferred authentication method for fitness and wearable APIs.

Example of an OAuth2 flow:

  1. The user initiates the authentication flow by clicking the “Login with [Service Name]” button in the third-party app.
  2. The app redirects the user to the OAuth2 authorization server of the service, along with some parameters that specify the app’s client ID, the desired scope of access (e.g. read-only access to heart rate data), and a redirect URI that the server will use to redirect the user back to the app once the authentication flow is complete.
  3. The authorization server prompts the user to log in, and then asks them to grant the app access to the requested scope of data.
  4. If the user grants access, the authorization server generates an access token and sends it back to the app at the specified redirect URI.
  5. The app can then use this access token to authenticate requests to the API, by including it in the Authorization header of each request.

Note that OAuth2 also supports refresh tokens, which can be used to obtain a new access token once the old one expires. This helps ensure that even fi the access token gets compromised, it can be refreshed, blocking the potential attacker from getting further data.

Example of an oauth1 flow:

  1. The third-party app sends a request to the OAuth1 provider (i.e., the API provider) for a request token.
  2. The OAuth1 provider responds with a request token and secret. The request token is a temporary token used in the next steps of the authentication process.
  3. The user is then redirected to the OAuth1 provider’s login page to enter their credentials, with the request token in the query parameters of the request. The user logs in with their credentials and authorizes the third-party app to access their data.
  4. Once the user has logged in, they are redirected back to the third-party app’s callback URL, along with the request token. The request token is included in the URL as a query parameter.
  5. The third-party app sends a signed request to the OAuth1 provider to exchange the request token for an access token. The OAuth1 provider verifies the signature and exchanges the request token for an access token and access token secret.
  6. The OAuth1 provider responds with an access token and secret. The access token is a long-lived token that can be used to make authorized API requests on behalf of the user. The secret is a shared secret used to verify the authenticity of subsequent requests.
  7. The third-party app can now use the access token to make authorized API requests on behalf of the user. Each API request must include the access token and a signature generated using the app’s API secret and the access token secret.

The API provider can then verify the signature and check that the access token is valid and authorized to access the requested data.

It’s worth noting that the specifics of the OAuth1 flow can vary depending on the implementation. Additionally, OAuth1 can be much more complex to implement than other authentication methods, such as OAuth2, as evidenced in the steps above.

Example of a username & password flow:

  1. The third-party app sends a request to the API that includes the user’s username and password for the fitness data provider’ app.
  2. The API checks the username and password against its user database to verify that they are correct. If the credentials are correct, the API generates an authentication token, and optionally a refresh token, and sends it back to the user in the response.
  3. The third-party app then includes the authentication token in subsequent requests to the API to retrieve data for a given user.
  4. If the access token expires, the refresh token can be used to generate a new access token

It’s worth noting that username and password-based authentication mechanisms have some drawbacks compared to other authentication methods. For example, passwords can be easily compromised if they are not stored securely, and users may reuse passwords across multiple services.

Additionally, transmitting passwords over the network can be risky if the connection is not secure. As a result, many APIs and web services are moving towards more secure authentication methods, such as OAuth2.

Authentication: Conclusion

As outlined above, oauth2 provides a good compromise between security & ease of implementation for Fitness data providers to allow third-party apps access to their data

REST endpoints for querying historical data

Once authentication is in place, the next step is to define REST endpoints for querying historical data. These endpoints should be designed to be easy to understand and use, with clear documentation and examples.

Advice when designing a REST API structure

1. Use clear and consistent naming conventions for your endpoints and URL paths.

  • It’s important to use clear, descriptive names for your endpoints and URL paths that accurately reflect the type of data being returned. Avoid using abbreviations or acronyms that may be unclear or confusing to users. Additionally, be consistent in your naming conventions throughout your API to make it easy for developers to understand and navigate.

2. Use HTTP methods appropriately.

  • The HTTP method you choose should match the type of action being performed on the resource. For example, use GET to retrieve data, POST to create new data, PUT to update existing data, and DELETE to delete data.

3. Use query parameters for filtering and pagination.

  • Query parameters allow developers to filter and paginate results, making retrieving specific subsets of data easier. Use clear and descriptive parameter names and provide documentation on how to use them.

4. Avoid using body parameters for GET requests.

  • While it’s technically possible to include parameters in the request body for GET requests, this is generally discouraged because it can make it harder for developers to understand and use your API.

5. Use versioning to avoid breaking changes.

  • As your API evolves over time, it’s important to version your endpoints to avoid breaking changes for existing users. Include a version number in your URL path to indicate which version of the API the user is accessing.

When designing endpoints for accessing specific metrics, consider organizing the URL path in a way that makes sense for the returned data. For example, if you have separate endpoints for heart rate, HRV, and sleep data, you might structure your URL paths like this:

  • /v1/users/{user_id}/heart_rate
  • /v1/users/{user_id}/hrv
  • /v1/users/{user_id}/sleep

Alternatively, you could use query parameters to retrieve data for specific metrics within a single endpoint:

  • /v1/users/{user_id}/data?metric=heart_rate
  • /v1/users/{user_id}/data?metric=hrv
  • /v1/users/{user_id}/data?metric=sleep

Ultimately, the key is to choose an approach that is consistent, easy to understand, and meets the needs of your users. Keep in mind each fitness API provider has different data provided, and structuring it should make sense in the context of the metrics available, and the overarching goal of what information you want to provide third-party apps with.

To get a better idea for what querying heart rate could look like for a specific user, here’s a more detailed example of a GET request achieving that:

GET /api/v1/users/{user_id}/heart_rate?start_date={start_date}&end_date={end_date} HTTP/1.1
Host: api.example.com
Authorization: Bearer <access_token>

In this example, the {user_id} parameter would be replaced with the unique ID of the user whose heart rate data is being queried. The start_date and end_date parameters would be replaced with the desired date range for the query. Note that the access token obtained through OAuth2 is included in the Authorization header of the request, to ensure that only authorized users can access the data.

The API might respond with a JSON object that looks something like this:

{
"data": [
{
"timestamp": "2022-03-29T12:34:56+01:00",
"value": 75
},
{
"timestamp": "2022-03-30T12:34:56+01:00",
"value": 80
},
{
"timestamp": "2022-03-31T12:34:56+01:00",
"value": 82
}
]
}

This response would include an array of heart rate measurements for the specified user and date range, along with a timestamp for each measurement. It is ideal to provide time zone information where possible in the API response. This can be done in ISO8601 format, as shown above, or timestamps can be timezone-naive, with the timezon for the payload being provided as an offset in seconds.

NOTE: Timezones

Keep in mind providing timezone information for each metric recording is crucial. Many APIs out there forego this, and only provide the user’s currently set time zone information. This makes it incredibly difficult for developers to accurately use historical data recorded in the past, as they have no knowledge of when exactly the metric was recorded.

Implementation of webhooks

Webhooks are a way for the API to send real-time updates to third-party apps when new data becomes available. To implement webhooks, the API should define a callback URL that the app can use to receive updates. Here’s an example of how this might work, for the example used previously of heart rate data:

  1. The app registers a callback/webhook URL with the API, by setting this as a setting in the API’s developer portal. Alternatively, a POST request that includes the URL as a parameter, and uses a client ID & client Secret for authentication would also work, if the API does not provide a management dashboard.
  2. Whenever new heart rate data becomes available for the user, the API sends a POST request to the registered callback URL, along with a JSON payload that includes the new data.
  3. The app receives the POST request and processes the new data in real-time.

Here’s an example of what the JSON payload might look like:

{
"event": "new_heart_rate_measurement",
"user_id": "12345",
"data": {
"timestamp": "2022-04-01T12:34:56Z",
"value": 85
}
}

In this example, the API sends a POST request to the registered callback URL whenever a new heart rate measurement becomes available for the user with ID “12345”. The JSON payload includes an event field that indicates the type of update being sent, a user_id field that identifies the user whose data has been updated, and a data field that includes the new heart rate measurement itself.

When the app receives this POST request, it can then process the new data in real-time. For example, it might update a dashboard that displays the user’s heart rate over time, or trigger an alert if the heart rate exceeds a certain threshold.

Overall, webhooks provide a more efficient and scalable way to receive real-time updates than polling for new data regularly. The API can ensure that third-party apps are always up-to-date with the latest user data by implementing webhooks.

Conclusion

In conclusion, when designing a REST API for fitness and wearable data, it’s important to prioritize user security, scalability, and ease of use. To achieve these goals, it’s essential to consider the following best practices:

  • Use OAuth2 or other secure authentication mechanisms to protect user data.
  • Design clear and consistent naming conventions for endpoints and URL paths, using appropriate HTTP methods.
  • Use query parameters for filtering and pagination, and avoid using body parameters for GET requests.
  • Implement versioning to avoid breaking changes for existing users.
  • Implement webhooks, which provide a more efficient and scalable method of accessing data by notifying third-party applications of updates, rather than requiring them to poll for new information constantly.

In addition to these best practices, it’s also crucial to consider the unique needs of fitness and wearable data. This includes providing endpoints for accessing historical data for metrics such as heart rate, HRV, and sleep and the heavy use of webhooks.

By following these best practices and implementing webhooks, you can create a REST API that offers secure, efficient and user-friendly access to fitness and wearable data.

--

--