diff --git a/server/app/app.py b/server/app/app.py index d926f515..7e02b4e1 100644 --- a/server/app/app.py +++ b/server/app/app.py @@ -99,6 +99,10 @@ def dataset_index(url_dataroot=None, dataset=None): ) +# TODO: This route will be deprecated, but needs to be left for a short time until all the +# deployments are upgraded to the new location for the health check (or else the upgrade will +# fail). Once the upgrade is complete, the deployments can move to the new health check URL +# and this route will be removed. @webbp.route("/health", methods=["GET"]) @cache_control_always(no_store=True) def health(): @@ -224,6 +228,13 @@ def dataroot_index(): return redirect(config.server_config.multi_dataset__index) +class HealthAPI(Resource): + @cache_control(no_store=True) + def get(self): + config = current_app.app_config + return health_check(config) + + class DatasetResource(Resource): """Base class for all Resources that act on datasets.""" @@ -312,8 +323,18 @@ class LayoutObsAPI(DatasetResource): return common_rest.layout_obs_put(request, data_adaptor) -def get_api_resources(bp_api, url_dataroot=None): - api = Api(bp_api) +def get_api_base_resources(bp_base): + """Add resources that are accessed from the api_base_url""" + api = Api(bp_base) + + # Diagnostics routes + api.add_resource(HealthAPI, "/health") + return api + + +def get_api_dataroot_resources(bp_dataroot, url_dataroot=None): + """Add resources that refer to a dataset""" + api = Api(bp_dataroot) def add_resource(resource, url): """convenience function to make the outer function less verbose""" @@ -385,18 +406,23 @@ class Server: parse = urlparse(api_base_url) api_path = parse.path + bp_base = Blueprint("bp_base", __name__, url_prefix=api_path) + base_resources = get_api_base_resources(bp_base) + self.app.register_blueprint(base_resources.blueprint) + if app_config.is_multi_dataset(): # NOTE: These routes only allow the dataset to be in the directory # of the dataroot, and not a subdirectory. We may want to change # the route format at some point for dataroot_dict in server_config.multi_dataset__dataroot.values(): url_dataroot = dataroot_dict["base_url"] - bp_api = Blueprint( + bp_dataroot = Blueprint( f"api_dataset_{url_dataroot}", __name__, url_prefix=f"{api_path}/{url_dataroot}/" + api_version ) - resources = get_api_resources(bp_api, url_dataroot) - self.app.register_blueprint(resources.blueprint) + dataroot_resources = get_api_dataroot_resources(bp_dataroot, url_dataroot) + self.app.register_blueprint(dataroot_resources.blueprint) + self.app.add_url_rule( f"/{url_dataroot}//", f"dataset_index_{url_dataroot}", @@ -412,7 +438,7 @@ class Server: else: bp_api = Blueprint("api", __name__, url_prefix=f"{api_path}{api_version}") - resources = get_api_resources(bp_api) + resources = get_api_dataroot_resources(bp_api) self.app.register_blueprint(resources.blueprint) self.app.add_url_rule( "/static/", diff --git a/server/test/unit/common/test_app_config.py b/server/test/unit/common/test_app_config.py index f8a20093..6b86d771 100644 --- a/server/test/unit/common/test_app_config.py +++ b/server/test/unit/common/test_app_config.py @@ -142,7 +142,7 @@ class AppConfigTest(unittest.TestCase): config = AppConfig() backend_port = find_available_port("localhost", 10000) config.update_server_config( - app__api_base_url=f"http://localhost:{backend_port}/additional/path/before/dataroot", + app__api_base_url=f"http://localhost:{backend_port}/additional/path", multi_dataset__dataroot=f"{PROJECT_ROOT}/example-dataset" ) @@ -151,11 +151,21 @@ class AppConfigTest(unittest.TestCase): with test_server(["-p", str(backend_port)], app_config=config) as server: session = requests.Session() self.assertEqual(server, f"http://localhost:{backend_port}") - response = session.get(f"{server}/additional/path/before/dataroot/d/pbmc3k.h5ad/api/v0.2/config") + response = session.get(f"{server}/additional/path/d/pbmc3k.h5ad/api/v0.2/config") self.assertEqual(response.status_code, 200) data_config = response.json() self.assertEqual(data_config["config"]["displayNames"]["dataset"], "pbmc3k") + # test the health check at the correct url + response = session.get(f"{server}/additional/path/health") + assert response.json()["status"] == "pass" + + # also check that the old URL still works. + # NOTE: this old URL location will soon be deprecated, and when that happens + # this check can be removed. + response = session.get(f"{server}/health") + assert response.json()["status"] == "pass" + def test_configfile_with_specialization(self): # test that per_dataset_config config load the default config, then the specialized config