Skip to content

Commit 948d9d5

Browse files
author
Sergio García Prado
authored
Merge pull request #55 from Clariteia/issue-54-remove-common-dependency
#54 - remove common dependency
2 parents 85e7312 + 8e12ccc commit 948d9d5

22 files changed

+319
-192
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ coverage: ## check code coverage quickly with the default Python
6767

6868
reformat: ## check code coverage quickly with the default Python
6969
poetry run black --line-length 120 minos tests
70-
poetry run isort --recursive minos tests
70+
poetry run isort minos tests
7171

7272
docs: ## generate Sphinx HTML documentation, including API docs
7373
rm -rf docs/api

minos/api_gateway/rest/__init__.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
"""
2-
Copyright (C) 2021 Clariteia SL
3-
4-
This file is part of minos framework.
5-
6-
Minos framework can not be copied and/or distributed without the express permission of Clariteia SL.
7-
"""
81
__version__ = "0.0.4"
92

3+
from .config import (
4+
ApiGatewayConfig,
5+
)
6+
from .exceptions import (
7+
ApiGatewayConfigException,
8+
ApiGatewayException,
9+
InvalidAuthenticationException,
10+
NoTokenException,
11+
)
1012
from .launchers import (
1113
EntrypointLauncher,
1214
)

minos/api_gateway/rest/__main__.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
"""
2-
Copyright (C) 2021 Clariteia SL
3-
4-
This file is part of minos framework.
5-
6-
Minos framework can not be copied and/or distributed without the express permission of Clariteia SL.
7-
"""
81
from .cli import (
92
main,
103
)

minos/api_gateway/rest/cli.py

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
"""
2-
Copyright (C) 2021 Clariteia SL
3-
4-
This file is part of minos framework.
5-
6-
Minos framework can not be copied and/or distributed without the express permission of Clariteia SL.
7-
"""
81
from pathlib import (
92
Path,
103
)
@@ -14,13 +7,13 @@
147

158
import typer
169

