diff --git a/config/dev.yml b/config/dev.yml index e55d2db..abc1ad3 100644 --- a/config/dev.yml +++ b/config/dev.yml @@ -1,9 +1,11 @@ storage: cls: remote url: http://moma.internal.softwareheritage.org:5002 search: cls: remote url: http://moma.internal.softwareheritage.org:5010 debug: yes + +introspection: yes diff --git a/config/staging.yml b/config/staging.yml index 3835837..125c68f 100644 --- a/config/staging.yml +++ b/config/staging.yml @@ -1,9 +1,11 @@ storage: cls: remote url: http://webapp.internal.staging.swh.network:5002 search: cls: remote url: http://webapp.internal.staging.swh.network:5010 debug: no + +introspection: yes diff --git a/swh/graphql/server.py b/swh/graphql/server.py index ef1fbb6..3df6a14 100644 --- a/swh/graphql/server.py +++ b/swh/graphql/server.py @@ -1,85 +1,90 @@ # Copyright (C) 2022 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information import os from typing import Any, Dict, Optional from swh.core import config from swh.search import get_search as get_swh_search from swh.search.interface import SearchInterface from swh.storage import get_storage as get_swh_storage from swh.storage.interface import StorageInterface graphql_cfg: Dict[str, Any] = {} storage: Optional[StorageInterface] = None search: Optional[SearchInterface] = None def get_storage() -> StorageInterface: global storage if not storage: storage = get_swh_storage(**graphql_cfg["storage"]) return storage def get_search() -> SearchInterface: global search if not search: search = get_swh_search(**graphql_cfg["search"]) return search def load_and_check_config(config_path: Optional[str]) -> Dict[str, Any]: """Check the minimal configuration is set to run the api or raise an error explanation. Args: config_path: Path to the configuration file to load Raises: Error if the setup is not as expected Returns: configuration as a dict """ if not config_path: raise EnvironmentError("Configuration file must be defined") if not os.path.exists(config_path): raise FileNotFoundError(f"Configuration file {config_path} does not exist") cfg = config.read(config_path) if "storage" not in cfg: raise KeyError("Missing 'storage' configuration") return cfg def make_app_from_configfile(): """Loading the configuration from a configuration file. SWH_CONFIG_FILENAME environment variable defines the configuration path to load. """ from ariadne.asgi import GraphQL from starlette.middleware.cors import CORSMiddleware from .app import schema from .errors import format_error global graphql_cfg if not graphql_cfg: config_path = os.environ.get("SWH_CONFIG_FILENAME") graphql_cfg = load_and_check_config(config_path) application = CORSMiddleware( - GraphQL(schema, debug=graphql_cfg["debug"], error_formatter=format_error), + GraphQL( + schema, + debug=graphql_cfg["debug"], + error_formatter=format_error, + introspection=graphql_cfg["introspection"], + ), # FIXME, restrict origins after deploying the JS client allow_origins=["*"], allow_methods=("GET", "POST", "OPTIONS"), ) return application diff --git a/swh/graphql/tests/unit/test_server.py b/swh/graphql/tests/unit/test_server.py index f968649..e824df3 100644 --- a/swh/graphql/tests/unit/test_server.py +++ b/swh/graphql/tests/unit/test_server.py @@ -1,67 +1,71 @@ # Copyright (C) 2022 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information import pytest from swh.graphql import server def test_get_storage(mocker): server.storage = None server.graphql_cfg = {"storage": {"test": "test"}} mocker.patch("swh.graphql.server.get_swh_storage", return_value="dummy-storage") assert server.get_storage() == "dummy-storage" def test_get_global_storage(mocker): server.storage = "existing-storage" assert server.get_storage() == "existing-storage" def test_get_search(mocker): server.search = None server.graphql_cfg = {"search": {"test": "test"}} mocker.patch("swh.graphql.server.get_swh_search", return_value="dummy-search") assert server.get_search() == "dummy-search" def test_get_global_search(mocker): server.search = "existing-search" assert server.get_search() == "existing-search" def test_load_and_check_config_no_config(): with pytest.raises(EnvironmentError): server.load_and_check_config(config_path=None) def test_load_and_check_config_missing_config_file(): with pytest.raises(FileNotFoundError): server.load_and_check_config(config_path="invalid") def test_load_and_check_config_missing_storage_config(mocker): mocker.patch("swh.core.config.read", return_value={"test": "test"}) with pytest.raises(KeyError): server.load_and_check_config(config_path="/tmp") def test_load_and_check_config(mocker): mocker.patch("swh.core.config.read", return_value={"storage": {"test": "test"}}) cfg = server.load_and_check_config(config_path="/tmp") assert cfg == {"storage": {"test": "test"}} def test_make_app_from_configfile_with_config(mocker): - server.graphql_cfg = {"storage": {"test": "test"}, "debug": True} + server.graphql_cfg = { + "storage": {"test": "test"}, + "debug": True, + "introspection": True, + } mocker.patch("starlette.middleware.cors.CORSMiddleware", return_value="dummy-app") assert server.make_app_from_configfile() == "dummy-app" def test_make_app_from_configfile_missing_config(mocker): server.graphql_cfg = None with pytest.raises(EnvironmentError): # trying to load config from a non existing env var assert server.make_app_from_configfile()