From d45811604d993e6f44cb3f4410eeee41528735cc Mon Sep 17 00:00:00 2001 From: Jim Crossley Date: Fri, 25 Jun 2021 13:54:50 -0400 Subject: [PATCH] Implement actix-web FromRequest and Responder Fixes #130 I'm not entirely sure why this works, but the compiler seems to like it! :D The example is intentionally as simple as it gets, but a "real" app should probably return Result from its handlers. Signed-off-by: Jim Crossley --- .../actix-web-example/src/main.rs | 32 ++++++++----------- src/actix/server_request.rs | 16 +++++++++- src/actix/server_response.rs | 14 +++++++- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/example-projects/actix-web-example/src/main.rs b/example-projects/actix-web-example/src/main.rs index 8abc291..e35202c 100644 --- a/example-projects/actix-web-example/src/main.rs +++ b/example-projects/actix-web-example/src/main.rs @@ -1,31 +1,25 @@ -use actix_web::{get, post, web, App, HttpRequest, HttpResponse, HttpServer}; -use cloudevents::actix::{HttpRequestExt, HttpResponseBuilderExt}; -use cloudevents::{EventBuilder, EventBuilderV10}; +use actix_web::{get, post, App, HttpServer}; +use cloudevents::{Event, EventBuilder, EventBuilderV10}; use serde_json::json; #[post("/")] -async fn post_event(req: HttpRequest, payload: web::Payload) -> Result { - let event = req.to_event(payload).await?; +async fn post_event(event: Event) -> Event { println!("Received Event: {:?}", event); - Ok(format!("{:?}", event)) + event } #[get("/")] -async fn get_event() -> Result { +async fn get_event() -> Event { let payload = json!({"hello": "world"}); - Ok(HttpResponse::Ok() - .event( - EventBuilderV10::new() - .id("0001") - .ty("example.test") - .source("http://localhost/") - .data("application/json", payload) - .extension("someint", "10") - .build() - .unwrap(), - ) - .await?) + EventBuilderV10::new() + .id("0001") + .ty("example.test") + .source("http://localhost/") + .data("application/json", payload) + .extension("someint", "10") + .build() + .unwrap() } #[actix_web::main] diff --git a/src/actix/server_request.rs b/src/actix/server_request.rs index 8a0e3c2..34bfe91 100644 --- a/src/actix/server_request.rs +++ b/src/actix/server_request.rs @@ -9,7 +9,8 @@ use actix_web::http::HeaderName; use actix_web::web::{Bytes, BytesMut}; use actix_web::{web, HttpMessage, HttpRequest}; use async_trait::async_trait; -use futures::StreamExt; +use futures::future::LocalBoxFuture; +use futures::{FutureExt, StreamExt}; use std::convert::TryFrom; /// Wrapper for [`HttpRequest`] that implements [`MessageDeserializer`] trait. @@ -112,6 +113,19 @@ pub async fn request_to_event( .map_err(actix_web::error::ErrorBadRequest) } +/// So that an actix-web handler may take an Event parameter +impl actix_web::FromRequest for Event { + type Config = (); + type Error = actix_web::Error; + type Future = LocalBoxFuture<'static, std::result::Result>; + + fn from_request(r: &HttpRequest, p: &mut actix_web::dev::Payload) -> Self::Future { + let payload = web::Payload(p.take()); + let request = r.to_owned(); + async move { request_to_event(&request, payload).await }.boxed_local() + } +} + /// Extention Trait for [`HttpRequest`] which acts as a wrapper for the function [`request_to_event()`]. /// /// This trait is sealed and cannot be implemented for types outside of this crate. diff --git a/src/actix/server_response.rs b/src/actix/server_response.rs index eec5f1c..5c68561 100644 --- a/src/actix/server_response.rs +++ b/src/actix/server_response.rs @@ -5,9 +5,11 @@ use crate::message::{ }; use crate::Event; use actix_web::dev::HttpResponseBuilder; -use actix_web::http::{HeaderName, HeaderValue}; +use actix_web::http::{HeaderName, HeaderValue, StatusCode}; use actix_web::HttpResponse; use async_trait::async_trait; +use futures::future::LocalBoxFuture; +use futures::FutureExt; use std::str::FromStr; /// Wrapper for [`HttpResponseBuilder`] that implements [`StructuredSerializer`] and [`BinarySerializer`]. @@ -76,6 +78,16 @@ pub async fn event_to_response( .map_err(actix_web::error::ErrorBadRequest) } +/// So that an actix-web handler may return an Event +impl actix_web::Responder for Event { + type Error = actix_web::Error; + type Future = LocalBoxFuture<'static, std::result::Result>; + + fn respond_to(self, _: &actix_web::HttpRequest) -> Self::Future { + async { HttpResponse::build(StatusCode::OK).event(self).await }.boxed_local() + } +} + /// Extension Trait for [`HttpResponseBuilder`] which acts as a wrapper for the function [`event_to_response()`]. /// /// This trait is sealed and cannot be implemented for types outside of this crate.