hedwig/lib.rs
1//! Hedwig is a message bus library that works with arbitrary pubsub services such as AWS SNS/SQS
2//! or Google Cloud Pubsub. Messages are validated before they are published. The publisher and
3//! consumer are de-coupled and fan-out is supported out of the box.
4//!
5//! The Rust library currently only supports publishing.
6//!
7//! # Examples
8//!
9//! Publish a message. Payload encoded with JSON and validated using a JSON Schema.
10//!
11//! ```
12//! use hedwig::{validators, Publisher, Consumer};
13//! # use uuid::Uuid;
14//! # use std::{path::Path, time::SystemTime};
15//! # use futures_util::{sink::SinkExt, stream::StreamExt};
16//! # #[cfg(not(all(feature = "protobuf", feature = "mock")))]
17//! # fn main() {}
18//! # #[cfg(all(feature = "protobuf", feature = "mock"))] // example uses a protobuf validator.
19//! # #[tokio::main(flavor = "current_thread")]
20//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
21//!
22//! #[derive(Clone, PartialEq, Eq, prost::Message)]
23//! struct UserCreatedMessage {
24//! #[prost(string, tag = "1")]
25//! user_id: String,
26//! }
27//!
28//! impl<'a> hedwig::EncodableMessage for UserCreatedMessage {
29//! type Error = validators::ProstValidatorError;
30//! type Validator = validators::ProstValidator;
31//! fn topic(&self) -> hedwig::Topic {
32//! "user.created".into()
33//! }
34//! fn encode(&self, validator: &Self::Validator) -> Result<hedwig::ValidatedMessage, Self::Error> {
35//! Ok(validator.validate(
36//! uuid::Uuid::new_v4(),
37//! SystemTime::now(),
38//! "user.created/1.0",
39//! Default::default(),
40//! self,
41//! )?)
42//! }
43//! }
44//!
45//! impl hedwig::DecodableMessage for UserCreatedMessage {
46//! type Error = validators::ProstDecodeError<validators::prost::SchemaMismatchError>;
47//! type Decoder =
48//! validators::ProstDecoder<validators::prost::ExactSchemaMatcher<UserCreatedMessage>>;
49//!
50//! fn decode(msg: hedwig::ValidatedMessage, decoder: &Self::Decoder) -> Result<Self, Self::Error> {
51//! decoder.decode(msg)
52//! }
53//! }
54//!
55//!
56//! let publisher = /* Some publisher */
57//! # hedwig::mock::MockPublisher::new();
58//! let consumer = /* Consumer associated to that publisher */
59//! # publisher.new_consumer("user.created", "example_subscription");
60//!
61//! let mut publish_sink = Publisher::<UserCreatedMessage>::publish_sink(publisher, validators::ProstValidator::new());
62//! let mut consumer_stream = consumer.consume::<UserCreatedMessage>(
63//! validators::ProstDecoder::new(validators::prost::ExactSchemaMatcher::new("user.created/1.0")),
64//! );
65//!
66//! publish_sink.send(UserCreatedMessage { user_id: String::from("U_123") }).await?;
67//!
68//! assert_eq!(
69//! "U_123",
70//! consumer_stream.next().await.unwrap()?.ack().await?.user_id
71//! );
72//!
73//! # Ok(())
74//! # }
75//! ```
76#![cfg_attr(docsrs, feature(doc_cfg))]
77#![deny(missing_docs)]
78
79pub use hedwig_core::{message, Headers, Topic, ValidatedMessage};
80
81mod backends;
82mod consumer;
83mod publisher;
84mod tests;
85pub mod validators;
86
87#[allow(unused_imports)]
88pub use backends::*;
89
90pub use consumer::*;
91pub use publisher::*;
92
93// TODO make these public somewhere?
94#[cfg(feature = "google")]
95pub(crate) const HEDWIG_ID: &str = "hedwig_id";
96#[cfg(feature = "google")]
97pub(crate) const HEDWIG_MESSAGE_TIMESTAMP: &str = "hedwig_message_timestamp";
98#[cfg(feature = "google")]
99pub(crate) const HEDWIG_SCHEMA: &str = "hedwig_schema";
100#[cfg(feature = "google")]
101pub(crate) const HEDWIG_PUBLISHER: &str = "hedwig_publisher";
102#[cfg(feature = "google")]
103pub(crate) const HEDWIG_FORMAT_VERSION: &str = "hedwig_format_version";
104
105/// All errors that may be returned when operating top level APIs.
106#[derive(Debug, thiserror::Error)]
107#[non_exhaustive]
108pub enum Error {
109 /// Unable to encode message payload
110 #[error("Unable to encode message payload")]
111 EncodeMessage(#[source] Box<dyn std::error::Error + Send + Sync>),
112}