cms-bluebutton-sdk 1.0.5
An SDK used for interacting with the CMS Blue Button 2.0 API
Requires Python: >=3.9

Python SDK for Blue Button 2.0 API
=====================================================

## Project Description
This Python software development kit (SDK) provides tools and resources for developers integrating with the [CMS Blue Button 2.0 (BB2.0) API](https://bluebutton.cms.gov/developers/).

## About the Project
The [Blue Button 2.0 API](https://bluebutton.cms.gov/) provides Medicare enrollee claims data to applications using the [OAuth2.0 authorization flow](https://datatracker.ietf.org/doc/html/rfc6749). We aim to provide a developer-friendly, standards-based API that enables people with Medicare to connect their claims data to the applications, services, and research programs they trust.

## Project Vision
The Python SDK helps third-party partners to develop applications that integrate with BlueButton using Python

<!-- ## Project Mission -->

## Agency Mission
The Centers for Medicare & Medicaid Services (CMS) is working to enable Medicare beneficiaries to securely share their health data with applications of their choice through standards-based APIs.

<!-- ## Team Mission -->

## Core Team
A list of core team members responsible for the code and documentation in this repository can be found in [COMMUNITY.md](COMMUNITY.md).

## Documentation Index:
- `README.md` - This file, containing setup and usage instructions
- `CONTRIBUTING.md` - Guidelines for contributing to the project
- `COMMUNITY.md` - Community guidelines and code of conduct
- `SECURITY.md` - Security and vulnerability disclosure policies
- `LICENSE` - Creative Commons Zero v1.0 Universal

### Table of Contents

- [Local Development](#local-dev)
- [Setup](#setup)
- [Installation](#installation)
- [Configuration Parameters](#configuration-parameters)
- [Configuration Methods](#configuration-methods)
- [Usage](#usage)
- [Sample App](#sample-app)
- [About](#about)
- [Policies](#policies)
- [Public Domain](#public-domain)
- [Security](#security)
- [Feedback](#feedback)

# Local Development<a id="local-dev"></a>

## Repository Structure
```
├── cms_bluebutton
│   ├── tests
│       ├── fixtures
│       ├── test_configs
```

## Setup <a name="setup"></a>

You'll need a sandbox account and sample access token to access data from the Blue Button 2.0 API.

To learn how to create a sandbox account and generate a sample access token, see **[Getting started in the developer sandbox](https://bluebutton.cms.gov/developers/#getting-started-in-the-developer-sandbox)**.


## Installation<a id="installation"></a>

```bash
pip install cms-bluebutton-sdk
```

## Configuration Parameters<a id="configuration-parameters"></a>

Required SDK configuration parameters include:

| Parameter     | Value                           | Default |Description                                |
| ------------- | ------------------------------- |----| --------------------------------------- |
| `environment` | `SANDBOX` or `PRODUCTION`     |`SANDBOX` | Blue Button 2.0 API environment |
| `version`       | `1` or `2`                        | `2`  | Blue Button 2.0 version            |
| `client_id`    | *`your_client_id`*                          | |OAuth2.0 client ID of your app             |
| `client_secret` | *`your_client_secret`*                           | |OAuth2.0 client secret of your app         |
| `callback_url`  | *`https://www.example.com/callback`* | |OAuth2.0 callback URL of your app          |


### Access Token Refresh on Expire
SDK FHIR requests check whether the access token is expired before the data endpoint call. By default, an expired token will refresh. To disable token refresh, set `token_refresh_on_expire` to `false`.

**Note:** If an application’s authorization for accessing user data has expired, the corresponding access token will not be able to be refreshed; see [here](https://bluebutton.cms.gov/developers/#expired-data-access-grant) for more details.

### FHIR Requests Retry Settings

Retry is enabled by default for FHIR requests. The folllowing parameters are available for the exponential back off retry algorithm.

| Retry parameter   | Value (default)      | Description                         |
| ----------------- | -------------------- | -------------------------------- |
| `backoff_factor`    | `5`                    | Backoff factor in seconds       |
| `total `            | `3`                    | Max retries                      |
| `status_forcelist`  | [`500`, `502`, `503`, `504`] | Error response codes to retry on |

The exponential backoff factor (in seconds) is used to calculate interval between retries using the formula `backoff_factor * (2 ** (i - 1))` where `i` starts from 0.

Example:

A `backoff_factor` of 5 seconds generates the wait intervals: 2.5, 5, 10, ...

To disable the retry, set `total = 0`

### Environments and Data

The Blue Button 2.0 API is available in V1 and V2 in a sandbox and production environment.

- Sandbox location: https://sandbox.bluebutton.cms.gov
- Production location: https://api.bluebutton.cms.gov

Version data formats:

- V1: FHIR STU3
- V2: FHIR R4

Sample configuration JSON with default version and environment:

```
{
  "client_id": "your_client_id",
  "client_secret": "your_client_secret",
  "callback_url": "https://www.example.com/",
}

```

If needed, you can set your application's target environment and API version.

Example:

```
{
  "client_id": "your_client_id",
  "client_secret": "your_client_secret",
  "callback_url": "https://www.example.com/",
  "version": "2",
  "environment": "PRODUCTION"
}

```

## Configuration Methods<a id="configuration-methods"></a>
There are three ways to configure the SDK when instantiating a `BlueButton` class instance.

### Python Dictionary
    - A dictionary of configuration key:value pairs can be used.
    - Configuration values can be provided from your own application's configuration method.
    - Example code:
      ```python
      bb = BlueButton({
               "environment": "PRODUCTION",
               "client_id": "your_client_id",
               "client_secret": "your_client_secret",
               "callback_url": "https://www.example.com/callback",
               "version": 2,
               "retry_settings": {
                   "total": 3,
                   "backoff_factor": 5,
                   "status_forcelist": [500, 502, 503, 504]
               }
            })
      ```
### JSON config file
    - This is using a configuration file that is in a JSON format.
    - This is stored in a local file.
    - The default location is in the current working directory with a file name: .bluebutton-config.json
    - Example code:
      ```python
      bb = BlueButton("settings/my_bb2_sdk_conf.json")
      ```
    - Example JSON in file:
      ```json
      {
          "environment": "SANDBOX",
          "client_id": "your_client_id",
          "client_secret": "your_client_secret",
          "callback_url": "https://www.example.com/callback",
          "version": 2,
          "retry_settings": {
              "total": 3,
              "backoff_factor": 5,
              "status_forcelist": [500, 502, 503, 504]
          }
      }
      ```

### YAML config file
    - This is using a configuration file that is in a YAML format.
    - This is stored in a local file.
    - The default location is in the current working directory with a file name: .bluebutton-config.yaml
    - Example code:
      ```python
      bb = BlueButton("settings/my_bb2_sdk_conf.yaml")
      ```
    - Example YAML in file:
      ```yaml
      environment: "SANDBOX"
      client_id: "id"
      client_secret: "your_client_secret"
      callback_url: "https://www.example.com/callback"
      version: 2
      ```

## Sample Usage: Obtain Access Grant, Probe Scope, and Access Data<a id="usage"></a>

Below are code snippets showing the SDK used with Python server and Flask. This code walks through:

- Obtaining an access token with scope ([Scopes](https://bluebutton.cms.gov/developers/#scopes)) chosen by a user
- Passing the token to query for FHIR data
- Using URL links from the response to page through data
- Using the SDK paging support to return all data in one call

```python
from flask import Flask
from flask import redirect, request
from cms_bluebutton import BlueButton, AuthorizationToken

# initialize the app
app = Flask(__name__)

# Instantiate SDK class instance via conf in file
bb = BlueButton()

# auth_data is saved for the current user
auth_data = bb.generate_auth_data()

"""
AuthorizationToken holds access grant info:
  access token, expire in, expire at, token type, scope, refreh token, etc.
It is associated with current logged in user in real app.
Check SDK python docs for more details.
"""

auth_token = None

# Start authorize flow: Response with URL to redirect to Medicare.gov beneficiary login
@app.route("/", methods=["GET"])
def get_auth_url():
    return bb.generate_authorize_url(auth_data)


@app.route('/api/bluebutton/callback/', methods=['GET'])
def authorization_callback():
    request_query = request.args
    code = request_query.get('code')
    state = request_query.get('state')

    auth_token = bb.get_authorization_token(auth_data, code, state)

    """
    Now access token obtained.

    Note: During authorization, the beneficiary can grant
    access to their demographic data and claims data or only claims data.

    Check the scope
    of the current access token as shown below:
    """
    scopes = auth_token.scope

    # iterate scope entries here or check if a permission is in the scope
    if "patient/Patient.r" in scopes or "patient/Patient.rs" in scopes: 
        # patient read access granted, similarly can check:
        # "patient/Patient.s", or "patient/Patient.rs"

    """
    1. access token scope where demographic info included:
    
    scope: [
        "profile",
        "openid",
        "patient/Patient.r",
        "patient/Patient.s",
        "patient/Patient.rs",
        "patient/ExplanationOfBenefit.r",
        "patient/ExplanationOfBenefit.s",
        "patient/ExplanationOfBenefit.rs",
        "patient/Coverage.r",
        "patient/Coverage.s",
        "patient/Coverage.rs",
        "launch/patient",
    ]
    
    2. access token scope where demographic info (profile patient/Patient.r patient/Patient.s patient/Patient.rs) not included:
    
    scope: [
        "openid",
        "patient/ExplanationOfBenefit.r",
        "patient/ExplanationOfBenefit.s",
        "patient/ExplanationOfBenefit.rs",
        "patient/Coverage.r",
        "patient/Coverage.s",
        "patient/Coverage.rs",
        "launch/patient",
    ]
    """
    config = {
        "auth_token": auth_token,
        "params": {},
        "url": "to be overriden"
    }

    result = {}

    # fetch eob, patient, coverage, profile
    try:
        eob_data = bb.get_explaination_of_benefit_data(config)
        result['eob_data'] = eob_data['response'].json()
        eob_data = eob_data['response'].json()
        result['eob_data'] = eob_data

        # A FHIR search response can result in a large number of resources. 
        # For example, an EOB search of a beneficiary could return hundreds 
        # of resources. By default, search results are grouped into
        # pages with 10 resources each. For example, 
        # bb.get_explaination_of_benefit_data(config) returns the
        # first page of resources as a FHIR bundle with a link section 
        # of page navigation URLs. Pagination link names include 
        # 'first,' 'last,' 'self,' next,' and 'previous.' 
        # To get all the pages, use bb.get_pages(data, config).
        
        eob_pages = bb.get_pages(eob_data, config)
        result['eob_pages'] = eob_pages['pages']
        auth_token = eob_pages['auth_token']

        pt_data = bb.get_patient_data(config)
        result['patient_data'] = pt_data['response'].json()

        coverage_data = bb.get_coverage_data(config)
        result['coverage_data'] = coverage_data['response'].json()

        profile_data = bb.get_profile_data(config)
        result['profile_data'] = profile_data['response'].json()
    except Exception as ex:
        print(ex)

    return result


if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=3001)
```

## Sample App<a id="sample-app"></a>

For a complete Python React sample app, see [CMS Blue Button Python Sample App](https://github.com/CMSgov/bluebutton-sample-client-python-react).

# Policies <a name="policies"></a>

## Development and Software Delivery Lifecycle

The following guide is for members of the project team who have access to the repository as well as code contributors. The main difference between internal and external contributions is that external contributors will need to fork the project and will not be able to merge their own pull requests. For more information on contributing, see: [CONTRIBUTING.md](./CONTRIBUTING.md).

## Contributing

Thank you for considering contributing to an Open Source project of the US Government! For more information about our contribution guidelines, see [CONTRIBUTING.md](CONTRIBUTING.md).

## Branching Model

This project follows standard GitHub flow practices:

* Make changes in feature branches and merge to `main` frequently
* Pull-requests are reviewed before merging
* Tests should be written for changes introduced
* Each change should be deployable to production

## Governance
For more information about our governance, see [GOVERNANCE.md](GOVERNANCE.md).

## Public Domain <a name="public-domain"></a>
This project is in the public domain within the United States, and copyright and related rights in the work worldwide are waived through the [CC0 1.0 Universal public domain dedication](https://creativecommons.org/publicdomain/zero/1.0/) as indicated in [LICENSE](LICENSE).

All contributions to this project will be released under the CC0 dedication. By submitting a pull request or issue, you are agreeing to comply with this waiver of copyright interest.

## Security<a id="security"></a>
We do our best to keep our SDKs up to date with vulnerability patching and security testing, but you are responsible for your own review and testing before implementation.

To report vulnerabilities, please see the [CMS Vulnerability Disclosure Policy](https://www.cms.gov/vulnerability-disclosure-policy) and follow the directions for reporting. 


## Feedback<a id="feedback"></a>
Got questions? Need help troubleshooting? Want to propose a new feature? Contact the Blue Button 2.0 team and connect with the community in our [Google Group](https://groups.google.com/forum/#!forum/Developer-group-for-cms-blue-button-api).