Skip to content

feat(core): add JSON Batch format support#299

Open
PlugaruT wants to merge 2 commits into
cloudevents:mainfrom
PlugaruT:feat/json-batch-core
Open

feat(core): add JSON Batch format support#299
PlugaruT wants to merge 2 commits into
cloudevents:mainfrom
PlugaruT:feat/json-batch-core

Conversation

@PlugaruT

Copy link
Copy Markdown
Member

What

Adds support for the CloudEvents JSON Batch format (application/cloudevents-batch+json) to the cloudevents.core package, across the JSON format layer and the HTTP binding.

Batch mode is only defined by the spec for the HTTP protocol binding (via the JSON Batch format); Kafka and AMQP define only structured/binary modes, so this change is intentionally scoped to JSON + HTTP.

Changes

  • formats/json.py: refactor write/read onto shared _event_to_dict/_dict_to_event helpers (no behavior change), then add BATCH_CONTENT_TYPE, write_batch, read_batch, and get_batch_content_type.
  • formats/base.py: extend the Format protocol with write_batch/read_batch/get_batch_content_type so any format implements the same contract.
  • bindings/http.py: add to_batch/from_batch plus the to_batch_event/from_batch_event JSON-default wrappers; from_http now rejects batch payloads with a clear, case-insensitive error pointing callers to from_batch.

Behavior

  • Empty array ↔ empty list.
  • Per-element version auto-detection — a batch may mix v0.3 and v1.0 events.
  • Binary data round-trips (data_base64 for v1.0, datacontentencoding: base64 for v0.3).
  • A malformed/invalid element aborts the whole call (no partial results).
  • A non-array body raises ValueError.

Tests

Added coverage for round-trip, empty batch, mixed-version batches, data_base64 elements, invalid-element abort, non-array body, and from_http batch rejection (incl. charset param and mixed-case content type). Full tests/test_core suite passes (356 tests); ruff clean.

Implement the CloudEvents JSON Batch format
(application/cloudevents-batch+json) in the core package.

- formats/json.py: extract shared _event_to_dict/_dict_to_event helpers
  and add BATCH_CONTENT_TYPE, write_batch, read_batch, get_batch_content_type
- formats/base.py: extend the Format protocol with the batch methods
- bindings/http.py: add to_batch/from_batch and to_batch_event/from_batch_event,
  and reject batch payloads in from_http with a clear error
- tests: cover round-trip, empty batch, mixed 0.3/1.0 versions, data_base64,
  invalid-element abort, non-array body, and from_http batch rejection

Signed-off-by: PlugaruT <plugaru.tudor@protonmail.com>
@PlugaruT PlugaruT marked this pull request as ready for review June 27, 2026 14:44
@PlugaruT PlugaruT requested a review from a team June 27, 2026 14:45

@xSAVIKx xSAVIKx left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PlugaruT, please take a look at some comments and suggestions noted below. IMO the biggest part here is to split the Format/BatchFormat to ease future development.

Comment thread src/cloudevents/core/bindings/http.py Outdated
Comment thread src/cloudevents/core/bindings/http.py Outdated
Comment thread src/cloudevents/core/bindings/http.py Outdated
Comment thread src/cloudevents/core/formats/base.py
Comment thread src/cloudevents/core/formats/json.py Outdated
Comment thread src/cloudevents/core/formats/json.py
Comment thread src/cloudevents/core/formats/json.py Outdated
- Split batch methods (write_batch/read_batch/get_batch_content_type)
  out of the Format protocol into a separate, runtime-checkable
  BatchFormat protocol so non-batch formats need not implement batching
  and existing Format implementations keep working.
- Rename HTTP convenience wrappers to_batch_event/from_batch_event to
  to_events_batch/from_events_batch (a batch of events, not a batch event).
- from_http: guard batch detection behind isinstance(BatchFormat),
  compare content types case-insensitively on both sides, and report the
  received vs. expected content type in the error.
- read_batch: include the actual JSON type in the non-array error, reject
  non-object elements, and wrap per-element failures with the element
  index for a clearer error.

Signed-off-by: PlugaruT <plugaru.tudor@protonmail.com>
@PlugaruT PlugaruT force-pushed the feat/json-batch-core branch from 04fc5ed to dc60518 Compare July 8, 2026 20:37
@PlugaruT PlugaruT requested a review from xSAVIKx July 9, 2026 05:52
Comment on lines +339 to +345
content_type = ""
for key, value in message.headers.items():
if key.lower() == CONTENT_TYPE_HEADER:
content_type = value
break

received_content_type = content_type.split(";")[0].strip().lower()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this content_type and received_content_type lines are only relevant if we're processing BatchFormat. Let's move them under the check or better have a private named method.

paths cannot drift.
"""
event_data = event.get_data()
event_dict: dict[str, Any] = dict(event.get_attributes())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
event_dict: dict[str, Any] = dict(event.get_attributes())
event_attributes: dict[str, Any] = dict(event.get_attributes())

event_dict: dict[str, Any] = dict(event.get_attributes())
specversion = event_dict.get("specversion", SPECVERSION_V1_0)

if event_data is not None:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we invert the condition? This way you'll have a fast way out with return event_dict and then just continue processing the branches. this will allow us to get rid of the nesting

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants