HTTP Adaptor

The http adaptor wraps the Tornado package exposing the ability to interact as a client or implement the server.

HTTP Server

The HTTP server provides a handler based approach to implementing server side logic. These are found in: hgraph.adaptors.tornado.http_server_adaptor.

http_server_handler(fn: Callable = None, *, url: str)[source]

Wrap an endpoint or route in the adaptor handler. If the handler is simple (i.e. it is self-contained) then the function can have a simple signature of:

@http_server_handler(url='/mypath')
def simple_handler(request: TS[HttpRequest]) -> TS[HttpResponse]:
    return combine[TS[HttpResponse]](status_code=200, body="Simple Response")

In this case, so long as this is imported, it will be wired in when the server is registered.

The http server is registered as below:

register_adaptor(default_path, http_server_adaptor_helper, port=8081)

The handler can take single TS inputs as above, or it can process all requests simultaneously. In this mode, the signature takes the form below:

@http_server_handler(url='/mypath')
def batch_handler(request: TSD[int, TS[HttpRequest]]) -> TSD[int, TS[HttpResponse]]:
    ...

In this more each request is collected into a TSD. As a reminder, it is the implementers’ responsibility to process the removal requests (forwarding them to the response output.

It is possible to support additional inputs and outputs. For inputs, add them to the input signature. Once the handler has any additional inputs (other than request) the handler must be instantiated manually. To return more than one response, use a TSB to encapsulate the responses. Note that there must be at least one response that is called response and has a type of TS[HttpResponse] or TSD[int, TS[HttpResponse]]. For example:

class MyHandlerResponse(TimeSeriesSchema):
    response: TS[HttpResponse]
    p1: ...
    p2: ...

@http_server_handler(url='/mypath')
def complex_handler(request: TS[HttpRequest], ts_1: ...) -> TSB[MyHandlerResponse]:
    ...

To instantiate the handler, the function is called in the graph with the inputs being the list of parameters in the input other than the request parameter. For example:

::

register_adaptor(default_path, http_server_adaptor_helper, port=8081) … out = complex_handlder(ts_1=…, …)

The request argument is automatically wired into the adaptor. The response is returned in full, but the response output will also be wired into the adaptor.

class HttpRequest(url: str, url_parsed_args: tuple[str, ...] = (), query: dict[str, str] = {}, headers: dict[str, str] = {}, cookies: dict[str, dict[str, object]] = {}, auth: object = None, connect_timeout: float = 20.0, request_timeout: float = 20.0)[source]

NOTE: Do not use this class directly. Use one of the specific types i.e.: * HttpGetRequest * HttpPutRequest * HttpDeleteRequest * HttpPostRequest

Using this will result in a request failure with code 400.

class HttpGetRequest(url: str, url_parsed_args: tuple[str, ...] = (), query: dict[str, str] = frozendict.frozendict({}), headers: dict[str, str] = frozendict.frozendict({}), cookies: dict[str, dict[str, object]] = frozendict.frozendict({}), auth: object = None, connect_timeout: float = 20.0, request_timeout: float = 20.0)[source]
class HttpDeleteRequest(url: str, url_parsed_args: tuple[str, ...] = (), query: dict[str, str] = frozendict.frozendict({}), headers: dict[str, str] = frozendict.frozendict({}), cookies: dict[str, dict[str, object]] = frozendict.frozendict({}), auth: object = None, connect_timeout: float = 20.0, request_timeout: float = 20.0)[source]
class HttpPutRequest(url: str, url_parsed_args: tuple[str, ...] = (), query: dict[str, str] = frozendict.frozendict({}), headers: dict[str, str] = frozendict.frozendict({}), cookies: dict[str, dict[str, object]] = frozendict.frozendict({}), auth: object = None, connect_timeout: float = 20.0, request_timeout: float = 20.0, body: str = '')[source]
class HttpPostRequest(url: str, url_parsed_args: tuple[str, ...] = (), query: dict[str, str] = frozendict.frozendict({}), headers: dict[str, str] = frozendict.frozendict({}), cookies: dict[str, dict[str, object]] = frozendict.frozendict({}), auth: object = None, connect_timeout: float = 20.0, request_timeout: float = 20.0, body: str = '')[source]
class HttpResponse(status_code: int, headers: frozendict.frozendict[str, str] = frozendict.frozendict({}), cookies: dict[str, dict[str, object]] = frozendict.frozendict({}), body: bytes = b'')[source]

Use the following to assist setting up the services to make this work:

register_http_server_adaptor(port: int)[source]

Correctly registers the http server adaptor and associated machinery.

HTTP Client

The client is accessed via a service adaptor, namely: http_client_adaptor. This is found in the package: hgraph.adaptors.tornado.http_client_adaptor.

http_client_adaptor(request: TS[HttpRequest], path: str) TS[HttpResponse][source]

Sends requests to a remote server. The result is returned as an HttpResponse object. Supports Get, Put, Delete and Post requests. To use the adaptor you need to register the service impl. The default provided implementation is http_client_adaptor_impl.

Return type:

TimeSeriesValueInput[HttpResponse]

The adaptor implementation is here:

http_client_adaptor_impl(path: str, use_curl: bool, max_clients: int) TSD[int, TS[HttpResponse]][source]

The client adaptor is responsible for making HTTP requests to a remote server. This implementation is able to support NTLM and Kerberos authentication.

Return type:

TimeSeriesDictInput[int, TimeSeriesValueInput[HttpResponse]]