ddd-toolkit
Domain-Driven Design traits and helpers, re-exported from
ddd-toolkit-core 0.4.0,
plus the four derives from
ddd-toolkit-macro 0.4.0.
All public items are available at ddd_toolkit::.
Requires Rust 1.85 or newer (edition 2024).
Installation
For traits and helpers without derive macros:
[]
= { = "0.3", = false }
For derive macros (enabled by default):
[]
= "0.3"
= "0.4.0"
Important: macro 0.4 requires a direct ddd-toolkit-core dependency
in the consuming crate, including when derives are invoked through this
facade. A renamed core dependency is supported. The previous facade-only
installation no longer suffices for derives; re-exporting macros does not
change their dependency resolution.
Facade 0.3.0 adopts core/macro 0.4.0 and contains breaking API changes from facade 0.2. See the migration guide below and CHANGELOG.md.
What's here
Entity,ValueObject,AggregateRoot, andDomainEventtraits and derives.Repository/AsyncRepository,DomainEventPublisher/AsyncDomainEventPublisher, anddispatch_events/dispatch_events_async.- CQRS command/query handlers and lifecycle contexts.
- Event stores, revision types, aggregate replay, and snapshots.
- Event consumption, projections, checkpoints, and transactional outbox contracts.
- Specifications, domain services/policies/factories, process managers, units of work, and event upcasters.
Secret<T>for redacted formatting and zeroization on drop.
Core defines contracts, not storage adapters, clock or ID generators, an async
runtime, or automatic transaction/delivery guarantees. Implement adapters in your
application. Async ports return boxed Send futures without choosing a runtime.
Example
With both dependencies shown above:
;
ValueObject derives Debug, Clone, PartialEq, Eq, and Hash;
do not derive these again. Unvalidated structs use new; validated structs use
try_new. Named/multi-field structs and data-carrying enums are also supported.
Entity derives equality and hashing using only the #[entity(id)] field.
Aggregate event publication
use ;
;
;
Repository persistence and event publication are separate. Repository::save
borrows the aggregate immutably and does not automatically drain pending events.
dispatch_events drains events on success; on publication failure it restores
all pulled events. Already published events are not rolled back, so retrying
may deliver duplicates. Application adapters define transaction guarantees.
Features
| Feature | Default | Enables |
|---|---|---|
derive |
yes | ValueObject, Entity, DomainEvent, AggregateRoot derives; consumers also need core directly |
serde |
no | Core's serde re-export and serde derive support for #[value_object(serde)]; independent of derive |
To serialize a value object, enable the facade's serde feature and opt in on
the type:
;
No direct serde dependency is required for these generated implementations.
Validated deserialization runs the validator and maps failure to
value object validation failed. Enums use externally tagged variants.
When combining serde and validation in one attribute, place the serde flag
last (#[value_object(validate = check, error = Error, serde)]): macro 0.4.0
rejects a flag followed by other options.
Upstream 0.4.0 limitation: a single-field tuple enum variant such as
Code(u32) serializes to {"Code":[7]}, but its generated deserializer expects
{"Code":7}. It cannot round-trip its own JSON. Use a named variant such as
Code { value: u32 } when JSON round-tripping is required.
Clippy 1.99 also reports clippy::redundant_field_names in macro 0.4.0's
named value-object constructors. With -D warnings, consuming modules may need
an allowance for that specific lint until the upstream generator is fixed.
Secret<T> is available without a feature flag and is not automatically serialized.
Calling Secret::into_inner transfers zeroization responsibility to the caller.
Migrating from core/macro 0.3
- Replace
domain,port,adapter,mock, andapplicationmodule paths with root-level imports. Built-in adapters/test doubles andUseCaseare gone. - Replace
EntityId/EnumVoderives with suitableValueObjecttypes;Wrappedis replaced byValueObject'sas_inner/into_innermethods. - Replace
#[vo(validate = "function")]with#[value_object(validate = function, error = YourError)].ValidationErroris gone; choose your own error type. - Replace generated
TryFrom/From/Displayusage with constructors and explicit application implementations where needed. - Replace
SecretVo/#[vo(zeroize)]withSecret<T>. - Replace
record/take_eventswithrecord_event/pull_events. - Replace
Load/Save/DeletewithRepositoryorAsyncRepository, andEventDispatcherwith event publisher contracts.PortErroris gone; adapters choose their own error types. - Remove
chrono,uuid, andzeroizefeature requests. - Add a direct core dependency for derives and opt in to serde per value object.
More details are in the API docs. The
facade-tests integration suite covers custom repositories,
async ports, multi-aggregate flows, publication failure/retry, derives, serde,
and secrets through the facade.
Changelog
See CHANGELOG.md for release history.
License
Licensed under either of Apache License, Version 2.0 or MIT license, at your option.