Skip to main content

Scope

Struct Scope 

Source
pub struct Scope<St: State, In, Out = In, M = Identity, F = Filter<St, In>> { /* private fields */ }
Expand description

Groups services under a shared path prefix.

A scope is useful for keeping a related part of an application together, such as an API or administration area. It can contain resources, routes, nested scopes, middleware, filters, guards, and its own fallback service.

The prefix matches complete path segments. For example, scope("/api") can contain a service for /api/users, but the scope itself does not match the bare /api path. Register an empty nested resource if that path also needs a handler.

Scope prefixes can contain dynamic segments. Their values remain available to nested handlers through HttpRequest::match_info() and the Path extractor. For example, scope("/users/{user_id}") makes user_id available to every handler nested inside that scope.

Once the scope’s prefix and guards match, its middleware and filters run, followed by its nested router. If no nested service matches, the scope uses its own fallback, which returns 404 Not Found by default. It does not fall back to the surrounding application.

use ntex::web::{self, App};

async fn issues(
    path: web::types::Path<(String,)>,
) -> String {
    format!("Issues for {}", path.0)
}

App::default().service(
    web::scope("/projects/{project_id}")
        .route("/issues", web::get().to(issues))
        .route("/settings", web::get().to(async || "settings")),
);

Implementations§

Source§

impl<St: State, In> Scope<St, In, In>

Source

pub fn new<T: IntoPattern>(path: T) -> Self

Create a new scope

Source§

impl<St, In, Out, M, F> Scope<St, In, Out, M, F>
where St: State, In: 'static, Out: 'static, F: ServiceFactory<St, WebRequest<In>, Res = WebRequest<Out>, Error = WebError<St, St::Error>, InitError = Failure>,

Source

pub fn guard<G: Guard + 'static>(self, guard: G) -> Self

Add a match guard to this scope.

The scope is selected only when its path prefix and all registered guards match. If a guard rejects the request, the application router can try another matching scope or resource; otherwise the application’s default service is used.

The guard applies to every resource nested in the scope.

use ntex::web::{self, guard, App};

App::default().service(
    web::scope("/api")
        .guard(guard::Header("x-api-version", "2"))
        .route("/users", web::get().to(async || "Version 2 users"))
);
Source

pub fn case_insensitive_routing(self) -> Self

Use ascii case-insensitive routing.

Only static segments could be case-insensitive.

Source

pub fn configure( self, f: impl FnOnce(&mut ServiceConfig<St, Out>), ) -> ScopeServices<St, In, Out, M, F>

Run external configuration as part of the scope building process

This function is useful for moving parts of configuration to a different module or even library. For example, some of the resource’s configuration could be moved to different module.

ⓘ
use ntex::web::{self, middleware, App, HttpResponse};

// this function could be located in different module
fn config(cfg: &mut web::ServiceConfig) {
    cfg.service(web::resource("/test")
        .route(web::get().to(async || { HttpResponse::Ok() }))
        .route(web::head().to(async || { HttpResponse::MethodNotAllowed() }))
    );
}

fn main() {
    let app = App::default()
        .middleware(middleware::Logger::default())
        .service(
            web::scope("/api")
                .configure(config)
        )
        .route("/index.html", web::get().to(async || { HttpResponse::Ok() }));
}
Source

pub fn service( self, factory: impl WebServiceFactory<St, Out>, ) -> ScopeServices<St, In, Out, M, F>

Registers a web service for this scope.

The service’s path is joined with the scope prefix. A service can be a Resource, another Scope, an attribute-macro handler, or a custom service built with web::service().

If this scope matches but none of its services do, the scope’s default service is used.

use ntex::web::{self, App};

App::default().service(
    web::scope("/api")
        .service(web::resource("/users").to(async || "users"))
        .service(
            web::scope("/admin")
                .route("/health", web::get().to(async || "OK")),
        ),
);
Source

pub fn route( self, path: &str, route: Route<St, Out>, ) -> ScopeServices<St, In, Out, M, F>

Register a route for a path relative to this scope.

This is shorthand for creating a Resource with one route and registering it with Scope::service(). The route’s method and custom guards are promoted to resource guards.

If those guards reject a request, the generated resource does not match and the scope router continues searching. If nothing else in the scope matches, the scope default service is used. Register an explicit Resource when route mismatches should use a resource-level fallback.

