### Ntex HTTP Server Setup Source: https://ntex.rs/docs/getting-started Sets up and runs an Ntex HTTP server. It creates a new Ntex application, registers the defined services and routes, binds the server to a local address, and starts listening for incoming requests. ```rust #[ntex::main] async fn main() -> std::io::Result<()> { web::HttpServer::new(|| { web::App::new() .service(hello) .service(echo) .route("/hey", web::get().to(manual_hello)) }) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Create and Run Cargo Project Source: https://ntex.rs/docs/getting-started Commands to create a new Rust binary project using Cargo and navigate into the project directory. ```bash cargo new hello-world cd hello-world ``` -------------------------------- ### Ntex Request Handlers Source: https://ntex.rs/docs/getting-started Defines asynchronous request handlers for an Ntex web application. Includes handlers for GET requests to the root path and POST requests to '/echo', along with a manually routed handler. ```rust use ntex::web; #[web::get("/")] async fn hello() -> impl web::Responder { web::HttpResponse::Ok().body("Hello world!") } #[web::post("/echo")] async fn echo(req_body: String) -> impl web::Responder { web::HttpResponse::Ok().body(req_body) } async fn manual_hello() -> impl web::Responder { web::HttpResponse::Ok().body("Hey there!") } ``` -------------------------------- ### Add Ntex Dependency Source: https://ntex.rs/docs/getting-started Configuration for the `Cargo.toml` file to add the Ntex web framework as a project dependency, specifying the version and enabling the 'tokio' feature. ```toml [dependencies] ntex = { version = "2.0", features = ["tokio"] } ``` -------------------------------- ### Start HTTP Server - Rust Source: https://ntex.rs/docs/server Demonstrates how to initialize and run an HTTP server using ntex.rs. It binds the server to a specified address and port, then starts listening for incoming requests. The server runs until a shutdown signal is received. ```rust use ntex::web; #[ntex::main] async fn main() -> std::io::Result<()> { web::HttpServer::new(|| { web::App::new().route( "/", web::get().to(|| async { web::HttpResponse::Ok().finish() }), ) }) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Basic Route Registration with App::route() Source: https://ntex.rs/docs/url-dispatch Demonstrates registering simple GET and POST routes using the App::route() method. ```APIDOC ## POST /user ### Description Registers a POST endpoint at '/user' that is handled by the 'index' function. ### Method POST ### Endpoint /user ### Request Example (No specific request body defined for this example) ### Response #### Success Response (200) Returns an HTTP response with 'Hello' body. #### Response Example (Body content: Hello) ``` ```APIDOC ## GET / ### Description Registers a GET endpoint at the root path '/' that is handled by the 'index' function. ### Method GET ### Endpoint / ### Request Example (No specific request body defined for this example) ### Response #### Success Response (200) Returns an HTTP response with 'Hello' body. #### Response Example (Body content: Hello) ``` -------------------------------- ### Create a Basic ntex Application with Scoped Routes Source: https://ntex.rs/docs/application Demonstrates how to set up a simple ntex web server with a scoped route. It registers a handler for a specific path prefix and HTTP method. This serves as a foundational example for building ntex applications. ```rust use ntex::web; async fn index() -> impl web::Responder { "Hello world!" } #[ntex::main] async fn main() -> std::io::Result<()> { web::HttpServer::new(|| { web::App::new().service( // prefixes all resources and routes attached to it... web::scope("/app") // ...so this handles requests for `GET /app/index.html` .route("/index.html", web::get().to(index)), ) }) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Configure Route with Guards and Handler Source: https://ntex.rs/docs/url-dispatch Shows how to configure a specific route within a resource using `Resource::route()`. This example demonstrates applying multiple guards (HTTP method and header) before registering an async handler function. ```rust web::App::new().service( web::resource("/path").route( web::route() .guard(web::guard::Get()) .guard(web::guard::Header("content-type", "text/plain")) .to(|| async { web::HttpResponse::Ok().finish() }), ), ) ``` -------------------------------- ### Register Routes with App::route() Source: https://ntex.rs/docs/url-dispatch Demonstrates registering simple GET and POST routes for specific paths using the `App::route()` method. This method allows direct mapping of path patterns and HTTP methods to handler functions. ```rust use ntex::web; async fn index() -> web::HttpResponse { web::HttpResponse::Ok().body("Hello") } #[ntex::main] async fn main() -> std::io::Result<()> { web::HttpServer::new(|| { web::App::new() .route("/", web::get().to(index)) .route("/user", web::post().to(index)) }) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Inverting Guard Logic with `web::guard::Not` in Ntex.rs Source: https://ntex.rs/docs/url-dispatch Shows how to invert the logic of a guard using `web::guard::Not`. This example uses `Not(web::guard::Get())` to ensure a route is only accessed by methods other than GET, returning a 'Method Not Allowed' response for GET requests. ```rust use ntex::web; #[ntex::main] async fn main() -> std::io::Result<()> { web::HttpServer::new(|| { web::App::new().route( "/", web::route() .guard(web::guard::Not(web::guard::Get())) .to(|| async { web::HttpResponse::MethodNotAllowed().finish() }), ) }) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Compose Applications with Scopes in Ntex.rs Source: https://ntex.rs/docs/url-dispatch Demonstrates how to use `web::scope()` to prepend a resource prefix to all routes within a scope. This helps in organizing routes and mounting them at different base paths without altering the original route definitions. The example shows setting a '/users' scope for user-related routes. ```rust use ntex::web; #[web::get("/show")] async fn show_users() -> web::HttpResponse { web::HttpResponse::Ok().body("Show users") } #[web::get("/show/{id}")] async fn user_detail(path: web::types::Path<(u32,)>) -> web::HttpResponse { web::HttpResponse::Ok().body(format!("User detail: {}", path.into_inner().0)) } #[ntex::main] async fn main() -> std::io::Result<()> { web::HttpServer::new(|| { web::App::new().service( web::scope("/users") .service(show_users) .service(user_detail), ) }) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Combining Guards with `Any` and `All` in Ntex.rs Source: https://ntex.rs/docs/url-dispatch Demonstrates combining multiple guards using `Any` and `All` predicates. `Any` matches if any of the provided guards succeed, while `All` requires all provided guards to succeed. Examples include `guard::Any(guard::Get()).or(guard::Post())` and `guard::All(guard::Get()).and(guard::Header("content-type", "plain/text"))`. ```rust /* // Example for Any guard: guard::Any(guard::Get()).or(guard::Post()) // Example for All guard: guard::All(guard::Get()).and(guard::Header("content-type", "plain/text")) */ ``` -------------------------------- ### Setup R2D2 Connection Pool and Ntex Server (Rust) Source: https://ntex.rs/docs/databases Initializes an R2D2 connection pool for SQLite and configures an Ntex HTTP server. The pool is shared via application state, allowing multiple handlers to access database connections. ```rust use ntex::web; use diesel::r2d2::{self, ConnectionManager, Pool}; use diesel::SqliteConnection; use std::io; type DbPool = r2d2::Pool>; // Assume index function is defined elsewhere // async fn index(...) -> ... #[ntex::main] async fn main() -> io::Result<()> { let manager = r2d2::ConnectionManager::::new("app.db"); let pool = r2d2::Pool::builder() .build(manager) .expect("database URL should be valid path to SQLite DB file"); web::HttpServer::new(move || { web::App::new() .state(pool.clone()) .route("/{name}", web::get().to(index)) }) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Accessing Match Information in Ntex Source: https://ntex.rs/docs/url-dispatch Demonstrates how to retrieve path segments from a request using `HttpRequest::match_info`. It shows extracting values with `get()`, `query()`, and `load()` methods for various path parameters. ```rust use ntex::web; #[web::get("/a/{v1}/{v2}/")] async fn index(req: web::HttpRequest) -> Result { let v1: u8 = req.match_info().get("v1").unwrap().parse().unwrap(); let v2: u8 = req.match_info().query("v2").parse().unwrap(); let (v3, v4): (u8, u8) = req.match_info().load().unwrap(); Ok(format!("Values {} {} {} {}", v1, v2, v3, v4)) } #[ntex::main] async fn main() -> std::io::Result<()> { web::HttpServer::new(|| web::App::new().service(index)) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Handler Returning Boxed Future Source: https://ntex.rs/docs/handlers An example of an asynchronous request handler that returns a boxed Future, resolving to an HttpResponse. This is useful for more complex asynchronous operations. ```rust async fn index(req: HttpRequest) -> Box> { ... } ``` -------------------------------- ### Rust: Manual JSON Deserialization from Payload Source: https://ntex.rs/docs/request This example demonstrates manually loading the request body into memory as `BytesMut` and then deserializing it into a struct using `serde_json`. It includes a maximum payload size check and handles potential errors during chunk processing. Dependencies include `futures`, `ntex`, and `serde`. ```rust use futures::StreamExt; use ntex::util::BytesMut; use ntex::web; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] struct MyObj { name: String, number: i32, } const MAX_SIZE: usize = 262_144; // max payload size is 256k #[web::post("/")] async fn index_manual( mut payload: web::types::Payload, ) -> Result { // payload is a stream of Bytes objects let mut body = BytesMut::new(); while let Some(chunk) = payload.next().await { let chunk = chunk?; // limit max size of in-memory payload if (body.len() + chunk.len()) > MAX_SIZE { return Err(web::error::ErrorBadRequest("overflow").into()); } body.extend_from_slice(&chunk); } // body is loaded, now we can deserialize serde-json let obj = serde_json::from_slice::(&body)?; Ok(web::HttpResponse::Ok().json(&obj)) // <- send response } ``` -------------------------------- ### Streaming Response Body Source: https://ntex.rs/docs/handlers Example of creating an HTTP response with a streaming body using ntex. The body implements the Stream trait, allowing for asynchronous generation of response data. ```rust use futures::{future::ok, stream::once}; use ntex::util::Bytes; use ntex::web; #[web::get("/stream")] async fn stream() -> web::HttpResponse { let body = once(ok::<_, web::Error>(Bytes::from_static(b"test"))); web::HttpResponse::Ok() .content_type("application/json") .streaming(body) } #[ntex::main] async fn main() -> std::io::Result<()> { web::HttpServer::new(|| web::App::new().service(stream)) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Custom Ntex Error Response with derive_more Source: https://ntex.rs/docs/errors An example of implementing a custom error response using the `derive_more` crate for concise error enum definitions. This demonstrates a basic `WebResponseError` implementation where the default `error_response` is used, resulting in a 500 internal server error. ```rust use derive_more::{Display, Error}; use ntex::web; #[derive(Debug, Display, Error)] #[display(fmt = "my error: {}", name)] struct MyError { name: &'static str, } impl web::error::WebResponseError for MyError {} async fn index() -> Result<&'static str, MyError> { Err(MyError { name: "test" }) } ``` -------------------------------- ### Asynchronous Handler Example - Rust Source: https://ntex.rs/docs/server Demonstrates an asynchronous handler function using `ntex::time::sleep`. This is the recommended approach for long-running operations, as it allows the worker thread to handle other requests concurrently while waiting for the operation to complete. ```rust async fn my_handler() -> impl Responder { ntex::time::sleep(ntex::time::Seconds(5)).await; // <-- Ok. Worker thread will handle other requests here "response" } ``` -------------------------------- ### Ntex.rs: Thread-local Request Counter with State Extractor Source: https://ntex.rs/docs/extractors This example demonstrates how to use the `web::types::State` extractor in Ntex.rs to manage a thread-local counter for processed requests. It initializes application state with a `Cell` for counting and defines handlers to display and increment this count. ```rust use ntex::web; use std::cell::Cell; #[derive(Clone)] struct AppState { count: Cell, } async fn show_count(data: web::types::State) -> impl web::Responder { format!("count: {}", data.count.get()) } async fn add_one(data: web::types::State) -> impl web::Responder { let count = data.count.get(); data.count.set(count + 1); format!("count: {}", data.count.get()) } #[ntex::main] async fn main() -> std::io::Result<()> { let data = AppState { count: Cell::new(0), }; web::HttpServer::new(move || { web::App::new() .state(data.clone()) .route("/", web::to(show_count)) .route("/add", web::to(add_one)) }) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Rust: Stream Request Payload Chunks Source: https://ntex.rs/docs/request This example demonstrates how to read a request body chunk by chunk using the `web::Payload` extractor, which acts as a stream of `Bytes`. It iterates through the stream, processes each chunk, and accumulates them into a `BytesMut` buffer. This is useful for handling large request bodies or performing real-time processing. ```rust use futures::StreamExt; use ntex::util::BytesMut; use ntex::web; #[web::get("/")] async fn index(mut body: web::types::Payload) -> Result { let mut bytes = BytesMut::new(); while let Some(item) = body.next().await { let item = item?; println!("Chunk: {:?}", &item); bytes.extend_from_slice(&item); } Ok(web::HttpResponse::Ok().finish()) } ``` -------------------------------- ### Resource Configuration with App::service() Source: https://ntex.rs/docs/url-dispatch Shows how to configure resources with names, guards, and multiple routes using App::service(). ```APIDOC ## GET /user/{name} ### Description Configures a resource named 'user_detail' for the path '/user/{name}'. It only matches GET requests with a 'content-type: application/json' header. ### Method GET ### Endpoint /user/{name} ### Parameters #### Path Parameters - **name** (string) - Description of the user identifier. #### Query Parameters (None specified) #### Request Body (None specified for GET requests) ### Response #### Success Response (200) Returns an empty HTTP response. #### Response Example (No body content) ``` ```APIDOC ## PUT /user/{name} ### Description Configures a resource named 'user_detail' for the path '/user/{name}'. It only matches PUT requests with a 'content-type: application/json' header. ### Method PUT ### Endpoint /user/{name} ### Parameters #### Path Parameters - **name** (string) - Description of the user identifier. #### Query Parameters (None specified) #### Request Body (None specified for PUT requests) ### Response #### Success Response (200) Returns an empty HTTP response. #### Response Example (No body content) ``` ```APIDOC ## Any /prefix ### Description Registers a service for the path '/prefix' handled by the 'index' function. ### Method (Any HTTP method) ### Endpoint /prefix ### Request Example (No specific request body defined for this example) ### Response #### Success Response (200) Returns an HTTP response with 'Hello' body. #### Response Example (Body content: Hello) ``` -------------------------------- ### GET / (Streaming Request Body) Source: https://ntex.rs/docs/request Reads the request body payload chunk by chunk as a stream of Bytes. ```APIDOC ## GET / ### Description Reads the request body payload chunk by chunk as a stream of Bytes. ### Method GET ### Endpoint / ### Parameters #### Request Body - **Payload** (Stream) - The raw request body stream. ### Response #### Success Response (200) - **Finish** - Indicates successful processing of the stream. ``` -------------------------------- ### Configure Resources with App::service() Source: https://ntex.rs/docs/url-dispatch Illustrates configuring application resources using `App::service()`. This method allows for more complex resource definitions, including named resources, header guards, and multiple routes per resource. ```rust use ntex::web; async fn index() -> web::HttpResponse { web::HttpResponse::Ok().body("Hello") } pub fn main() { web::App::new() .service(web::resource("/prefix").to(index)) .service( web::resource("/user/{name}") .name("user_detail") .guard(web::guard::Header("content-type", "application/json")) .route(web::get().to(|| async { web::HttpResponse::Ok().finish() })) .route(web::put().to(|| async { web::HttpResponse::Ok().finish() })) ); } ``` -------------------------------- ### Implementing Custom Error Responses Source: https://ntex.rs/docs/errors An example of creating a custom error enum and implementing the WebResponseError trait to define specific HTTP status codes and response bodies. ```APIDOC ## Custom Error Response Example ### Description This example demonstrates how to define a custom error enum and implement the `WebResponseError` trait to control the HTTP status code and response body for different error variants. ### Code ```rust use derive_more::{Display, Error}; use ntex::http; use ntex::web; #[derive(Debug, Display, Error)] enum MyError { #[display(fmt = "internal error")] InternalError, #[display(fmt = "bad request")] BadClientData, #[display(fmt = "timeout")] Timeout, } impl web::error::WebResponseError for MyError { fn error_response(&self, _: &web::HttpRequest) -> web::HttpResponse { web::HttpResponse::build(self.status_code()) .set_header("content-type", "text/html; charset=utf-8") .body(self.to_string()) } fn status_code(&self) -> http::StatusCode { match *self { MyError::InternalError => http::StatusCode::INTERNAL_SERVER_ERROR, MyError::BadClientData => http::StatusCode::BAD_REQUEST, MyError::Timeout => http::StatusCode::GATEWAY_TIMEOUT, } } } #[web::get("/")] async fn index() -> Result<&'static str, MyError> { Err(MyError::BadClientData) } ``` ``` -------------------------------- ### Modular Configuration with Configure in ntex Source: https://ntex.rs/docs/application Shows how to use the configure method on App and web::Scope to move service configurations into separate functions or modules. This enhances code organization and reusability for larger applications. ```rust use ntex::web; fn scoped_config(cfg: &mut web::ServiceConfig) { cfg.service( web::resource("/test") .route(web::get().to(|| async { web::HttpResponse::Ok().body("test") })) .route(web::head().to(|| async { web::HttpResponse::MethodNotAllowed().finish() })), ); } fn config(cfg: &mut web::ServiceConfig) { cfg.service( web::resource("/app") .route(web::get().to(|| async { web::HttpResponse::Ok().body("app") })) .route(web::head().to(|| async { web::HttpResponse::MethodNotAllowed().finish() })), ); } #[ntex::main] async fn main() -> std::io::Result<()> { web::HttpServer::new(|| { web::App::new() .configure(config) .service(web::scope("/api").configure(scoped_config)) .route( "/", web::get().to(|| async { web::HttpResponse::Ok().body("/") }), ) }) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Virtual Hosting with Host Guard in ntex Source: https://ntex.rs/docs/application Illustrates using the web::guard::Host guard to implement virtual hosting. This allows different services to respond based on the Host header of the incoming request, enabling routing to different content based on the domain name. ```rust web::HttpServer::new(|| { web::App::new() .service( web::scope("/") .guard(web::guard::Host("www.rust-lang.org")), ) .service( web::scope("/") .guard(web::guard::Host("users.rust-lang.org")), ) .route("/", web::to(|| async { web::HttpResponse::Ok().finish() })) }) .bind(("127.0.0.1", 8080))? .run() .await ``` -------------------------------- ### Serve Pre-compressed Data with Ntex Source: https://ntex.rs/docs/response Explains how to serve already compressed data by manually setting the `content-encoding` header in Ntex to bypass the Compress middleware's automatic compression. ```rust use ntex::web; static HELLO_WORLD: &[u8] = &[ 0x1f, 0x8b, 0x08, 0x00, 0xa2, 0x30, 0x10, 0x5c, 0x00, 0x03, 0xcb, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00, 0x00, 0x00, ]; #[web::get("/")] async fn index() -> web::HttpResponse { web::HttpResponse::Ok() .set_header("content-encoding", "gzip") .body(HELLO_WORLD) } ``` -------------------------------- ### Resource Pattern Syntax Overview Source: https://ntex.rs/docs/url-dispatch Explains the basic structure of resource patterns, including optional leading slashes and variable parts (replacement markers). ```APIDOC ## Resource Pattern Syntax The syntax of the pattern matching language used by ntex in the pattern argument is straightforward. * **Optional Leading Slash**: Patterns can optionally start with a slash character. If a pattern does not start with a slash, an implicit slash is prepended at matching time. ``` {foo}/bar/baz ``` is equivalent to: ``` /{foo}/bar/baz ``` * **Variable Part (Replacement Marker)**: Specified in the form `{identifier}`. This captures any characters up to the next slash and uses the identifier as the key in the `HttpRequest.match_info()` object. A replacement marker matches the regular expression `[^/{}]+ * **Match Info**: A `Params` object representing dynamic parts extracted from a URL based on the routing pattern, available as `request.match_info()`. Example pattern: `foo/{baz}/{bar}` Matches: ``` foo/1/2 -> Params {'baz': '1', 'bar': '2'} foo/abc/def -> Params {'baz': 'abc', 'bar': 'def'} ``` Non-Matches: ``` foo/1/2/ -> No match (trailing slash) bar/abc/def -> First segment literal mismatch ``` * **Segment Matching**: Replacement markers match up to the first non-alphanumeric character in a segment. Pattern: `foo/{name}.html` matches `/foo/biz.html` with `Params {'name': 'biz'}`. To capture multiple parts, use multiple markers: Pattern: `foo/{name}.{ext}` matches `/foo/biz.html` with `Params {'name': 'biz', 'ext': 'html'}`. * **Custom Regular Expressions**: Specify a regex within the marker: `{identifier:regex}`. The default regex for `{foo}` is `[^/]+`. To match only digits: `{foo:\d+}`. * **Segment Requirement**: Segments must contain at least one character to match a replacement marker. `/abc/{foo}` will not match `/abc/`. `/{foo}/` will match `/` with `Params {'foo': ''}` (This is incorrect, it should not match). Correction: `/{foo}/` will match `/somevalue/` with `Params {'foo': 'somevalue'}`. For an empty segment, it would not match. * **URL Decoding**: Paths are URL-unquoted and decoded before matching. Matched segment values are also URL-unquoted. URL: `http://example.com/foo/La%20Pe%C3%B1a` with pattern `foo/{bar}` results in `Params {'bar': 'La Pexf1a'}`. * **Literal Path Values**: Literal strings in patterns should represent the decoded value. Use `/Foo Bar/{baz}` instead of `/Foo%20Bar/{baz}`. * **Tail Matching**: Use `*` after a marker for tail matching. Pattern: `foo/{bar}/{tail}*` Matches: ``` foo/1/2/ -> Params {'bar': '1', 'tail': '2/'} foo/abc/def/a/b/c -> Params {'bar': 'abc', 'tail': 'def/a/b/c'} ``` ``` -------------------------------- ### Configure HTTP Server Workers - Rust Source: https://ntex.rs/docs/server Shows how to configure the number of worker threads for the HttpServer in ntex.rs. This allows controlling the concurrency level of the server. The example explicitly sets the server to use 4 workers. ```rust use ntex::web; #[ntex::main] async fn main() { web::HttpServer::new(|| { web::App::new().route( "/", web::get().to(|| async { web::HttpResponse::Ok().finish() }), ) }) .workers(4); // <- Start 4 workers } ``` -------------------------------- ### Serve Files from Directory with Files Service (Rust) Source: https://ntex.rs/docs/static-files Illustrates serving static files from a specified directory and its sub-directories using the `Files` service. It also shows how to enable directory listings. ```rust use ntex::web; use ntex_files as fs; #[ntex::main] async fn main() -> std::io::Result<()> { web::HttpServer::new(|| { web::App::new().service(fs::Files::new("/static", ".").show_files_listing()) }) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Configure Directory Service with Options (Rust) Source: https://ntex.rs/docs/static-files Demonstrates how to configure the `Files` service to serve files from a directory, including enabling file listings and setting the 'Last-Modified' header. ```rust use ntex::web; use ntex_files as fs; #[ntex::main] async fn main() -> std::io::Result<()> { web::HttpServer::new(|| { web::App::new().service( fs::Files::new("/static", ".") .show_files_listing() .use_last_modified(true), ) }) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Deserialize JSON Request Body with Serde Source: https://ntex.rs/docs/extractors Deserializes a request body into a struct using the `Json` extractor. The type `T` must implement `serde::Deserialize`. This example demonstrates a POST request to '/submit' that expects a JSON payload. ```rust use ntex::web; use serde::Deserialize; #[derive(Deserialize)] struct Info { username: String, } /// deserialize `Info` from request's body #[web::post("/submit")] async fn submit(info: web::types::Json) -> Result { Ok(format!("Welcome {}!", info.username)) } ``` -------------------------------- ### Compose Applications with Scopes in ntex Source: https://ntex.rs/docs/application Demonstrates using web::scope() to prepend a resource prefix to route patterns, effectively grouping routes under a common path. This is useful for organizing services and defining effective URL paths. ```rust #[ntex::main] async fn main() { let scope = web::scope("/users").service(show_users); web::App::new().service(scope); } ``` -------------------------------- ### Integration Tests with init_service and call_service - Ntex Source: https://ntex.rs/docs/testing Shows how to perform integration tests by initializing a test service with `init_service` and sending requests using `call_service`. This method tests handlers within a simulated HTTP server environment, allowing for more complex request/response testing. ```rust #[cfg(test)] mod tests { use ntex::web; use ntex::web::test; use super::* #[ntex::test] async fn test_index_get() { let app = test::init_service(web::App::new().route("/", web::get().to(index))).await; let req = test::TestRequest::default() .header("content-type", "text/plain") .to_request(); let resp = test::call_service(&app, req).await; assert!(resp.status().is_success()); } #[ntex::test] async fn test_index_post() { let app = test::init_service(web::App::new().route("/", web::get().to(index))).await; let req = test::TestRequest::post().uri("/").to_request(); let resp = test::call_service(&app, req).await; assert!(resp.status().is_client_error()); } } ``` -------------------------------- ### Handling io::Error with Ntex Source: https://ntex.rs/docs/errors Demonstrates how Ntex automatically converts a standard Rust `io::Error` into an `HttpInternalServerError` when returned from a handler. This example shows returning an `io::Result` which is handled by Ntex's error conversion mechanisms. ```rust use std::io; use ntex_files::NamedFile; fn index(_req: HttpRequest) -> io::Result { Ok(NamedFile::open("static/index.html")?) } ``` -------------------------------- ### Ntex Logger Middleware Usage Source: https://ntex.rs/docs/middleware Shows how to initialize the Ntex `Logger` middleware within an `HttpServer` application. It demonstrates creating the logger with default settings and with a custom format string, logging request details. ```rust use env_logger::Env; use ntex::web; #[ntex::main] async fn main() -> std::io::Result<()> { env_logger::init_from_env(Env::default().default_filter_or("info")); web::HttpServer::new(|| { web::App::new() .wrap(web::middleware::Logger::default()) .wrap(web::middleware::Logger::new("%a %{User-Agent}i")) }) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Blocking Handler Example - Rust Source: https://ntex.rs/docs/server Illustrates a handler function that blocks the current worker thread using `std::thread::sleep`. This is shown as a bad practice because it prevents the worker thread from processing other requests, potentially leading to performance issues. ```rust fn my_handler() -> impl Responder { std::thread::sleep(Duration::from_secs(5)); // <-- Bad practice! Will cause the current worker thread to hang! "response" } ``` -------------------------------- ### Running Ntex with Backtrace Logging Source: https://ntex.rs/docs/errors Shows the command-line arguments required to run an Ntex application with detailed error logging, including backtraces. Setting `RUST_BACKTRACE=1` enables backtraces, and `RUST_LOG=ntex::web` filters logs to include Ntex's web module output. ```bash >> RUST_BACKTRACE=1 RUST_LOG=ntex::web cargo run ``` -------------------------------- ### Build HTTP Response with Ntex Source: https://ntex.rs/docs/response Demonstrates using the HttpResponseBuilder pattern in Ntex.rs to construct an HTTP response. It shows setting content type, headers, and the response body. ```rust use ntex::web; async fn index() -> web::HttpResponse { web::HttpResponse::Ok() .content_type("text/plain") .set_header("X-Hdr", "sample") .body("data") } ``` -------------------------------- ### Customizing Default Not Found Response in Ntex.rs Source: https://ntex.rs/docs/url-dispatch Explains how to override the default 'NOT FOUND' response using `App::default_service()`. This method allows configuring a custom response or handler for paths that do not match any defined routes, illustrated with an example that returns 'Method Not Allowed' for non-GET requests. ```rust use ntex::web; // Assuming 'index' is a defined handler function async fn index() -> web::HttpResponse { web::HttpResponse::Ok().body("Index page") } #[ntex::main] async fn main() -> std::io::Result<()> { web::HttpServer::new(|| { web::App::new() .service(web::resource("/").route(web::get().to(index))) .default_service( web::route() .guard(web::guard::Not(web::guard::Get())) .to(|| async { web::HttpResponse::MethodNotAllowed().finish() }), ) }) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Serve Static Files with NamedFile and Custom Path (Rust) Source: https://ntex.rs/docs/static-files Demonstrates serving individual static files by matching a path tail with a regex and using NamedFile. This approach requires careful handling to avoid security vulnerabilities like directory traversal. ```rust use ntex::web; use ntex_files::NamedFile; use std::path::PathBuf; async fn index(req: web::HttpRequest) -> Result { let path: PathBuf = req.match_info().query("filename").parse().unwrap(); Ok(NamedFile::open(path)?) } #[ntex::main] async fn main() -> std::io::Result<()> { web::HttpServer::new(|| web::App::new().route("/{filename}*", web::get().to(index))) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Implement Custom Error Handling Middleware in Rust Source: https://ntex.rs/docs/middleware This Rust code defines a middleware `ErrorMiddleware` for the ntex web framework. It intercepts responses, checks if the status code indicates a client or server error, and if so, adds a 'Content-Type: Error' header. The example also demonstrates how to apply this middleware to an ntex application. ```rust use ntex::http::header; use ntex::service::{Middleware, Service, ServiceCtx}; use ntex::web; pub struct Error; impl Middleware for Error { type Service = ErrorMiddleware; fn create(&self, service: S) -> Self::Service { ErrorMiddleware { service } } } pub struct ErrorMiddleware { service: S, } impl Service> for ErrorMiddleware where S: Service, Response = web::WebResponse, Error = web::Error>, Err: web::ErrorRenderer, { type Response = web::WebResponse; type Error = web::Error; ntex::forward_ready!(service); async fn call(&self, req: web::WebRequest, ctx: ServiceCtx<'_, Self>) -> Result { ctx.call(&self.service, req).await.map(|mut res| { let status = res.status(); if status.is_client_error() || status.is_server_error() { res.headers_mut().insert( header::CONTENT_TYPE, header::HeaderValue::from_static("Error"), ); } res }) } } #[ntex::main] async fn main() -> std::io::Result<()> { web::HttpServer::new(|| { web::App::new() .wrap(Error) .service(web::resource("/").route( web::get().to(|| async { web::HttpResponse::InternalServerError().finish() }), )) }) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Basic Pattern Matching in ntex Source: https://ntex.rs/docs/url-dispatch Demonstrates the basic syntax for resource pattern matching in ntex, including literal segments and variable parts (replacement markers). ```plaintext foo/{baz}/{bar} foo/1/2 -> Params {'baz': '1', 'bar': '2'} foo/abc/def -> Params {'baz': 'abc', 'bar': 'def'} foo/1/2/ -> No match (trailing slash) bar/abc/def -> First segment literal mismatch ``` -------------------------------- ### Enable Automatic Content Compression with Ntex Compress Middleware Source: https://ntex.rs/docs/response Shows how to apply the `Compress` middleware in Ntex.rs to automatically handle content compression for responses based on the request's Accept-Encoding header. Supports Brotli, Gzip, and Deflate. ```rust use ntex::web; #[web::get("/")] async fn index() -> web::HttpResponse { web::HttpResponse::Ok().body("data") } #[ntex::main] async fn main() -> std::io::Result<()> { web::HttpServer::new(|| { web::App::new() .wrap(web::middleware::Compress::default()) .service(index) }) .bind(("127.0.0.1", 8080))? .run() .await } ``` -------------------------------- ### Route Configuration with Guards Source: https://ntex.rs/docs/url-dispatch Illustrates configuring a route with specific guards (HTTP method and header). ```APIDOC ## GET /path ### Description Configures a route for the path '/path' that only accepts GET requests with the 'Content-Type' header set to 'text/plain'. ### Method GET ### Endpoint /path ### Parameters #### Path Parameters (None specified) #### Query Parameters (None specified) #### Request Body (None specified for GET requests) ### Response #### Success Response (200) Returns an HTTP response indicating success. #### Response Example (No body content) ``` -------------------------------- ### Testing with Application State - Ntex Source: https://ntex.rs/docs/testing Demonstrates how to test Ntex applications that utilize application state. This involves configuring the `App` with state using `.state()` and then reading the state from the response using `read_response_json`. ```rust #[cfg(test)] mod tests { use super::* use ntex::web; use ntex::web::test; #[ntex::test] async fn test_index_get() { let app = test::init_service( web::App::new() .state(AppState { count: 4 }) .route("/", web::get().to(index)), ) .await; let req = test::TestRequest::get().uri("/").to_request(); let resp: AppState = test::read_response_json(&app, req).await; assert_eq!(resp.count, 4); } } ``` -------------------------------- ### Ntex.rs: Shared and Thread-local Request Counter with State Extractor Source: https://ntex.rs/docs/extractors This example shows how to manage both shared (across threads) and thread-local request counts using the `web::types::State` extractor in Ntex.rs. It utilizes `Arc` for shared counting and `Cell` for thread-local counting, with specific handlers for incrementing and displaying these values. ```rust use ntex::web; use std::{ cell::Cell, sync::atomic::{AtomicUsize, Ordering}, sync::Arc, }; #[derive(Clone)] struct AppState { local_count: Cell, global_count: Arc, } #[web::get("/")] async fn show_count(data: web::types::State) -> impl web::Responder { format!( "global_count: {} local_count: {}", data.global_count.load(Ordering::Relaxed), data.local_count.get() ) } #[web::get("/add")] async fn add_one(data: web::types::State) -> impl web::Responder { data.global_count.fetch_add(1, Ordering::Relaxed); let local_count = data.local_count.get(); data.local_count.set(local_count + 1); format!( "global_count: {} local_count: {}", data.global_count.load(Ordering::Relaxed), data.local_count.get() ) } #[ntex::main] async fn main() -> std::io::Result<()> { let data = AppState { local_count: Cell::new(0), global_count: Arc::new(AtomicUsize::new(0)), }; web::HttpServer::new(move || { web::App::new() .state(data.clone()) .service(show_count) .service(add_one) }) .bind(("127.0.0.1", 8080))? .run() .await } ```