request_scoped

Attribute Macro request_scoped 

#[request_scoped]
Expand description

Define a request-scoped constructor.

Request-scoped constructors are invoked once per request to create a new instance of their output type. The created instance is cached for the duration of the request processing lifecycle.

Check out #[singleton] and #[transient] if you need to define constructors with different lifecycles.

§Example

use pavex::methods;

pub struct RequestId(uuid::Uuid);

#[methods]
impl RequestId {
    #[request_scoped]
    pub fn new() -> Self {
        Self(uuid::Uuid::new_v4())
    }
}

RequestId::new will be called once per request whenever a new instance of RequestId is needed.

§Guide

Check out the “Dependency injection” section of Pavex’s guide for a thorough introduction to dependency injection in Pavex applications.

§Registration

You can register a request-scoped constructor with your application in two ways:

The #[request_scoped] macro generates a constant that you can use to refer to the constructor when invoking Blueprint::constructor.

§Arguments

The sections below provide an exhaustive list of all the arguments and flags supported by the request_scoped macro:

NameKindRequired
idArgumentNo
clone_if_necessaryFlagNo
never_cloneFlagNo
allowArgumentNo

§id

By default, Pavex generates a constant named after your type and method (converted to UPPER_SNAKE_CASE) that you use when registering the constructor.

The id argument allows you to customize the name of the generated constant.

§Example

Using the default generated identifier:

use pavex::{methods, Blueprint};

pub struct RequestLogger {
    // [...]
}

#[methods]
impl RequestLogger {
    #[request_scoped]
    pub fn new() -> Self {
        Self {
            // [...]
        }
    }
}

let mut bp = Blueprint::new();
// The generated constant is named `REQUEST_LOGGER_NEW`
bp.constructor(REQUEST_LOGGER_NEW);

Using a custom identifier:

use pavex::{methods, Blueprint};

pub struct RequestLogger {
    // [...]
}

#[methods]
impl RequestLogger {
    #[request_scoped(id = "LOGGER_CONSTRUCTOR")]
    //               👆 Custom identifier
    pub fn new() -> Self {
        Self {
            // [...]
        }
    }
}

let mut bp = Blueprint::new();
// Use the custom identifier when registering
bp.constructor(LOGGER_CONSTRUCTOR);

§clone_if_necessary

By default, Pavex will not clone the output of request-scoped constructors. The clone_if_necessary flag allows Pavex to invoke .clone() on the output if it helps satisfy Rust’s borrow checker.

The constructed type must implement the Clone trait.

This flag is mutually exclusive with never_clone.

§Example

use pavex::methods;
use std::collections::HashMap;

#[derive(Clone)]
pub struct RequestConfig {
    settings: HashMap<String, String>,
}

#[methods]
impl RequestConfig {
    #[request_scoped(clone_if_necessary)]
    //               👆 Allow cloning when needed
    pub fn new() -> Self {
        Self {
            settings: HashMap::new(),
        }
    }
}

§never_clone

The never_clone flag explicitly prevents Pavex from cloning the output of this constructor. This is the default behavior for request-scoped constructors, so this flag is typically used for clarity and explicitness.

This flag is mutually exclusive with clone_if_necessary.

§Example

use pavex::methods;

pub struct ScratchPad {
    // Contains non-cloneable resources
    temp_file: std::fs::File,
}

#[methods]
impl ScratchPad {
    #[request_scoped(never_clone)]
    //               👆 Explicitly prevent cloning (default behavior)
    pub fn new() -> std::io::Result<Self> {
        Ok(Self {
            temp_file: std::fs::File::create("request.tmp")?,
        })
    }
}

Pavex will report an error during the code-generation phase if cloning is required but forbidden.

§allow

The allow argument can be used to suppress specific warnings.

Currently, only one value is supported:

  • unused: Suppress warnings if this constructor is registered but never used

§Example

use pavex::methods;

pub struct DebugInfo {
    // [...]
}

#[methods]
impl DebugInfo {
    #[request_scoped(allow(unused))]
    //               👆 Don't warn if unused
    pub fn new() -> Self {
        Self {
            // [...]
        }
    }
}