hello_world/hello_world.rs
1//! Hello World Example - Minimal fastapi_rust Application
2//!
3//! This example demonstrates the most basic fastapi_rust setup:
4//! - Creating an application with a single GET endpoint
5//! - Defining a simple request handler
6//! - Testing with the built-in TestClient
7//!
8//! # Running This Example
9//!
10//! ```bash
11//! cargo run --example hello_world
12//! ```
13//!
14//! # Expected Output
15//!
16//! ```text
17//! GET / -> 200 OK
18//! Response: Hello, World!
19//! ```
20
21// Import the core types from fastapi
22use fastapi_rust::core::{
23 App, // The application builder and container
24 Request, // Incoming HTTP request
25 RequestContext, // Request context (contains Cx, request ID, etc.)
26 Response, // HTTP response to send back
27 ResponseBody, // Response body types
28 TestClient, // Built-in test client for making requests
29};
30
31/// A simple request handler that returns "Hello, World!"
32///
33/// # Parameters
34///
35/// - `_ctx`: The request context (unused in this simple example)
36/// - `_req`: The incoming request (unused - we return the same response for any request)
37///
38/// # Returns
39///
40/// An HTTP 200 OK response with "Hello, World!" as the body.
41///
42/// # Note
43///
44/// Handlers in fastapi_rust are functions that take a RequestContext
45/// and mutable Request, and return a Response. They can be sync or async.
46fn hello_handler(_ctx: &RequestContext, _req: &mut Request) -> std::future::Ready<Response> {
47 // Create a 200 OK response with a plain text body
48 std::future::ready(Response::ok().body(ResponseBody::Bytes(b"Hello, World!".to_vec())))
49}
50
51#[allow(clippy::needless_pass_by_value)]
52fn check_eq<T: PartialEq + std::fmt::Debug>(left: T, right: T, message: &str) -> bool {
53 if left == right {
54 true
55 } else {
56 eprintln!("Check failed: {message}. left={left:?} right={right:?}");
57 false
58 }
59}
60
61fn main() {
62 println!("fastapi_rust Hello World Example");
63 println!("================================\n");
64
65 // Build the application
66 //
67 // App::builder() creates a new application builder that lets you:
68 // - Add routes for different HTTP methods
69 // - Configure middleware
70 // - Set application state
71 // - Define exception handlers
72 let app = App::builder()
73 // Register a GET handler for the root path "/"
74 //
75 // This is equivalent to:
76 // @app.get("/")
77 // def hello():
78 // return "Hello, World!"
79 // in Python FastAPI
80 .get("/", hello_handler)
81 // Build the final immutable App
82 .build();
83
84 println!("App created with {} route(s)\n", app.route_count());
85
86 // Create a test client to make requests to our app
87 //
88 // TestClient wraps any Handler (including App) and provides
89 // a convenient API for making HTTP requests in tests.
90 let client = TestClient::new(app);
91
92 // Make a GET request to "/"
93 println!("Making request: GET /");
94 let response = client.get("/").send();
95
96 // Check the response
97 println!(
98 "GET / -> {} {}",
99 response.status().as_u16(),
100 response.status().canonical_reason()
101 );
102 println!("Response: {}\n", response.text());
103
104 // Verify success
105 if !check_eq(response.status().as_u16(), 200, "GET / should return 200") {
106 return;
107 }
108 if !check_eq(response.text(), "Hello, World!", "GET / should return body") {
109 return;
110 }
111
112 // Try a path that doesn't exist - should get 404
113 println!("Making request: GET /not-found");
114 let response = client.get("/not-found").send();
115 println!(
116 "GET /not-found -> {} {}",
117 response.status().as_u16(),
118 response.status().canonical_reason()
119 );
120 if !check_eq(
121 response.status().as_u16(),
122 404,
123 "Unknown routes should return 404",
124 ) {
125 return;
126 }
127
128 println!("\nAll assertions passed!");
129}