Git Product home page Git Product logo

api_gateway_common's People

Contributors

albamig avatar andrea-mucci avatar restyled-commits avatar vladyslav-fenchak avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar

api_gateway_common's Issues

Client HTTP for microservices

the Common library must support an HTTP Client for Microservices interfaces

METH_GET = "GET"
METH_DELETE = "DELETE"
METH_PATCH = "PATCH"
METH_POST = "POST"
METH_PUT = "PUT"


class ClientHttpBase:
    def __init__(self, **kwargs):
        pass

    async def get(self, url, params: dict = None, **kwargs: Any):
        return await self._triger_request(METH_GET, url, params, **kwargs)

    async def post(self, url, params: dict = None, data: Any = None, **kwargs: Any):
        return await self._triger_request(METH_POST, url, params, data, **kwargs)

    async def put(self, url, params: dict = None, data: Any = None, **kwargs: Any):
        return await self._triger_request(METH_PUT, url, params, data, **kwargs)

    async def patch(self, url, params: dict = None, data: Any = None, **kwargs: Any):
        return await self._triger_request(METH_PATCH, url, params, data, **kwargs)

    async def delete(self, url, params: dict = None, data: Any = None, **kwargs: Any):
        return await self._triger_request(METH_DELETE, url, params, data, **kwargs)

    async def _triger_request(self, method, url, params, data: Any = None, **kwargs: Any):
        async with aiohttp.ClientSession() as session:
            async with session.request(method=method, url=url, params=params, data=data, **kwargs) as resp:
                return resp

MinosConfig replica

Example of MinosConfig:

service:
    name: Order
rest:
    host: localhost
    port: 8900
    endpoints:
        - name: AddOrder
          route: /order
          method: POST
          controller: minos.services.OrderService
          action: add_order
discovery:
    host: localhost
    port: 8080
    path: /discover
    endpoints:
        - name: Discover
          route: /discover
          method: GET
          controller: minos.services.DiscoveryService
          action: discover
        - name: Subscribe
          route: /subscribe
          method: POST
          controller: minos.services.DiscoveryService
          action: subscribe
        - name: Unsubscribe
          route: /unsubscribe
          method: POST
          controller: minos.services.DiscoveryService
          action: unsubscribe
        - name: SystemHealth
          route: /system/health
          method: GET
          controller: minos.services.DiscoveryService
          action: system_health
    db:
        host: localhost
        port: 6379
        password: None

Add importlib class

def import_module(module: str) -> t.Type:
    """Import the given module from a package"""
    try:
        if "." in module:
            parts = module.split(".")
            name = ".".join(parts[:-1])

        module_ref = importlib.import_module(name)
        kallable = getattr(module_ref, parts[-1])
        if not six.callable(kallable):
            raise TypeError("The module is not callable")
        return kallable
    except ImportError as e:
        raise MinosImportException("Error importing Package")


def classname(cls: t.Type) -> str:
    """Compute the given class full name.

    :param cls: Target class.
    :return: An string object.
    """
    return f"{cls.__module__}.{cls.__qualname__}"

Add Endpoint Routes loader

Example:

class RestRoutesLoader:
    """
    Rest Interface Handler

    Rest Interface for aiohttp web handling.

    """

    __slots__ = "_config", "_app"

    def __init__(self, config: MinosConfig, app: web.Application = web.Application()):
        self._config = config
        self._app = app
        self.load_routes()

    def load_routes(self):
        """Load routes from config file."""
        for item in self._config.discovery.endpoints:
            callable_f = self.class_resolver(item.controller, item.action)
            self._app.router.add_route(item.method, item.route, callable_f)

    @staticmethod
    def class_resolver(controller: str, action: str):
        """Load controller class and action method.
        :param controller: Controller string. Example: "tests.service.CommandTestService.CommandService"
        :param action: Config instance. Example: "get_order"
        :return: A class method callable instance.
        """
        object_class = import_module(controller)
        instance_class = object_class()
        class_method = getattr(instance_class, action)

        return class_method

    def get_app(self):
        """Return rest application instance.
        :return: A `web.Application` instance.
        """
        return self._app

