Skip to content

Commit

Permalink
Support JSON requests over HTTP (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
taral authored Jun 24, 2021
1 parent 0946bbc commit 3b6a83a
Show file tree
Hide file tree
Showing 43 changed files with 1,433 additions and 188 deletions.
Empty file.
50 changes: 50 additions & 0 deletions exabel_data_sdk/client/api/api_client/entity_api_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from abc import ABC, abstractmethod

from exabel_data_sdk.stubs.exabel.api.data.v1.all_pb2 import (
CreateEntityRequest,
DeleteEntityRequest,
Entity,
EntityType,
GetEntityRequest,
GetEntityTypeRequest,
ListEntitiesRequest,
ListEntitiesResponse,
ListEntityTypesRequest,
ListEntityTypesResponse,
SearchEntitiesRequest,
SearchEntitiesResponse,
)


class EntityApiClient(ABC):
"""
Superclass for clients that send entity requests to the Exabel Data API.
"""

@abstractmethod
def list_entity_types(self, request: ListEntityTypesRequest) -> ListEntityTypesResponse:
"""List all known entity types."""

@abstractmethod
def get_entity_type(self, request: GetEntityTypeRequest) -> EntityType:
"""Get an entity type."""

@abstractmethod
def list_entities(self, request: ListEntitiesRequest) -> ListEntitiesResponse:
"""List all entities of a given entity type."""

@abstractmethod
def get_entity(self, request: GetEntityRequest) -> Entity:
"""Get an entity."""

@abstractmethod
def create_entity(self, request: CreateEntityRequest) -> Entity:
"""Create an entity."""

@abstractmethod
def delete_entity(self, request: DeleteEntityRequest) -> None:
"""Delete an entity."""

@abstractmethod
def search_entities(self, request: SearchEntitiesRequest) -> SearchEntitiesResponse:
"""Search for entities."""
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
from exabel_data_sdk.client.client_config import ClientConfig


class BaseApi:
class BaseGrpcClient:
"""
Base class for API classes.
Base class for clients that access the Exabel Data API with gRPC.
"""

def __init__(self, config: ClientConfig):
Expand Down
61 changes: 61 additions & 0 deletions exabel_data_sdk/client/api/api_client/grpc/entity_grpc_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from exabel_data_sdk.client.api.api_client.entity_api_client import EntityApiClient
from exabel_data_sdk.client.api.api_client.grpc.base_grpc_client import BaseGrpcClient
from exabel_data_sdk.client.api.error_handler import handle_grpc_error
from exabel_data_sdk.client.client_config import ClientConfig
from exabel_data_sdk.stubs.exabel.api.data.v1.all_pb2 import (
CreateEntityRequest,
DeleteEntityRequest,
Entity,
EntityType,
GetEntityRequest,
GetEntityTypeRequest,
ListEntitiesRequest,
ListEntitiesResponse,
ListEntityTypesRequest,
ListEntityTypesResponse,
SearchEntitiesRequest,
SearchEntitiesResponse,
)
from exabel_data_sdk.stubs.exabel.api.data.v1.all_pb2_grpc import EntityServiceStub


class EntityGrpcClient(EntityApiClient, BaseGrpcClient):
"""
Client which sends entity requests to the Exabel Data API with gRPC.
"""

def __init__(self, config: ClientConfig):
super().__init__(config)
self.stub = EntityServiceStub(self.channel)

@handle_grpc_error
def list_entity_types(self, request: ListEntityTypesRequest) -> ListEntityTypesResponse:
return self.stub.ListEntityTypes(
request, metadata=self.metadata, timeout=self.config.timeout
)

@handle_grpc_error
def get_entity_type(self, request: GetEntityTypeRequest) -> EntityType:
return self.stub.GetEntityType(request, metadata=self.metadata, timeout=self.config.timeout)

@handle_grpc_error
def list_entities(self, request: ListEntitiesRequest) -> ListEntitiesResponse:
return self.stub.ListEntities(request, metadata=self.metadata, timeout=self.config.timeout)

@handle_grpc_error
def get_entity(self, request: GetEntityRequest) -> Entity:
return self.stub.GetEntity(request, metadata=self.metadata, timeout=self.config.timeout)

@handle_grpc_error
def create_entity(self, request: CreateEntityRequest) -> Entity:
return self.stub.CreateEntity(request, metadata=self.metadata, timeout=self.config.timeout)

@handle_grpc_error
def delete_entity(self, request: DeleteEntityRequest) -> None:
self.stub.DeleteEntity(request, metadata=self.metadata, timeout=self.config.timeout)

@handle_grpc_error
def search_entities(self, request: SearchEntitiesRequest) -> SearchEntitiesResponse:
return self.stub.SearchEntities(
request, metadata=self.metadata, timeout=self.config.timeout
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from exabel_data_sdk.client.api.api_client.grpc.base_grpc_client import BaseGrpcClient
from exabel_data_sdk.client.api.api_client.relationship_api_client import RelationshipApiClient
from exabel_data_sdk.client.api.error_handler import handle_grpc_error
from exabel_data_sdk.client.client_config import ClientConfig
from exabel_data_sdk.stubs.exabel.api.data.v1.all_pb2 import (
CreateRelationshipRequest,
CreateRelationshipTypeRequest,
DeleteRelationshipRequest,
DeleteRelationshipTypeRequest,
GetRelationshipRequest,
GetRelationshipTypeRequest,
ListRelationshipsRequest,
ListRelationshipsResponse,
ListRelationshipTypesRequest,
ListRelationshipTypesResponse,
Relationship,
RelationshipType,
)
from exabel_data_sdk.stubs.exabel.api.data.v1.all_pb2_grpc import RelationshipServiceStub


class RelationshipGrpcClient(RelationshipApiClient, BaseGrpcClient):
"""
Client which sends relationship requests to the Exabel Data API with gRPC.
"""

def __init__(self, config: ClientConfig):
super().__init__(config)
self.stub = RelationshipServiceStub(self.channel)

@handle_grpc_error
def list_relationship_types(
self, request: ListRelationshipTypesRequest
) -> ListRelationshipTypesResponse:
return self.stub.ListRelationshipTypes(
request, metadata=self.metadata, timeout=self.config.timeout
)

@handle_grpc_error
def get_relationship_type(self, request: GetRelationshipTypeRequest) -> RelationshipType:
return self.stub.GetRelationshipType(
request, metadata=self.metadata, timeout=self.config.timeout
)

@handle_grpc_error
def create_relationship_type(self, request: CreateRelationshipTypeRequest) -> RelationshipType:
return self.stub.CreateRelationshipType(
request, metadata=self.metadata, timeout=self.config.timeout
)

@handle_grpc_error
def delete_relationship_type(self, request: DeleteRelationshipTypeRequest) -> None:
return self.stub.DeleteRelationshipType(
request, metadata=self.metadata, timeout=self.config.timeout
)

@handle_grpc_error
def list_relationships(self, request: ListRelationshipsRequest) -> ListRelationshipsResponse:
return self.stub.ListRelationships(
request, metadata=self.metadata, timeout=self.config.timeout
)

@handle_grpc_error
def get_relationship(self, request: GetRelationshipRequest) -> Relationship:
return self.stub.GetRelationship(
request, metadata=self.metadata, timeout=self.config.timeout
)

@handle_grpc_error
def create_relationship(self, request: CreateRelationshipRequest) -> Relationship:
return self.stub.CreateRelationship(
request, metadata=self.metadata, timeout=self.config.timeout
)

@handle_grpc_error
def delete_relationship(self, request: DeleteRelationshipRequest) -> None:
self.stub.DeleteRelationship(request, metadata=self.metadata, timeout=self.config.timeout)
55 changes: 55 additions & 0 deletions exabel_data_sdk/client/api/api_client/grpc/signal_grpc_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from exabel_data_sdk.client.api.api_client.grpc.base_grpc_client import BaseGrpcClient
from exabel_data_sdk.client.api.api_client.signal_api_client import SignalApiClient
from exabel_data_sdk.client.api.error_handler import handle_grpc_error
from exabel_data_sdk.client.client_config import ClientConfig
from exabel_data_sdk.stubs.exabel.api.data.v1.all_pb2 import (
CreateSignalRequest,
DeleteSignalRequest,
GetSignalRequest,
ListSignalsRequest,
ListSignalsResponse,
Signal,
)
from exabel_data_sdk.stubs.exabel.api.data.v1.all_pb2_grpc import SignalServiceStub


class SignalGrpcClient(SignalApiClient, BaseGrpcClient):
"""
Client which sends signal requests to the Exabel Data API with gRPC.
"""

def __init__(self, config: ClientConfig):
super().__init__(config)
self.stub = SignalServiceStub(self.channel)

@handle_grpc_error
def list_signals(self, request: ListSignalsRequest) -> ListSignalsResponse:
return self.stub.ListSignals(
request,
metadata=self.metadata,
timeout=self.config.timeout,
)

@handle_grpc_error
def get_signal(self, request: GetSignalRequest) -> Signal:
return self.stub.GetSignal(
request,
metadata=self.metadata,
timeout=self.config.timeout,
)

@handle_grpc_error
def create_signal(self, request: CreateSignalRequest) -> Signal:
return self.stub.CreateSignal(
request,
metadata=self.metadata,
timeout=self.config.timeout,
)

@handle_grpc_error
def delete_signal(self, request: DeleteSignalRequest) -> None:
self.stub.DeleteSignal(
request,
metadata=self.metadata,
timeout=self.config.timeout,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from exabel_data_sdk.client.api.api_client.grpc.base_grpc_client import BaseGrpcClient
from exabel_data_sdk.client.api.api_client.time_series_api_client import TimeSeriesApiClient
from exabel_data_sdk.client.api.error_handler import handle_grpc_error
from exabel_data_sdk.client.client_config import ClientConfig
from exabel_data_sdk.stubs.exabel.api.data.v1.all_pb2 import (
BatchDeleteTimeSeriesPointsRequest,
CreateTimeSeriesRequest,
DeleteTimeSeriesRequest,
GetTimeSeriesRequest,
ListTimeSeriesRequest,
ListTimeSeriesResponse,
TimeSeries,
UpdateTimeSeriesRequest,
)
from exabel_data_sdk.stubs.exabel.api.data.v1.all_pb2_grpc import TimeSeriesServiceStub


class TimeSeriesGrpcClient(TimeSeriesApiClient, BaseGrpcClient):
"""
Client which sends time series requests to the Exabel Data API with gRPC.
"""

def __init__(self, config: ClientConfig):
super().__init__(config)
self.stub = TimeSeriesServiceStub(self.channel)

@handle_grpc_error
def list_time_series(self, request: ListTimeSeriesRequest) -> ListTimeSeriesResponse:
return self.stub.ListTimeSeries(
request, metadata=self.metadata, timeout=self.config.timeout
)

@handle_grpc_error
def get_time_series(self, request: GetTimeSeriesRequest) -> TimeSeries:
return self.stub.GetTimeSeries(request, metadata=self.metadata, timeout=self.config.timeout)

@handle_grpc_error
def create_time_series(self, request: CreateTimeSeriesRequest) -> TimeSeries:
return self.stub.CreateTimeSeries(
request, metadata=self.metadata, timeout=self.config.timeout
)

@handle_grpc_error
def update_time_series(self, request: UpdateTimeSeriesRequest) -> TimeSeries:
return self.stub.UpdateTimeSeries(
request, metadata=self.metadata, timeout=self.config.timeout
)

@handle_grpc_error
def delete_time_series(self, request: DeleteTimeSeriesRequest) -> None:
self.stub.DeleteTimeSeries(request, metadata=self.metadata, timeout=self.config.timeout)

@handle_grpc_error
def batch_delete_time_series_points(self, request: BatchDeleteTimeSeriesPointsRequest) -> None:
self.stub.BatchDeleteTimeSeriesPoints(
request, metadata=self.metadata, timeout=self.config.timeout
)
Empty file.
50 changes: 50 additions & 0 deletions exabel_data_sdk/client/api/api_client/http/base_http_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import json
from typing import Optional, TypeVar, overload

import requests
from google.protobuf.json_format import MessageToJson, Parse
from google.protobuf.message import Message

from exabel_data_sdk.client.api.data_classes.request_error import RequestError
from exabel_data_sdk.client.api.error_handler import http_status_to_error_type
from exabel_data_sdk.client.client_config import ClientConfig

TMessage = TypeVar("TMessage", bound=Message)


class BaseHttpClient:
"""
Base class for clients that access the Exabel Data API with JSON over HTTP.
"""

def __init__(self, config: ClientConfig):
self.config = config

@overload
def _request(
self, method: str, url: str, response_proto: TMessage, body: Message = None
) -> TMessage:
...

@overload
def _request(self, method: str, url: str, response_proto: None, body: Message = None) -> None:
...

def _request(
self, method: str, url: str, response_proto: Optional[TMessage], body: Message = None
) -> Optional[TMessage]:
response = requests.request(
method,
f"https://{self.config.host}/v1/{url}",
data=MessageToJson(body) if body is not None else None,
headers={
"Accept": "application/json",
"X-Api-Key": self.config.api_key,
},
)
if response.status_code != 200:
values = json.loads(response.content)
raise RequestError(http_status_to_error_type(response.status_code), values["message"])
if response_proto is None:
return None
return Parse(response.content, response_proto)
Loading

0 comments on commit 3b6a83a

Please sign in to comment.