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,
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,
Sourcepub async fn new(database_url: &str) -> Result<Self, PostgresHandlerError>
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(())
}
Sourcepub fn with_request_serializer<F>(self, serializer: F) -> Self
pub fn with_request_serializer<F>(self, serializer: F) -> Self
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.
Sourcepub fn with_response_serializer<F>(self, serializer: F) -> Selfwhere
F: Fn(&RequestData, &ResponseData) -> Result<TRes, SerializationError> + Send + Sync + 'static,
pub fn with_response_serializer<F>(self, serializer: F) -> Selfwhere
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.
Sourcepub fn with_path_filter(self, filter: PathFilter) -> Self
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()],
});
Sourcepub fn with_path_prefix(self, prefix: &str) -> Self
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/");
Sourcepub async fn from_pool(pool: PgPool) -> Result<Self, PostgresHandlerError>
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(())
}
Sourcepub fn repository(&self) -> RequestRepository<TReq, TRes>
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,
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>
fn clone(&self) -> PostgresHandler<TReq, TRes>
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moreSource§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,
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)
async fn handle_request(&self, data: RequestData)
Source§async fn handle_response(
&self,
request_data: RequestData,
response_data: ResponseData,
)
async fn handle_response( &self, request_data: RequestData, response_data: ResponseData, )
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> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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