elytra_client/README.md

10 KiB

Elytra PIM Client

A fully Pythonic and Pydantic-driven client for the Elytra PIM (Product Information Management) API.

Features

  • 🐍 Fully Pythonic with Pydantic v2 data validation
  • 📦 Auto-generated Pydantic models from OpenAPI specification
  • 🔐 Bearer token authentication
  • Request/Response validation with Pydantic
  • 🌍 Multi-language support
  • 📄 Full type hints throughout the codebase
  • 🧪 Comprehensive error handling
  • 🔄 Context manager support
  • 🔄 Automatic serialization/deserialization

Installation

From Forgejo PyPI

Install directly from the HIM-public package registry:

pip install --index-url https://git.him-tools.de/api/packages/HIM-public/pypi/simple/ elytra-pim-client

From Source

Clone the repository:

git clone https://git.him-tools.de/HIM-public/elytra_client.git
cd elytra_client
pip install -e .

With Development Dependencies

pip install -e ".[dev]"

Quick Start

Basic Usage

from elytra_client import ElytraClient, SingleProductResponse

# Initialize the client
client = ElytraClient(
    base_url="https://example.com/api/v1",
    api_key="your-api-key"
)

# Get all products - returns dict with Pydantic validated items
products_response = client.get_products(lang="en", page=1, limit=10)
for product in products_response["items"]:
    print(f"Product: {product.productName}, ID: {product.id}")

# Get a specific product - returns Pydantic model directly
product: SingleProductResponse = client.get_product(product_id=123, lang="en")
print(f"Name: {product.productName}")
print(f"Status: {product.objectStatus}")

# Close the client
client.close()

Creating Products with Validation

from elytra_client import (
    ElytraClient,
    SingleNewProductRequestBody,
    AttributeRequestBody,
)

with ElytraClient(base_url="https://example.com/api/v1", api_key="your-api-key") as client:
    # Create a new product with validated Pydantic model
    new_product = SingleNewProductRequestBody(
        productName="NEW-PRODUCT-001",
        parentId=1,
        attributeGroupId=10,
        attributes=[
            AttributeRequestBody(
                attributeId=1,
                value="Sample Value",
                languageCode="en"
            )
        ]
    )

    # Validation happens automatically
    created_product = client.create_product(new_product)
    print(f"Created product ID: {created_product.id}")

Environment Variable Configuration

Set your environment variables:

export ELYTRA_BASE_URL="https://example.com/api/v1"
export ELYTRA_API_KEY="your-api-key"
export ELYTRA_TIMEOUT="30"
export ELYTRA_VERIFY_SSL="true"

Then load from environment:

from elytra_client import ElytraClient
from elytra_client.config import ElytraConfig

config = ElytraConfig.from_env()
client = ElytraClient(base_url=config.base_url, api_key=config.api_key)

Legacy REST API (Lobster PIM)

The package also includes a subpackage for the older Lobster PIM REST API, which provides access to scheduled jobs and protocol logs that are not yet available in the newer API.

Quick Start

from elytra_client.rest_api import LobsterRestApiClient, RestApiAuth

# Create authentication
auth = RestApiAuth.from_username_password("username", "password")

# Create client for the REST API
client = LobsterRestApiClient("http://lobster-server:8080", auth=auth)

# Get all active jobs
jobs = client.get_all_active_jobs()
for job in jobs.jobInfoObjects:
    print(f"Job: {job.name} - Status: {job.status}")

# Execute a job
result = client.execute_job(job_id=123)
print(f"Execution started with runtime ID: {result.runtimeId}")

# Get protocol/logs
protocols = client.get_protocols()

Features

  • 📋 Job Management: Access, monitor, and execute scheduled jobs
  • 📜 Protocol/Logs: Retrieve execution logs and protocol information
  • 🔐 Flexible Authentication: Username/password or API token authentication
  • Job Control: Execute jobs with parameter overrides and queue management
  • 🎯 Type Safety: Full Pydantic validation for all responses

Authentication Methods

# Username/Password
auth = RestApiAuth.from_username_password("admin", "password")

# API Token (domain-specific)
auth = RestApiAuth.from_api_token("admin", "token-id", domain="Jobs")

Documentation

See elytra_client/rest_api/README.md for comprehensive REST API documentation, including:

  • Complete API reference
  • Authentication details
  • Job management examples
  • Protocol/log access
  • Error handling
  • Common usage scenarios

Webhooks (Elytra Event API)

The package includes a subpackage for handling CloudEvents-based webhooks from the Elytra PIM Event API.

Quick Start

from elytra_client.webhooks import CloudEvent, parse_webhook_payload

# Parse an incoming webhook payload
event = parse_webhook_payload(request.json())
print(f"Event type: {event.eventtype}")
print(f"Object ID: {event.get_object_id()}")

With Authentication Validation

from elytra_client.webhooks import WebhookValidator, BasicAuth

