Skip to content

Commit

Permalink
Merge pull request #49 from stealthrocket/improve-error-messages
Browse files Browse the repository at this point in the history
improve error messages
  • Loading branch information
achille-roussel authored Feb 14, 2024
2 parents bd73ced + 5177e2a commit dee029e
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 29 deletions.
12 changes: 8 additions & 4 deletions src/dispatch/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,28 @@ def __init__(self, api_key: None | str = None, api_url: None | str = None):
api_url: The URL of the Dispatch API to use. Uses the value of the
DISPATCH_API_URL environment variable if set, otherwise
defaults to the public Dispatch API (DEFAULT_DISPATCH_API_URL).
defaults to the public Dispatch API (DEFAULT_API_URL).
Raises:
ValueError: if the API key is missing.
"""

if not api_key:
api_key = os.environ.get("DISPATCH_API_KEY")
if not api_key:
raise ValueError("api_key is required")
raise ValueError(
"missing API key: set it with the DISPATCH_API_KEY environment variable"
)

if not api_url:
api_url = os.environ.get("DISPATCH_API_URL", DEFAULT_API_URL)
if not api_url:
raise ValueError("api_url is required")
raise ValueError(
"missing API URL: set it with the DISPATCH_API_URL environment variable"
)

self.api_url = api_url
self.api_key = api_key

self._init_stub()

def __getstate__(self):
Expand Down
35 changes: 19 additions & 16 deletions src/dispatch/fastapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def read_root():
from http_message_signatures import InvalidSignature
from httpx import _urlparse

from dispatch.client import DEFAULT_API_URL, Client
from dispatch.client import Client
from dispatch.function import Registry
from dispatch.proto import Input
from dispatch.sdk.v1 import function_pb2 as function_pb
Expand Down Expand Up @@ -70,24 +70,32 @@ def __init__(
the value of the DISPATCH_VERIFICATION_KEY environment variable
by default. The environment variable is expected to carry an
Ed25519 public key in base64 or PEM format.
If not set, request signature verification is disabled (a warning
will be logged by the constructor).
api_key: Dispatch API key to use for authentication. Uses the value of
the DISPATCH_API_KEY environment variable by default.
api_url: The URL of the Dispatch API to use. Uses the value of the
DISPATCH_API_URL environment variable if set, otherwise
defaults to the public Dispatch API (DEFAULT_DISPATCH_API_URL).
defaults to the public Dispatch API (DEFAULT_API_URL).
Raises:
ValueError: If any of the required arguments are missing.
"""
if not app:
raise ValueError("app is required")
raise ValueError(
"missing FastAPI app as first argument of the Dispatch constructor"
)

endpoint_from = "endpoint argument"
if not endpoint:
endpoint = os.getenv("DISPATCH_ENDPOINT_URL")
endpoint_from = "DISPATCH_ENDPOINT_URL"
if not endpoint:
raise ValueError("endpoint is required")
raise ValueError(
"missing application endpoint: set it with the DISPATCH_ENDPOINT_URL environment variable"
)

if not verification_key:
try:
Expand All @@ -108,27 +116,22 @@ def __init__(

parsed_url = _urlparse.urlparse(endpoint)
if not parsed_url.netloc or not parsed_url.scheme:
raise ValueError("endpoint must be a full URL with protocol and domain")
raise ValueError(
f"{endpoint_from} must be a full URL with protocol and domain (e.g., https://example.com)"
)

if verification_key:
base64_key = base64.b64encode(verification_key.public_bytes_raw()).decode()
logger.info("verifying request signatures using key %s", base64_key)
else:
logger.warning("request verification is disabled")

if not api_key:
api_key = os.environ.get("DISPATCH_API_KEY")
if not api_url:
api_url = os.environ.get("DISPATCH_API_URL", DEFAULT_API_URL)

client = (
Client(api_key=api_key, api_url=api_url) if api_key and api_url else None
)
logger.warning(
"request verification is disabled because DISPATCH_VERIFICATION_KEY is not set"
)

client = Client(api_key=api_key, api_url=api_url)
super().__init__(endpoint, client)

function_service = _new_app(self, verification_key)

app.mount("/dispatch.sdk.v1.FunctionService", function_service)


Expand Down
5 changes: 4 additions & 1 deletion tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ def test_api_key_from_env(self):
def test_api_key_missing(self):
with self.assertRaises(ValueError) as mc:
Client()
self.assertEqual(str(mc.exception), "api_key is required")
self.assertEqual(
str(mc.exception),
"missing API key: set it with the DISPATCH_API_KEY environment variable",
)

def test_url_bad_scheme(self):
with self.assertRaises(ValueError) as mc:
Expand Down
24 changes: 17 additions & 7 deletions tests/test_fastapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,19 @@
from . import function_service


def create_dispatch_instance(app, endpoint):
return Dispatch(
app,
endpoint=endpoint,
api_key="0000000000000000",
api_url="http://127.0.0.1:10000",
)


class TestFastAPI(unittest.TestCase):
def test_Dispatch(self):
app = fastapi.FastAPI()

Dispatch(app, endpoint="https://127.0.0.1:9999")
create_dispatch_instance(app, "https://127.0.0.1:9999")

@app.get("/")
def read_root():
Expand All @@ -42,21 +50,21 @@ def read_root():

def test_Dispatch_no_app(self):
with self.assertRaises(ValueError):
Dispatch(None, endpoint="http://127.0.0.1:9999")
create_dispatch_instance(None, endpoint="http://127.0.0.1:9999")

def test_Dispatch_no_endpoint(self):
app = fastapi.FastAPI()
with self.assertRaises(ValueError):
Dispatch(app, endpoint="")
create_dispatch_instance(app, endpoint="")

def test_Dispatch_endpoint_no_scheme(self):
app = fastapi.FastAPI()
with self.assertRaises(ValueError):
Dispatch(app, endpoint="127.0.0.1:9999")
create_dispatch_instance(app, endpoint="127.0.0.1:9999")

def test_fastapi_simple_request(self):
app = fastapi.FastAPI()
dispatch = Dispatch(app, endpoint="http://127.0.0.1:9999/")
dispatch = create_dispatch_instance(app, endpoint="http://127.0.0.1:9999/")

@dispatch.primitive_function()
def my_function(input: Input) -> Output:
Expand Down Expand Up @@ -101,7 +109,9 @@ def setUp(self):
def root():
return "OK"

self.dispatch = Dispatch(self.app, endpoint="https://127.0.0.1:9999")
self.dispatch = create_dispatch_instance(
self.app, endpoint="https://127.0.0.1:9999"
)
self.http_client = TestClient(self.app)
self.client = function_service.client(self.http_client)

Expand Down
6 changes: 5 additions & 1 deletion tests/test_full.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ class TestFullFastapi(unittest.TestCase):
def setUp(self):
self.app = fastapi.FastAPI()
self.dispatch = Dispatch(
self.app, endpoint="http://function-service", verification_key=public_key
self.app,
endpoint="http://function-service",
verification_key=public_key,
api_key="0000000000000000",
api_url="http://127.0.0.1:10000",
)

http_client = TestClient(self.app, base_url="http://dispatch-service")
Expand Down

0 comments on commit dee029e

Please sign in to comment.