17-
from minos.api_gateway.common import (
18-
MinosConfig,
10+
from .config import (
11+
ApiGatewayConfig,
1912
)
20-
from minos.api_gateway.rest.launchers import (
13+
from .launchers import (
2114
EntrypointLauncher,
2215
)
23-
from minos.api_gateway.rest.service import (
16+
from .service import (
2417
ApiGatewayRestService,
2518
)
2619

@@ -36,14 +29,12 @@ def start(
3629
"""Start Api Gateway services."""
3730

3831
try:
39-
config = MinosConfig(file_path)
32+
config = ApiGatewayConfig(file_path)
4033
except Exception as exc:
4134
typer.echo(f"Error loading config: {exc!r}")
4235
raise typer.Exit(code=1)
4336

44-
services = (
45-
ApiGatewayRestService(address=config.rest.connection.host, port=config.rest.connection.port, config=config),
46-
)
37+
services = (ApiGatewayRestService(address=config.rest.host, port=config.rest.port, config=config),)
4738
try:
4839
EntrypointLauncher(config=config, services=services).launch()
4940
except Exception as exc:

minos/api_gateway/rest/config.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
from __future__ import (
2+
annotations,
3+
)
4+
5+
import abc
6+
import collections
7+
import os
8+
import typing as t
9+
from distutils import (
10+
util,
11+
)
12+
from pathlib import (
13+
Path,
14+
)
15+
16+
import yaml
17+
18+
from .exceptions import (
19+
ApiGatewayConfigException,
20+
)
21+
22+
REST = collections.namedtuple("Rest", "host port cors")
23+
DISCOVERY = collections.namedtuple("Discovery", "host port")
24+
CORS = collections.namedtuple("Cors", "enabled")
25+
26+
_ENVIRONMENT_MAPPER = {
27+
"rest.host": "API_GATEWAY_REST_HOST",
28+
"rest.port": "API_GATEWAY_REST_PORT",
29+
"rest.cors.enabled": "API_GATEWAY_REST_CORS_ENABLED",
30+
"discovery.host": "API_GATEWAY_DISCOVERY_HOST",
31+
"discovery.port": "API_GATEWAY_DISCOVERY_PORT",
32+
}
33+
34+
_PARAMETERIZED_MAPPER = {
35+
"rest.host": "api_gateway_rest_host",
36+
"rest.port": "api_gateway_rest_port",
37+
"rest.cors.enabled": "api_gateway_rest_cors_enabled",
38+
"discovery.host": "api_gateway_discovery_host",
39+
"discovery.port": "api_gateway_discovery_port",
40+
}
41+
42+
43+
class ApiGatewayConfig(abc.ABC):
44+
"""Api Gateway config class."""
45+
46+
__slots__ = ("_services", "_path", "_data", "_with_environment", "_parameterized")
47+
48+
def __init__(self, path: t.Union[Path, str], with_environment: bool = True, **kwargs):
49+
if isinstance(path, Path):
50+
path = str(path)
51+
self._services = {}
52+
self._path = path
53+
self._load(path)
54+
self._with_environment = with_environment
55+
self._parameterized = kwargs
56+
57+
@staticmethod
58+
def _file_exit(path: str) -> bool:
59+
if os.path.isfile(path):
60+
return True
61+
return False
62+
63+
def _load(self, path):
64+
if self._file_exit(path):
65+
with open(path) as f:
66+
self._data = yaml.load(f, Loader=yaml.FullLoader)
67+
else:
68+
raise ApiGatewayConfigException(f"Check if this path: {path} is correct")
69+
70+
def _get(self, key: str, **kwargs: t.Any) -> t.Any:
71+
if key in _PARAMETERIZED_MAPPER and _PARAMETERIZED_MAPPER[key] in self._parameterized:
72+
return self._parameterized[_PARAMETERIZED_MAPPER[key]]
73+
74+
if self._with_environment and key in _ENVIRONMENT_MAPPER and _ENVIRONMENT_MAPPER[key] in os.environ:
75+
if os.environ[_ENVIRONMENT_MAPPER[key]] in ["true", "True", "false", "False"]:
76+
return bool(util.strtobool(os.environ[_ENVIRONMENT_MAPPER[key]]))
77+
return os.environ[_ENVIRONMENT_MAPPER[key]]
78+
79+
def _fn(k: str, data: dict[str, t.Any]) -> t.Any:
80+
current, _, following = k.partition(".")
81+
82+
part = data[current]
83+
if not following:
84+
return part
85+
86+
return _fn(following, part)
87+
88+
return _fn(key, self._data)
89+
90+
@property
91+
def rest(self) -> REST:
92+
"""Get the rest config.
93+
94+
:return: A ``REST`` NamedTuple instance.
95+
"""
96+
return REST(host=self._get("rest.host"), port=int(self._get("rest.port")), cors=self._cors)
97+
98+
@property
99+
def _cors(self) -> CORS:
100+
"""Get the cors config.
101+
102+
:return: A ``CORS`` NamedTuple instance.
103+
"""
104+
return CORS(enabled=self._get("rest.cors.enabled"))
105+
106+
@property
107+
def discovery(self) -> DISCOVERY:
108+
"""Get the rest config.
109+
110+
:return: A ``REST`` NamedTuple instance.
111+
"""
112+
return DISCOVERY(host=self._get("discovery.host"), port=int(self._get("discovery.port")))
Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1-
class InvalidAuthenticationException(Exception):
2-
pass
1+
class ApiGatewayException(Exception):
2+
"""TODO"""
33

44

5-
class NoTokenException(Exception):
6-
pass
5+
class InvalidAuthenticationException(ApiGatewayException):
6+
"""TODO"""
7+
8+
9+
class NoTokenException(ApiGatewayException):
10+
"""TODO"""
11+
12+
13+
class ApiGatewayConfigException(ApiGatewayException):
14+
"""Base config exception."""

minos/api_gateway/rest/handler.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
"""minos.api_gateway.rest.handler module."""
2-
31
import logging
42
from typing import (
53
Any,
@@ -15,7 +13,7 @@
1513
URL,
1614
)
1715

18-
from minos.api_gateway.rest.exceptions import (
16+
from .exceptions import (
1917
InvalidAuthenticationException,
2018
NoTokenException,
2119
)
@@ -27,8 +25,8 @@
2725

2826
async def orchestrate(request: web.Request) -> web.Response:
2927
""" Orchestrate discovery and microservice call """
30-
discovery_host = request.app["config"].discovery.connection.host
31-
discovery_port = request.app["config"].discovery.connection.port
28+
discovery_host = request.app["config"].discovery.host
29+
discovery_port = request.app["config"].discovery.port
3230

3331
verb = request.method
3432
url = f"/{request.match_info['endpoint']}"

minos/api_gateway/rest/launchers.py

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
"""
2-
Copyright (C) 2021 Clariteia SL
3-
4-
This file is part of minos framework.
5-
6-
Minos framework can not be copied and/or distributed without the express permission of Clariteia SL.
7-
"""
8-
91
import logging
102
from typing import (
113
NoReturn,
@@ -21,8 +13,8 @@
2113
cached_property,
2214
)
2315

24-
from minos.api_gateway.common import (
25-
MinosConfig,
16+
from .config import (
17+
ApiGatewayConfig,
2618
)
2719

2820
logger = logging.getLogger(__name__)
@@ -31,7 +23,7 @@
3123
class EntrypointLauncher:
3224
"""EntryPoint Launcher class."""
3325

34-
def __init__(self, config: MinosConfig, services: tuple, *args, **kwargs):
26+
def __init__(self, config: ApiGatewayConfig, services: tuple, *args, **kwargs):
3527
self.config = config
3628
self.services = services
3729

minos/api_gateway/rest/service.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
"""minos.api_gateway.rest.service module."""
2-
31
import logging
42

53
from aiohttp import (
@@ -12,30 +10,30 @@
1210
AIOHTTPService,
1311
)
1412

15-
from minos.api_gateway.common import (
16-
MinosConfig,
13+
from .config import (
14+
ApiGatewayConfig,
1715
)
18-
from minos.api_gateway.rest import (
19-
handler,
16+
from .handler import (
17+
orchestrate,
2018
)
2119

2220
logger = logging.getLogger(__name__)
2321

2422

2523
class ApiGatewayRestService(AIOHTTPService):
26-
def __init__(self, address: str, port: int, config: MinosConfig):
24+
def __init__(self, address: str, port: int, config: ApiGatewayConfig):
2725
self.config = config
2826
super().__init__(address, port)
2927

3028
async def create_application(self) -> web.Application:
3129
middlewares = list()
32-
if self.config.cors.enabled:
30+
if self.config.rest.cors.enabled:
3331
middlewares = [cors_middleware(allow_all=True)]
3432

3533
app = web.Application(middlewares=middlewares)
3634

3735
app["config"] = self.config
3836

39-
app.router.add_route("*", "/{endpoint:.*}", handler.orchestrate)
37+
app.router.add_route("*", "/{endpoint:.*}", orchestrate)
4038

4139
return app

0 commit comments

Comments
 (0)