auth = BasicAuth(username="user", password="pass")
validator = WebhookValidator(auth_type="basic", auth=auth)

event = validator.validate_and_parse(
    payload=request.json(),
    headers=dict(request.headers)
)

Features

  • 📨 CloudEvents Support: Strongly-typed Pydantic models following the CNCF CloudEvents v1.0 spec
  • 🔐 Flexible Authentication: Basic, Bearer token, and API Key authentication
  • 🔀 Event Routing: SimpleWebhookEventDispatcher to route events by type and operation to dedicated handlers
  • 🔁 Retry Logic: Exponential backoff retry policies for reliable webhook delivery
  • 🌐 Framework Integration: Ready-to-use examples for Flask and FastAPI

Authentication Methods

# Basic authentication
auth = BasicAuth(username="admin", password="secret")

# Bearer token
auth = BearerAuth(token="eyJhbGciOiJIUzI1NiIs...")

# API Key (custom header)
auth = APIKeyAuth(api_key="sk_live_secret123", header_name="X-API-Key")

Event Types and Operations

Events carry an EventType (e.g., PRODUCT, PRODUCT_GROUP, PRODUCT_ATTRIBUTE_VALUE) and an Operation (ADD, MODIFY, REMOVE, LINK, UNLINK).

Documentation

See elytra_client/webhooks/README.md for comprehensive webhook documentation, including:

  • Complete API reference
  • Authentication details
  • Event routing and dispatching
  • Retry logic configuration
  • Flask and FastAPI integration examples

API Methods

All methods return Pydantic models with full type validation and IDE autocompletion support.

Products

  • get_products(...) -> Dict - Get all products (items are SingleProductResponse Pydantic models)
  • get_product(id, lang) -> SingleProductResponse - Get single product
  • create_product(data) -> SingleProductResponse - Create new product with validation
  • update_product(data) -> SingleProductResponse - Update product with validation
  • delete_product(id) -> Dict - Delete product

Product Groups

  • get_product_groups(...) -> Dict - Get all product groups (items are SingleProductGroupResponse models)
  • get_product_group(id, lang) -> SingleProductGroupResponse - Get single product group
  • create_product_group(data) -> SingleProductGroupResponse - Create new product group
  • update_product_group(data) -> SingleProductGroupResponse - Update product group
  • delete_product_group(id) -> Dict - Delete product group

Attributes

  • get_attributes(...) -> Dict - Get all attributes (items are SingleAttributeResponse models)
  • get_attribute(id, lang) -> SingleAttributeResponse - Get single attribute

Health Check

  • health_check() -> Dict - Check API health status

Error Handling

The client provides specific exception classes for different error types:

from elytra_client import ElytraClient
from elytra_client.exceptions import (
    ElytraAuthenticationError,
    ElytraNotFoundError,
    ElytraValidationError,
    ElytraAPIError,
)
from pydantic import ValidationError

try:
    client = ElytraClient(base_url="https://example.com/api/v1", api_key="invalid-key")
    product = client.get_product(123)
except ElytraAuthenticationError:
    print("Authentication failed")
except ElytraNotFoundError:
    print("Product not found")
except ElytraValidationError as e:
    print(f"API response validation failed: {e}")
except ValidationError as e:
    print(f"Request model validation failed: {e}")
except ElytraAPIError as e:
    print(f"API error: {e}")

Validation

  • Request validation: Pydantic models validate all input before sending to API
  • Response validation: Pydantic models validate API responses for data integrity
  • Automatic deserialization: Responses are automatically converted to Pydantic models

Pydantic Models

All request and response models are automatically generated from the OpenAPI specification using datamodel-code-generator.

Available Models

  • Response Models: SingleProductResponse, SingleProductGroupResponse, SingleAttributeResponse, etc.
  • Request Models: SingleNewProductRequestBody, SingleUpdateProductRequestBody, SingleNewProductGroupRequestBody, etc.
  • Attribute Models: ProductAttributeResponse, AttributeRequestBody

All models include:

  • Full type hints and validation
  • Documentation from OpenAPI spec
  • IDE autocompletion support
  • Automatic serialization/deserialization

Regenerating Models

To regenerate models from the OpenAPI spec:

python -m datamodel_code_generator --input openapi.yaml --input-file-type openapi --output elytra_client/models.py --target-python-version 3.10

Development

Running Tests

pytest

Code Quality

Format code with Black:

black elytra_client tests

Check with flake8:

flake8 elytra_client tests

Type checking with mypy:

mypy elytra_client

API Documentation

For complete API documentation, refer to the OpenAPI specification in openapi.yaml see here: https://w4services.atlassian.net/wiki/spaces/pimdocext/pages/426803205/Web+API or visit the Elytra website: https://www.elytra.ch/

Contact

For support on this client, please email: info@hoerl-im.de

License

MIT License - see LICENSE file for details