Repository: Clinical-Genomics/patientMatcher

Issue:
patientMatcher MUST have a heartbeat
I completely missed this: https://github.com/ga4gh/mme-apis/blob/master/heartbeat-api.md

Good thing it's easy to implement!

Discussion:

Patch:
diff --git a/patientMatcher/server/controllers.py b/patientMatcher/server/controllers.py
index ac9ff04..30bb61a 100644
--- a/patientMatcher/server/controllers.py
+++ b/patientMatcher/server/controllers.py
@@ -9,9 +9,24 @@ from patientMatcher.utils.patient import patients
 from patientMatcher.parse.patient import json_patient, validate_api, mme_patient
 from patientMatcher.auth.auth import authorize
 from patientMatcher.match.handler import external_matcher
+from patientMatcher.__version__ import __version__
 
 LOG = logging.getLogger(__name__)
 
+def heartbeat(disclaimer):
+    """Return a heartbeat as defined here:https://github.com/ga4gh/mme-apis/blob/master/heartbeat-api.md"""
+
+    hbeat = {
+        "heartbeat": {
+            "production": True,
+            "version": __version__,
+            "accept": ["application/vnd.ga4gh.matchmaker.v1.0+json", "application/vnd.ga4gh.matchmaker.v1.1+json"]
+        },
+        "disclaimer": disclaimer,
+    }
+    return hbeat
+
+
 def metrics(database):
     """return database metrics"""
     db_metrics = general_metrics(database)
diff --git a/patientMatcher/server/views.py b/patientMatcher/server/views.py
index a14b73a..b5e96a1 100644
--- a/patientMatcher/server/views.py
+++ b/patientMatcher/server/views.py
@@ -69,6 +69,24 @@ def delete(patient_id):
     return resp
 
 
+@blueprint.route('/heartbeat', methods=['GET'])
+def heartbeat():
+    """Get the server specs"""
+    resp = None
+    if authorize(current_app.db, request):
+        LOG.info('Authorized client requests heartbeat..')
+        LOG.info('current_app is {}'.format(current_app))
+        disclaimer = current_app.config.get('DISCLAIMER')
+        result = controllers.heartbeat(disclaimer)
+        resp = jsonify(result)
+        resp.status_code = 200
+
+    else: # not authorized, return a 401 status code
+        return controllers.bad_request(401)
+
+    return resp
+
+
 @blueprint.route('/metrics', methods=['GET'])
 def metrics():
     """Get database metrics"""


Test patch:
diff --git a/tests/server/test_server_responses.py b/tests/server/test_server_responses.py
index bd25bbb..c11a16a 100644
--- a/tests/server/test_server_responses.py
+++ b/tests/server/test_server_responses.py
@@ -9,9 +9,34 @@ from patientMatcher.auth.auth import authorize
 from patientMatcher.server.controllers import validate_response
 from patientMatcher.parse.patient import mme_patient
 from patientMatcher.match.handler import patient_matches
+from patientMatcher.__version__ import __version__
 
 app = create_app()
 
+def test_heartbeat(database, test_client):
+    # Test sending a GET request to see if app has a heartbeat
+    app.db = database
+    # send a get request without being authorized
+    response = app.test_client().get('heartbeat')
+    assert response.status_code == 401
+
+    # add an authorized client to database
+    ok_token = test_client['auth_token']
+    add_node(mongo_db=app.db, obj=test_client, is_client=True)
+
+    # make sure that the request using its token is valid
+    response = app.test_client().get('heartbeat', headers = auth_headers(ok_token))
+    assert response.status_code == 200
+
+    # Make sure that all important info is returned
+    data = json.loads(response.data)
+    assert data['disclaimer'] == app.config.get('DISCLAIMER')
+    assert data['heartbeat']['version'] == __version__
+    assert isinstance(data['heartbeat']['production'], bool)
+    assert isinstance(data['heartbeat']['accept'], list)
+    assert len(data['heartbeat']['accept']) > 0
+
+
 def test_add_patient(database, json_patients, test_client, test_node):
     #Test sending a POST request to server to add a patient
     app.db = database