Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support JSON requests over HTTP #28

Merged
merged 2 commits into from
Jun 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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