Each call creates a separate resource, so the same relative path can be registered more than once with different guards.

use ntex::web::{self, App, HttpResponse};

App::default().service(
    web::scope("/api")
        .route("/items", web::get().to(async || "list"))
        .route(
            "/items",
            web::post().to(async || HttpResponse::Created()),
        )
);
Source

pub fn default_service<Sf>( self, f: impl IntoServiceFactory<Sf, St, WebRequest<Out>>, ) -> ScopeServices<St, In, Out, M, F>
where Sf: ServiceFactory<St, WebRequest<Out>, Res = WebResponse> + 'static, Sf::Error: WebResponseError<St, St::Error>, Sf::InitError: IntoFailure,

Set the fallback service for unmatched requests within this scope.

The fallback is called after the scope prefix and guards match but no nested resource matches. Without a custom fallback, the scope returns 404 Not Found; it does not delegate to the application’s fallback. Routing failures inside a matched resource are handled by that resource’s fallback instead.

use ntex::web::{self, App, HttpRequest, HttpResponse};

async fn not_found(req: HttpRequest) -> HttpResponse {
    HttpResponse::NotFound()
        .body(format!("No API resource for {}", req.path()))
}

App::default().service(
    web::scope("/api")
        .route("/health", web::get().to(async || "ready"))
        .default_service(web::to(not_found))
);
Source

pub fn filter<U, R>( self, filter: impl IntoServiceFactory<U, St, WebRequest<Out>>, ) -> Scope<St, In, R, M, impl ServiceFactory<St, WebRequest<In>, Res = WebRequest<R>, Error = WebError<St, St::Error>, InitError = Failure>>
where U: ServiceFactory<St, WebRequest<Out>, Res = WebRequest<R>>, U::Error: WebResponseError<St, St::Error>, U::InitError: IntoFailure,

Registers a request filter for this scope.

The filter runs after the scope’s path and guards match, but before its nested router selects a resource. It is not called for requests that do not match this scope.

use std::convert::Infallible;
use ntex::web::{self, App, WebRequest};

async fn user(_state: &(), user_id: usize) -> String {
    format!("User {user_id}")
}

App::new().service(
    web::scope("/api")
        .filter(async |req: WebRequest<()>| {
            Ok::<_, Infallible>(req.map_state(|()| 42usize))
        })
        .route("/user", web::get().to_with_state(user)),
);
Source

pub fn middleware<U>(self, mw: U) -> Scope<St, In, Out, WebStack<St, U, M>, F>

Registers a middleware for this scope.

The middleware runs only after the scope’s path and guards match. It wraps everything inside the scope, including its filter, nested routes, and fallback service. This means it can inspect or modify both the request and response, even when no nested route matches.

use ntex::web::{self, middleware, App};

App::default().service(
    web::scope("/api")
        .middleware(
            middleware::DefaultHeaders::new()
                .header("x-api", "v1"),
        )
        .route("/health", web::get().to(async || "OK")),
);

Trait Implementations§

Source§

impl<St: State, In, Out, M, F> Debug for Scope<St, In, Out, M, F>

Source§

fn fmt(&self, __derive_more_f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<St, In, Out = In, M = Identity, F = Filter<St, In>> !RefUnwindSafe for Scope<St, In, Out, M, F>

§

impl<St, In, Out = In, M = Identity, F = Filter<St, In>> !Send for Scope<St, In, Out, M, F>

§

impl<St, In, Out = In, M = Identity, F = Filter<St, In>> !Sync for Scope<St, In, Out, M, F>

§

impl<St, In, Out = In, M = Identity, F = Filter<St, In>> !UnwindSafe for Scope<St, In, Out, M, F>

§

impl<St, In, Out, M, F> Freeze for Scope<St, In, Out, M, F>
where M: Freeze, F: Freeze,

§

impl<St, In, Out, M, F> Unpin for Scope<St, In, Out, M, F>
where M: Unpin, F: Unpin, Out: Unpin, St: Unpin, In: Unpin,

§

impl<St, In, Out, M, F> UnsafeUnpin for Scope<St, In, Out, M, F>
where M: UnsafeUnpin, F: UnsafeUnpin,

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> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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, 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.