Skip to content

Commit d4db57b

Browse files
author
Sergio García Prado
authored
Merge pull request #44 from Clariteia/0.0.3
0.0.3
2 parents 1a9f3bf + e3d340f commit d4db57b

File tree

13 files changed

+446
-418
lines changed

13 files changed

+446
-418
lines changed

HISTORY.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,10 @@
77
## 0.0.2 (2021-06-18)
88

99
* Bugfix.
10+
11+
## 0.0.3 (2021-08-19)
12+
13+
* Support auto discoverable endpoints.
14+
* Handle requests to unavailable microservices.
15+
* Improve request forwarding to microservices.
16+
* Fix bug related with unnecessary `json` casting.

minos/api_gateway/rest/__init__.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@
55
66
Minos framework can not be copied and/or distributed without the express permission of Clariteia SL.
77
"""
8-
__version__ = "0.0.2"
8+
__version__ = "0.0.3"
99

10-
from .coordinator import (
11-
MicroserviceCallCoordinator,
12-
)
1310
from .launchers import (
1411
EntrypointLauncher,
1512
)

tests/test_api_gateway/test_something.py renamed to minos/api_gateway/rest/__main__.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,9 @@
55
66
Minos framework can not be copied and/or distributed without the express permission of Clariteia SL.
77
"""
8-
9-
import unittest
10-
11-
12-
class TestSomething(unittest.TestCase):
13-
def test_something(self):
14-
self.assertEqual(True, True)
15-
8+
from .cli import (
9+
main,
10+
)
1611

1712
if __name__ == "__main__":
18-
unittest.main()
13+
main()

minos/api_gateway/rest/cli.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ def start(
4141
typer.echo(f"Error loading config: {exc!r}")
4242
raise typer.Exit(code=1)
4343

44-
services = (ApiGatewayRestService(config=config),)
44+
services = (
45+
ApiGatewayRestService(address=config.rest.connection.host, port=config.rest.connection.port, config=config),
46+
)
4547
try:
4648
EntrypointLauncher(config=config, services=services).launch()
4749
except Exception as exc:

minos/api_gateway/rest/coordinator.py

Lines changed: 0 additions & 68 deletions
This file was deleted.

minos/api_gateway/rest/handler.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""minos.api_gateway.rest.handler module."""
2+
3+
import logging
4+
from typing import (
5+
Any,
6+
)
7+
8+
from aiohttp import (
9+
ClientConnectorError,
10+
ClientResponse,
11+
ClientSession,
12+
web,
13+
)
14+
from yarl import (
15+
URL,
16+
)
17+
18+
logger = logging.getLogger(__name__)
19+
20+
21+
async def orchestrate(request: web.Request) -> web.Response:
22+
""" Orchestrate discovery and microservice call """
23+
discovery_host = request.app["config"].discovery.connection.host
24+
discovery_port = request.app["config"].discovery.connection.port
25+
26+
verb = request.method
27+
url = f"/{request.match_info['endpoint']}"
28+
29+
discovery_data = await discover(discovery_host, int(discovery_port), "/microservices", verb, url)
30+
31+
microservice_response = await call(**discovery_data, original_req=request)
32+
return microservice_response
33+
34+
35+
async def discover(host: str, port: int, path: str, verb: str, endpoint: str) -> dict[str, Any]:
36+
"""Call discovery service and get microservice connection data.
37+
38+
:param host: Discovery host name.
39+
:param port: Discovery port.
40+
:param path: Discovery path.
41+
:param verb: Endpoint Verb.
42+
:param endpoint: Endpoint url.
43+
:return: The response of the discovery.
44+
"""
45+
46+
url = URL.build(scheme="http", host=host, port=port, path=path, query={"verb": verb, "path": endpoint})
47+
try:
48+
async with ClientSession() as session:
49+
async with session.get(url=url) as response:
50+
if not response.ok:
51+
raise web.HTTPBadGateway(text="The discovery response is not okay.")
52+
data = await response.json()
53+
except ClientConnectorError:
54+
raise web.HTTPGatewayTimeout(text="The discovery is not available.")
55+
56+
data["port"] = int(data["port"])
57+
58+
return data
59+
60+
61+
# noinspection PyUnusedLocal
62+
async def call(address: str, port: int, original_req: web.Request, **kwargs) -> web.Response:
63+
"""Call microservice (redirect the original call)
64+
65+
:param address: The ip of the microservices.
66+
:param port: The port of the microservice.
67+
:param original_req: The original request.
68+
:param kwargs: Additional named arguments.
69+
:return: The web response to be retrieved to the client.
70+
"""
71+
72+
headers = original_req.headers
73+
url = original_req.url.with_scheme("http").with_host(address).with_port(port)
74+
method = original_req.method
75+
content = await original_req.text()
76+
77+
logger.info(f"Redirecting {method!r} request to {url!r}...")
78+
79+
try:
80+
async with ClientSession(headers=headers) as session:
81+
async with session.request(method=method, url=url, data=content) as response:
82+
return await _clone_response(response)
83+
except ClientConnectorError:
84+
raise web.HTTPServiceUnavailable(text="The requested endpoint is not available.")
85+
86+
87+
# noinspection PyMethodMayBeStatic
88+
async def _clone_response(response: ClientResponse) -> web.Response:
89+
return web.Response(
90+
body=await response.read(), status=response.status, reason=response.reason, headers=response.headers,
91+
)

minos/api_gateway/rest/service.py

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,33 @@
1-
# Copyright (C) 2020 Clariteia SL
2-
#
3-
# This file is part of minos framework.
4-
#
5-
# Minos framework can not be copied and/or distributed without the express
6-
# permission of Clariteia SL.
1+
"""minos.api_gateway.rest.service module."""
72

8-
import typing as t
3+
import logging
94

105
from aiohttp import (
116
web,
127
)
8+
from aiomisc.service.aiohttp import (
9+
AIOHTTPService,
10+
)
1311

1412
from minos.api_gateway.common import (
1513
MinosConfig,
16-
RESTService,
1714
)
15+
from minos.api_gateway.rest import (
16+
handler,
17+
)
18+
19+
logger = logging.getLogger(__name__)
20+
21+
22+
class ApiGatewayRestService(AIOHTTPService):
23+
def __init__(self, address: str, port: int, config: MinosConfig):
24+
self.config = config
25+
super().__init__(address, port)
26+
27+
async def create_application(self) -> web.Application:
28+
app = web.Application()
29+
app["config"] = self.config
1830

31+
app.router.add_route("*", "/{endpoint:.*}", handler.orchestrate)
1932

20-
class ApiGatewayRestService(RESTService):
21-
def __init__(self, config: MinosConfig, app: web.Application = web.Application(), **kwds: t.Any):
22-
super().__init__(
23-
address=config.rest.connection.host,
24-
port=config.rest.connection.port,
25-
endpoints=config.rest.endpoints,
26-
config=config,
27-
app=app,
28-
**kwds
29-
)
33+
return app

0 commit comments

Comments
 (0)