Fix package naming

Currently, the package is named as "api_gateway_common" in pyproject.toml. That name is used as the package name on Pypi.

To avoid future confusion and keep all the packages developed for the minos framework, I propose to replace it by something like "minos_api_gateway_common"

Add Aiohttp Service extensible

Example of main class:

class RESTService(AIOHTTPService):
    """
    Rest Interface

    Expose REST Interface handler using aiomisc AIOHTTPService.

    """

    def __init__(self, address: str, port: int, endpoints: dict, app: web.Application = web.Application(), **kwds: t.Any):
        address = address
        port = port
        super().__init__(address=address, port=port, **kwds)
        self._endpoints = endpoints
        self.rest_interface = RestRoutesLoader(endpoints=endpoints, app=app)

    async def create_application(self):
        return self.rest_interface.get_app()  # pragma: no cover

Example of extend and create custom service:

class TestRestService(RESTService):
    def __init__(self, address: str, port: int, endpoints: dict, **kwds: t.Any):
        super().__init__(address=address, port=port, endpoints=endpoints, **kwds)

config = MinosConfig(self.CONFIG_FILE_PATH)
        rest_interface = TestRestService(address=config.rest.connection.host, port=config.rest.connection.port, endpoints=config.rest.endpoints)

Include restyle config file

---
enabled: true
exclude:
  - "**/*.md"
  - ".idea/**/*"
  - "docs/**/*"
  - "**/*.in"
  - "Makefile"
  - ".github/workflows/**/*"
restylers:
  - name: black
    image: restyled/restyler-black:v19.10b0
    command:
      - black
    arguments: ["--line-length", "120"]
    include:
      - "**/*.py"
    interpreters:
      - python
  - name: isort
    image: restyled/restyler-isort:v5.8.0
    command:
      - isort
    arguments: []
    include:
      - "**/*.py"
    interpreters:
      - python

Add MinosConfig to RestRoutesLoader

RestRoutesLoader must load controller and action passing MinosConfig as default:

class RestRoutesLoader:
    ...
    def resolve_callable(self, controller: str, action: str):
        """Load controller class and action method.
        :param controller: Controller string. Example: "tests.service.CommandTestService.CommandService"
        :param action: Config instance. Example: "get_order"
        :return: A class method callable instance.
        """
        object_class = import_module(controller)
        instance_class = object_class()
        class_method = getattr(instance_class, action)
        partial = functools.partial(class_method, config=self._config)

        return partial

   ...

ClientHttp close connection

Problem:

  • Some aiohttp methods are async and response.text() is one of them. So. if you want to get the text response or another async method, an exception that the connection is closed will be thrown.

Current Implementation:

class ClientHttp(ClientHttpBase):
 ...
   async def _trigger_request(self, method: str, url: str, params, data: Any = None, **kwargs: Any):
        """Trigger the request.
        :param method: HTTP method.
        :param url: Url to call.
        :param params: Params to send on URL.
        :param data: Data to send in body.
        :param kwargs: Additional named arguments.
        :return: A `_RequestContextManager` instance.
        """
        async with aiohttp.ClientSession() as session:
            async with session.request(method=method, url=url, params=params, data=data, **kwargs) as resp:
                return resp
  ....

Solution:

class ClientHttp(ClientHttpBase):
    """HTTP Client aiohttp."""

    async def __aenter__(self):
        self.session = aiohttp.ClientSession()
        return self.session

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        await self.session.close()

    async def _trigger_request(self, method: str, url: str, params, data: Any = None, **kwargs: Any):
        """Trigger the request.
        :param method: HTTP method.
        :param url: Url to call.
        :param params: Params to send on URL.
        :param data: Data to send in body.
        :param kwargs: Additional named arguments.
        :return: A `_RequestContextManager` instance.
        """
        async with self.session.request(method=method, url=url, params=params, data=data, **kwargs) as response:
            return response

Use:

        async with ClientHttp() as client:
            request = await client.get(url="http://httpbin.org/get")
            self.assertEqual(request.status, 200)

Package Restyling

The changes to be applied during the restyling process are:

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.