Skip to content
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
1 change: 1 addition & 0 deletions python/changelog.d/+optional-rest-api-key.fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Allowed `RestConfig` to omit `api_key`, creating a REST client without a default `Authorization` header.
9 changes: 6 additions & 3 deletions python/lib/sift_client/_internal/rest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

from abc import ABC
from typing import TypedDict

Expand All @@ -15,7 +17,7 @@ class SiftRestConfig(TypedDict):
"""
Config class used to to interact with services that use Sift's REST API.`.
- `uri`: The URI of Sift's REST API. The scheme portion of the URI i.e. `https://` should be ommitted.
- `apikey`: User-generated API key generated via the Sift application.
- `apikey`: User-generated API key, or None to omit the Authorization header.
- `retry`: Urllib3 Retry configuration. If not provided, a default of 3 retries is used.
- `use_ssl`: INTERNAL USE. Meant to be used for local development.
- `cert_via_openssl`: Enable this if you want to use OpenSSL to load the certificates.
Expand All @@ -24,7 +26,7 @@ class SiftRestConfig(TypedDict):
"""

uri: str
apikey: str
apikey: str | None
retry: NotRequired[Retry]
use_ssl: NotRequired[bool]
cert_via_openssl: NotRequired[bool]
Expand Down Expand Up @@ -75,7 +77,8 @@ def __init__(self, rest_conf: SiftRestConfig):
self._apikey = rest_conf["apikey"]

self._session = requests.Session()
self._session.headers = {"Authorization": f"Bearer {self._apikey}"}
if self._apikey is not None:
self._session.headers = {"Authorization": f"Bearer {self._apikey}"}

adapter = _SiftHTTPAdapter(rest_conf)
self._session.mount("https://", adapter)
Expand Down
28 changes: 28 additions & 0 deletions python/lib/sift_client/_tests/_internal/test_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import threading

import pytest
import requests

from sift_client._internal.grpc_transport.transport import (
_compute_channel_options,
Expand Down Expand Up @@ -114,6 +115,33 @@ def test_url_keeps_http(self):
assert config.base_url == "http://rest.sift.com"


class TestRestAuthentication:
@pytest.mark.parametrize(
("config_kwargs", "expected_authorization"),
[
({}, None),
({"api_key": None}, None),
({"api_key": "api"}, "Bearer api"),
({"api_key": ""}, "Bearer "),
],
)
def test_authorization_header(self, config_kwargs, expected_authorization):
client = RestClient(RestConfig(base_url="https://vendor.example", **config_kwargs))
with client._client._session as session:
request = session.prepare_request(requests.Request("GET", client.base_url))
assert request.headers.get("Authorization") == expected_authorization

def test_custom_authorization_without_api_key(self):
client = RestClient(RestConfig(base_url="https://vendor.example"))
with client._client._session as session:
request = session.prepare_request(
requests.Request(
"GET", client.base_url, headers={"Authorization": "Basic vendor-credential"}
)
)
assert request.headers["Authorization"] == "Basic vendor-credential"


class TestRestRequestTimeout:
"""The REST client applies a default per-request timeout so a stalled socket
fails fast instead of blocking the calling thread forever.
Expand Down
4 changes: 2 additions & 2 deletions python/lib/sift_client/transport/rest_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class RestConfig:
def __init__(
self,
base_url: str,
api_key: str,
api_key: str | None = None,
use_ssl: bool = True,
cert_via_openssl: bool = False,
retry: Retry = _DEFAULT_REST_RETRY,
Expand All @@ -41,7 +41,7 @@ def __init__(

Args:
base_url: The base URL of the API.
api_key: The API key for authentication.
api_key: The API key for authentication. None omits the Authorization header.
use_ssl: Whether to use HTTPS.
cert_via_openssl: Whether to use OpenSSL for SSL/TLS.
retry: The retry configuration for requests.
Expand Down
Loading