PostgresHandler

Struct PostgresHandler 

Source
pub struct PostgresHandler<TReq = Value, TRes = Value>
where TReq: for<'de> Deserialize<'de> + Serialize + Send + Sync + 'static, TRes: for<'de> Deserialize<'de> + Serialize + Send + Sync + 'static,
{ /* private fields */ }
Expand description

PostgreSQL handler for outlet middleware.

Implements the RequestHandler trait to log HTTP requests and responses to PostgreSQL. Request and response bodies are serialized to JSONB fields.

Generic over TReq and TRes which represent the request and response body types that should implement Deserialize for parsing and Serialize for database storage as JSONB. Use serde_json::Value for flexible JSON storage, or custom structs for typed storage.

Implementations§

Source§

impl<TReq, TRes> PostgresHandler<TReq, TRes>
where TReq: for<'de> Deserialize<'de> + Serialize + Send + Sync + 'static, TRes: for<'de> Deserialize<'de> + Serialize + Send + Sync + 'static,

Source

pub async fn new(database_url: &str) -> Result<Self, PostgresHandlerError>

Create a new PostgreSQL handler with a connection pool.

This will connect to the database but will NOT run migrations. Use migrator() to get a migrator and run migrations separately.

§Arguments
  • database_url - PostgreSQL connection string
§Examples
use outlet_postgres::{PostgresHandler, migrator};
use serde::{Deserialize, Serialize};
use serde_json::Value;

#[derive(Deserialize, Serialize)]
struct MyBodyType {
    id: u64,
    name: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Run migrations first
    let pool = sqlx::PgPool::connect("postgresql://user:pass@localhost/db").await?;
    migrator().run(&pool).await?;
     
    // Create handler
    let handler = PostgresHandler::<MyBodyType, MyBodyType>::new("postgresql://user:pass@localhost/db").await?;
    Ok(())
}
Source

pub fn with_request_serializer<F>(self, serializer: F) -> Self
where F: Fn(&RequestData) -> Result<TReq, SerializationError> + Send + Sync + 'static,

Add a custom request body serializer.

The serializer function takes raw bytes and should return a Result<TReq, String>. If the serializer succeeds, the result will be stored as JSONB and body_parsed will be true. If it fails, the raw content will be stored as a UTF-8 string and body_parsed will be false.

§Panics

This will panic if the serializer succeeds but the resulting TReq value cannot be converted to JSON via serde_json::to_value(). This indicates a bug in the Serialize implementation of TReq and should be fixed by the caller.

Source

pub fn with_response_serializer<F>(self, serializer: F) -> Self
where F: Fn(&RequestData, &ResponseData) -> Result<TRes, SerializationError> + Send + Sync + 'static,

Add a custom response body serializer.

The serializer function takes raw bytes and should return a Result<TRes, String>. If the serializer succeeds, the result will be stored as JSONB and body_parsed will be true. If it fails, the raw content will be stored as a UTF-8 string and body_parsed will be false.

§Panics

This will panic if the serializer succeeds but the resulting TRes value cannot be converted to JSON via serde_json::to_value(). This indicates a bug in the Serialize implementation of TRes and should be fixed by the caller.

Source

pub fn with_path_filter(self, filter: PathFilter) -> Self

Add path filtering to only log requests for specific URI prefixes.

§Examples
use outlet_postgres::{PostgresHandler, PathFilter};

use serde_json::Value;
let handler = PostgresHandler::<Value, Value>::new("postgresql://user:pass@localhost/db")
    .await?
    .with_path_filter(PathFilter {
        allowed_prefixes: vec!["/api/".to_string(), "/webhook/".to_string()],
        blocked_prefixes: vec!["/api/health".to_string()],
    });
Source

pub fn with_path_prefix(self, prefix: &str) -> Self

Add simple path prefix filtering - only log requests starting with the given prefix.

§Examples
use outlet_postgres::PostgresHandler;

use serde_json::Value;
let handler = PostgresHandler::<Value, Value>::new("postgresql://user:pass@localhost/db")
    .await?
    .with_path_prefix("/api/");
Source

pub async fn from_pool(pool: PgPool) -> Result<Self, PostgresHandlerError>

Create a PostgreSQL handler from an existing connection pool.

Use this if you already have a connection pool and want to reuse it. This will NOT run migrations - use migrator() to run migrations separately.

§Arguments
  • pool - Existing PostgreSQL connection pool
§Examples
use outlet_postgres::{PostgresHandler, migrator};
use sqlx::PgPool;
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize)]
struct MyBodyType {
    id: u64,
    name: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let pool = PgPool::connect("postgresql://user:pass@localhost/db").await?;
     
    // Run migrations first
    migrator().run(&pool).await?;
     
    // Create handler
    let handler = PostgresHandler::<MyBodyType, MyBodyType>::from_pool(pool).await?;
    Ok(())
}
Source

pub fn repository(&self) -> RequestRepository<TReq, TRes>

Get a repository for querying logged requests and responses.

Returns a RequestRepository with the same type parameters as this handler, allowing for type-safe querying of request and response bodies.

Trait Implementations§

Source§

impl<TReq, TRes> Clone for PostgresHandler<TReq, TRes>
where TReq: for<'de> Deserialize<'de> + Serialize + Send + Sync + 'static + Clone, TRes: for<'de> Deserialize<'de> + Serialize + Send + Sync + 'static + Clone,

Source§

fn clone(&self) -> PostgresHandler<TReq, TRes>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<TReq, TRes> RequestHandler for PostgresHandler<TReq, TRes>
where TReq: for<'de> Deserialize<'de> + Serialize + Send + Sync + 'static, TRes: for<'de> Deserialize<'de> + Serialize + Send + Sync + 'static,

Source§

async fn handle_request(&self, data: RequestData)

Handle a captured HTTP request. Read more
Source§

async fn handle_response( &self, request_data: RequestData, response_data: ResponseData, )

Handle a captured HTTP response. Read more

Auto Trait Implementations§

§

impl<TReq, TRes> Freeze for PostgresHandler<TReq, TRes>

§

impl<TReq = Value, TRes = Value> !RefUnwindSafe for PostgresHandler<TReq, TRes>

§

impl<TReq, TRes> Send for PostgresHandler<TReq, TRes>

§

impl<TReq, TRes> Sync for PostgresHandler<TReq, TRes>

§

impl<TReq, TRes> Unpin for PostgresHandler<TReq, TRes>

§

impl<TReq = Value, TRes = Value> !UnwindSafe for PostgresHandler<TReq, TRes>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,