sdk-rust/src/binding/axum/mod.rs

163 lines
4.6 KiB
Rust

//! This module integrates the [cloudevents-sdk](https://docs.rs/cloudevents-sdk) with [Axum web service framework](https://docs.rs/axum/)
//! to easily send and receive CloudEvents.
//!
//! To deserialize an HTTP request as CloudEvent
//!
//! To echo events:
//!
//! ```
//! use axum_lib as axum;
//! use axum::{
//! routing::{get, post},
//! Router,
//! };
//! use cloudevents::Event;
//! use http::StatusCode;
//!
//! fn app() -> Router {
//! Router::new()
//! .route("/", get(|| async { "hello from cloudevents server" }))
//! .route(
//! "/",
//! post(|event: Event| async move {
//! println!("received cloudevent {}", &event);
//! (StatusCode::OK, event)
//! }),
//! )
//! }
//!
//! ```
//!
//! To create event inside request handlers and send them as responses:
//!
//! ```
//! use axum_lib as axum;
//! use axum::{
//! routing::{get, post},
//! Router,
//! };
//! use cloudevents::{Event, EventBuilder, EventBuilderV10};
//! use http::StatusCode;
//! use serde_json::json;
//!
//! fn app() -> Router {
//! Router::new()
//! .route("/", get(|| async { "hello from cloudevents server" }))
//! .route(
//! "/",
//! post(|| async move {
//! let event = EventBuilderV10::new()
//! .id("1")
//! .source("url://example_response/")
//! .ty("example.ce")
//! .data(
//! mime::APPLICATION_JSON.to_string(),
//! json!({
//! "name": "John Doe",
//! "age": 43,
//! "phones": [
//! "+44 1234567",
//! "+44 2345678"
//! ]
//! }),
//! )
//! .build()
//! .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
//!
//! Ok::<Event, (StatusCode, String)>(event)
//! }),
//! )
//! }
//!
//! ```
pub mod extract;
pub mod response;
#[cfg(test)]
mod tests {
use axum_lib as axum;
use axum::{
body::Body,
http::{self, Request, StatusCode},
routing::{get, post},
Router,
};
use chrono::Utc;
use serde_json::json;
use tower::ServiceExt; // for `app.oneshot()`
use crate::Event;
fn echo_app() -> Router {
Router::new()
.route("/", get(|| async { "hello from cloudevents server" }))
.route(
"/",
post(|event: Event| async move {
println!("received cloudevent {}", &event);
(StatusCode::OK, event)
}),
)
}
#[tokio::test]
async fn axum_mod_test() {
let app = echo_app();
let time = Utc::now();
let j = json!({"hello": "world"});
let request = Request::builder()
.method(http::Method::POST)
.header("ce-specversion", "1.0")
.header("ce-id", "0001")
.header("ce-type", "example.test")
.header("ce-source", "http://localhost/")
.header("ce-someint", "10")
.header("ce-time", time.to_rfc3339())
.header("content-type", "application/json")
.body(Body::from(serde_json::to_vec(&j).unwrap()))
.unwrap();
let resp = app.oneshot(request).await.unwrap();
assert_eq!(
resp.headers()
.get("ce-specversion")
.unwrap()
.to_str()
.unwrap(),
"1.0"
);
assert_eq!(
resp.headers().get("ce-id").unwrap().to_str().unwrap(),
"0001"
);
assert_eq!(
resp.headers().get("ce-type").unwrap().to_str().unwrap(),
"example.test"
);
assert_eq!(
resp.headers().get("ce-source").unwrap().to_str().unwrap(),
"http://localhost/"
);
assert_eq!(
resp.headers()
.get("content-type")
.unwrap()
.to_str()
.unwrap(),
"application/json"
);
assert_eq!(
resp.headers().get("ce-someint").unwrap().to_str().unwrap(),
"10"
);
let (_, body) = resp.into_parts();
let body = axum::body::to_bytes(body, usize::MAX).await.unwrap();
assert_eq!(j.to_string().as_bytes(), body);
}
}