Metadata-Version: 2.4
Name: ebms-adapter-client
Version: 0.2.0
Summary: Python client for the ebms-core (eluinstra/ebms-core) REST API.
Author: Worth Systems
License-Expression: MIT
Project-URL: Homepage, https://github.com/Worth-NL/ebms-adapter-client
Project-URL: Repository, https://github.com/Worth-NL/ebms-adapter-client
Project-URL: Issues, https://github.com/Worth-NL/ebms-adapter-client/issues
Project-URL: Changelog, https://github.com/Worth-NL/ebms-adapter-client/blob/main/CHANGELOG.md
Keywords: ebms,ebms-core,berichtenbox
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.27.0
Requires-Dist: defusedxml>=0.7.1
Dynamic: license-file

# ebms-adapter-client

<p align="center">
  <a href="https://pypi.org/project/ebms-adapter-client/"><img alt="PyPI" src="https://img.shields.io/pypi/v/ebms-adapter-client.svg?style=for-the-badge&logo=pypi&logoColor=white"></a>
  <a href="https://pypi.org/project/ebms-adapter-client/"><img alt="Python versions" src="https://img.shields.io/pypi/pyversions/ebms-adapter-client.svg?style=for-the-badge&logo=python&logoColor=white"></a>
  <a href="https://github.com/Worth-NL/ebms-adapter-client/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/Worth-NL/ebms-adapter-client/ci.yml?style=for-the-badge&logo=githubactions&logoColor=white"></a>
  <a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-yellow.svg?style=for-the-badge&logo=opensourceinitiative&logoColor=white"></a>
  <a href="https://github.com/astral-sh/uv"><img alt="uv" src="https://img.shields.io/endpoint?style=for-the-badge&url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json"></a>
  <a href="https://github.com/astral-sh/ruff"><img alt="Ruff" src="https://img.shields.io/endpoint?style=for-the-badge&url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json"></a>
  <a href="https://mijn.overheid.nl/"><img alt="mijn | overheid" src="https://img.shields.io/badge/mijn-overheid-f3f3f3?style=for-the-badge&labelColor=154273"></a>
</p>

A minimal Python client for the REST API exposed by
[eluinstra/ebms-core](https://github.com/eluinstra/ebms-core) (branch
`ebms-core-2.20.x`), an ebMS (Electronic Business Messaging Service)
adapter/core used to send and receive ebMS messages between trading
partners.

> [!NOTE] 
> This package only talks to ebms-core's HTTP/JSON REST API — it doesn't implement ebMS/SOAP itself.

## Endpoint coverage

ebms-core mounts its REST API at `{base_url}/service/rest/v19/...` (see
`EmbeddedWebConfig.java`/`Start.java` in the sibling `ebms-admin` repo, which
is what actually deploys `ebms-core`). Four JSON resource groups are covered:

- `/cpas` — Collaboration Protocol Agreement (CPA) management
- `/urlMappings` — URL mapping management
- `/certificateMappings` — certificate mapping management
- `/ebms` — message submission, retrieval, status, and event polling

The MTOM/multipart variants (`POST /ebms/messages/mtom`,
`GET /ebms/messages/mtom/{messageId}`) are intentionally **not** implemented —
the JSON `DataSource` model (Base64-encoded `content`) covers attachments for
the plain JSON endpoints.

## Installation

```bash
pip install ebms-adapter-client
```

## Usage

```python
from ebms_adapter_client import (
    DataSource,
    EbmsAdapterClient,
    EbmsAdapterClientConfig,
    MessageRequest,
    MessageRequestProperties,
)

config = EbmsAdapterClientConfig(
    base_url="http://localhost:8080",
    username="user", # omit if the server runs without --authentication
    password="pass",
)

with EbmsAdapterClient(config) as client:
    message_id = client.send_message(
        MessageRequest(
            properties=MessageRequestProperties(
                cpa_id="cpa-1",
                from_party_id="party-a",
                service="my-service",
                action="my-action",
            ),
            data_sources=[
                DataSource(content_type="application/pdf", content=b"...", name="letter.pdf"),
            ],
        )
    )

    status = client.get_message_status(message_id)
```

### Configuration

`EbmsAdapterClientConfig` builds the full API base URL as
`{base_url}{service_path}{api_path}`, defaulting to `/service` + `/rest/v19`
to match ebms-admin's default wiring. Override `service_path`/`api_path` if a
reverse proxy changes that layout.

### Auth

- No credentials (`username=None`) → no `Authorization` header is sent,
  matching a server started without `--authentication`.
- `username`/`password` set → HTTP Basic Auth, matching a server started with
  `--authentication` (without `--clientAuthentication`).
- Mutual TLS (`--authentication --ssl --clientAuthentication`) is not wired up
  yet; pass a preconfigured `httpx.Client` (with `cert=`) via the
  `http_client` constructor argument if needed.

### Error handling

All non-2xx responses raise a subclass of `EbmsAdapterError`
(`ebms_adapter_client.exceptions`):

- `EbmsNotFoundError` — HTTP 404
- `EbmsBadRequestError` — HTTP 400 (message text carries the server's error)
- `EbmsServerError` — HTTP 5xx
- `EbmsConnectionError` — the server could not be reached at all

## Development

```bash
uv sync --all-groups
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv run mypy src
```

See [CONTRIBUTING.md](CONTRIBUTING.md) for more.
