pub struct RequestBuilder<'a, H> { /* private fields */ }Expand description
Builder for constructing test requests with a fluent API.
Use the methods on TestClient to create a request builder,
then chain configuration methods and call send to execute.
§Example
ⓘ
let response = client
.post("/api/items")
.header("Content-Type", "application/json")
.body(r#"{"name": "Widget"}"#)
.send();Implementations§
Source§impl<'a, H> RequestBuilder<'a, H>where
H: Handler + 'static,
impl<'a, H> RequestBuilder<'a, H>where
H: Handler + 'static,
Sourcepub fn query(self, key: &str, value: &str) -> RequestBuilder<'a, H>
pub fn query(self, key: &str, value: &str) -> RequestBuilder<'a, H>
Sourcepub fn header(
self,
name: impl Into<String>,
value: impl Into<Vec<u8>>,
) -> RequestBuilder<'a, H>
pub fn header( self, name: impl Into<String>, value: impl Into<Vec<u8>>, ) -> RequestBuilder<'a, H>
Examples found in repository?
examples/crud_api.rs (line 277)
252fn main() {
253 // Initialize the global store
254 *STORE.lock().unwrap() = Some(UserDb {
255 users: HashMap::new(),
256 next_id: 1,
257 });
258
259 println!("fastapi_rust CRUD API Example");
260 println!("=============================\n");
261
262 let app = App::builder()
263 .post("/users", create_user)
264 .get("/users", list_users)
265 .get("/users/{id}", get_user)
266 .put("/users/{id}", update_user)
267 .delete("/users/{id}", delete_user)
268 .build();
269
270 println!("App created with {} route(s)\n", app.route_count());
271 let client = TestClient::new(app);
272
273 // 1. Create users
274 println!("1. Create users");
275 let resp = client
276 .post("/users")
277 .header("content-type", "application/json")
278 .body(r#"{"name": "Alice", "email": "alice@example.com"}"#)
279 .send();
280 println!(
281 " POST /users -> {} {}",
282 resp.status().as_u16(),
283 resp.text()
284 );
285 assert_eq!(resp.status().as_u16(), 201);
286
287 let resp = client
288 .post("/users")
289 .header("content-type", "application/json")
290 .body(r#"{"name": "Bob", "email": "bob@example.com"}"#)
291 .send();
292 println!(
293 " POST /users -> {} {}",
294 resp.status().as_u16(),
295 resp.text()
296 );
297 assert_eq!(resp.status().as_u16(), 201);
298
299 // 2. List users
300 println!("\n2. List all users");
301 let resp = client.get("/users").send();
302 println!(
303 " GET /users -> {} {}",
304 resp.status().as_u16(),
305 resp.text()
306 );
307 assert_eq!(resp.status().as_u16(), 200);
308
309 // 3. Get user by ID
310 println!("\n3. Get user by ID");
311 let resp = client.get("/users/1").send();
312 println!(
313 " GET /users/1 -> {} {}",
314 resp.status().as_u16(),
315 resp.text()
316 );
317 assert_eq!(resp.status().as_u16(), 200);
318
319 // 4. Get nonexistent user
320 println!("\n4. Get nonexistent user");
321 let resp = client.get("/users/999").send();
322 println!(
323 " GET /users/999 -> {} {}",
324 resp.status().as_u16(),
325 resp.text()
326 );
327 assert_eq!(resp.status().as_u16(), 404);
328
329 // 5. Update user
330 println!("\n5. Update user");
331 let resp = client
332 .put("/users/1")
333 .header("content-type", "application/json")
334 .body(r#"{"name": "Alice Smith", "email": "alice.smith@example.com"}"#)
335 .send();
336 println!(
337 " PUT /users/1 -> {} {}",
338 resp.status().as_u16(),
339 resp.text()
340 );
341 assert_eq!(resp.status().as_u16(), 200);
342
343 // 6. Validation: empty name
344 println!("\n6. Validation error (empty name)");
345 let resp = client
346 .post("/users")
347 .header("content-type", "application/json")
348 .body(r#"{"name": "", "email": "bad@example.com"}"#)
349 .send();
350 println!(
351 " POST /users -> {} {}",
352 resp.status().as_u16(),
353 resp.text()
354 );
355 assert_eq!(resp.status().as_u16(), 400);
356
357 // 7. Validation: invalid email
358 println!("\n7. Validation error (invalid email)");
359 let resp = client
360 .post("/users")
361 .header("content-type", "application/json")
362 .body(r#"{"name": "Charlie", "email": "not-an-email"}"#)
363 .send();
364 println!(
365 " POST /users -> {} {}",
366 resp.status().as_u16(),
367 resp.text()
368 );
369 assert_eq!(resp.status().as_u16(), 400);
370
371 // 8. Wrong Content-Type
372 println!("\n8. Wrong Content-Type");
373 let resp = client
374 .post("/users")
375 .header("content-type", "text/plain")
376 .body(r#"{"name": "Dan", "email": "dan@example.com"}"#)
377 .send();
378 println!(
379 " POST /users -> {} {}",
380 resp.status().as_u16(),
381 resp.text()
382 );
383 assert_eq!(resp.status().as_u16(), 415);
384
385 // 9. Delete user
386 println!("\n9. Delete user");
387 let resp = client.delete("/users/2").send();
388 println!(" DELETE /users/2 -> {}", resp.status().as_u16());
389 assert_eq!(resp.status().as_u16(), 204);
390
391 // 10. Verify deletion
392 println!("\n10. Verify deletion");
393 let resp = client.get("/users/2").send();
394 println!(
395 " GET /users/2 -> {} {}",
396 resp.status().as_u16(),
397 resp.text()
398 );
399 assert_eq!(resp.status().as_u16(), 404);
400
401 let resp = client.get("/users").send();
402 println!(
403 " GET /users -> {} {}",
404 resp.status().as_u16(),
405 resp.text()
406 );
407 assert_eq!(resp.status().as_u16(), 200);
408
409 println!("\nAll CRUD operations passed!");
410}More examples
examples/auth_example.rs (line 312)
248fn main() {
249 println!("fastapi_rust Authentication Example");
250 println!("====================================\n");
251
252 // Build the application with public and protected routes
253 let app = App::builder()
254 // Public endpoints - accessible to everyone
255 .get("/public", public_handler)
256 // Login endpoint - returns a token
257 .post("/login", login_handler)
258 // Protected endpoint - requires valid bearer token
259 .get("/protected", protected_handler)
260 .build();
261
262 println!("App created with {} route(s)\n", app.route_count());
263
264 // Create a test client
265 let client = TestClient::new(app);
266
267 // =========================================================================
268 // Test 1: Public endpoint - no auth required
269 // =========================================================================
270 println!("1. Public endpoint - no auth required");
271 let response = client.get("/public").send();
272 println!(
273 " GET /public -> {} {}",
274 response.status().as_u16(),
275 response.status().canonical_reason()
276 );
277 assert_eq!(response.status().as_u16(), 200);
278 assert!(response.text().contains("public endpoint"));
279
280 // =========================================================================
281 // Test 2: Protected endpoint - without token (should get 401)
282 // =========================================================================
283 println!("\n2. Protected endpoint - without token");
284 let response = client.get("/protected").send();
285 println!(
286 " GET /protected -> {} {}",
287 response.status().as_u16(),
288 response.status().canonical_reason()
289 );
290 assert_eq!(
291 response.status().as_u16(),
292 401,
293 "Protected endpoint should return 401 without token"
294 );
295
296 // Check for WWW-Authenticate header
297 let has_www_auth = response
298 .headers()
299 .iter()
300 .any(|(name, value)| name == "www-authenticate" && value == b"Bearer");
301 assert!(
302 has_www_auth,
303 "401 response should include WWW-Authenticate: Bearer header"
304 );
305
306 // =========================================================================
307 // Test 3: Login endpoint - get a token
308 // =========================================================================
309 println!("\n3. Login endpoint - get a token");
310 let response = client
311 .post("/login")
312 .header("content-type", "application/json")
313 .body(r#"{"username":"test","password":"test123"}"#)
314 .send();
315 println!(
316 " POST /login -> {} {}",
317 response.status().as_u16(),
318 response.status().canonical_reason()
319 );
320 assert_eq!(response.status().as_u16(), 200);
321
322 // Parse the response to get the token
323 let body: serde_json::Value = serde_json::from_str(response.text()).unwrap();
324 let token = body["access_token"].as_str().unwrap();
325 println!(" Token: {token}");
326 assert_eq!(token, SECRET_TOKEN);
327
328 // =========================================================================
329 // Test 4: Protected endpoint - with valid token (should get 200)
330 // =========================================================================
331 println!("\n4. Protected endpoint - with valid token");
332 let response = client
333 .get("/protected")
334 .header("authorization", format!("Bearer {SECRET_TOKEN}"))
335 .send();
336 println!(
337 " GET /protected (Authorization: Bearer {}) -> {} {}",
338 SECRET_TOKEN,
339 response.status().as_u16(),
340 response.status().canonical_reason()
341 );
342 assert_eq!(
343 response.status().as_u16(),
344 200,
345 "Protected endpoint should return 200 with valid token"
346 );
347 assert!(response.text().contains("protected resource"));
348
349 // =========================================================================
350 // Test 5: Protected endpoint - with invalid token (should get 403)
351 // =========================================================================
352 println!("\n5. Protected endpoint - with invalid token");
353 let response = client
354 .get("/protected")
355 .header("authorization", "Bearer wrong_token")
356 .send();
357 println!(
358 " GET /protected (Authorization: Bearer wrong_token) -> {} {}",
359 response.status().as_u16(),
360 response.status().canonical_reason()
361 );
362 assert_eq!(
363 response.status().as_u16(),
364 403,
365 "Protected endpoint should return 403 with invalid token"
366 );
367
368 // =========================================================================
369 // Test 6: Protected endpoint - with wrong auth scheme (should get 401)
370 // =========================================================================
371 println!("\n6. Protected endpoint - with wrong auth scheme");
372 let response = client
373 .get("/protected")
374 .header("authorization", "Basic dXNlcjpwYXNz")
375 .send();
376 println!(
377 " GET /protected (Authorization: Basic ...) -> {} {}",
378 response.status().as_u16(),
379 response.status().canonical_reason()
380 );
381 assert_eq!(
382 response.status().as_u16(),
383 401,
384 "Protected endpoint should return 401 with wrong auth scheme"
385 );
386
387 // =========================================================================
388 // Test 7: Login with wrong Content-Type (should get 415)
389 // =========================================================================
390 println!("\n7. Login with wrong Content-Type");
391 let response = client
392 .post("/login")
393 .header("content-type", "text/plain")
394 .body("username=test&password=test123")
395 .send();
396 println!(
397 " POST /login (Content-Type: text/plain) -> {} {}",
398 response.status().as_u16(),
399 response.status().canonical_reason()
400 );
401 assert_eq!(
402 response.status().as_u16(),
403 415,
404 "Login should return 415 with wrong Content-Type"
405 );
406
407 // =========================================================================
408 // Test 8: Token case sensitivity (lowercase 'bearer')
409 // =========================================================================
410 println!("\n8. Token case sensitivity (lowercase 'bearer')");
411 let response = client
412 .get("/protected")
413 .header("authorization", format!("bearer {SECRET_TOKEN}"))
414 .send();
415 println!(
416 " GET /protected (Authorization: bearer {}) -> {} {}",
417 SECRET_TOKEN,
418 response.status().as_u16(),
419 response.status().canonical_reason()
420 );
421 assert_eq!(
422 response.status().as_u16(),
423 200,
424 "Bearer scheme should be case-insensitive (lowercase accepted)"
425 );
426
427 println!("\nAll authentication tests passed!");
428}Sourcepub fn header_str(
self,
name: impl Into<String>,
value: &str,
) -> RequestBuilder<'a, H>
pub fn header_str( self, name: impl Into<String>, value: &str, ) -> RequestBuilder<'a, H>
Sets a request header with a string value.
Sourcepub fn body(self, body: impl Into<Vec<u8>>) -> RequestBuilder<'a, H>
pub fn body(self, body: impl Into<Vec<u8>>) -> RequestBuilder<'a, H>
Sets the request body as raw bytes.
§Example
ⓘ
client.post("/upload").body(b"binary data".to_vec()).send()Examples found in repository?
examples/crud_api.rs (line 278)
252fn main() {
253 // Initialize the global store
254 *STORE.lock().unwrap() = Some(UserDb {
255 users: HashMap::new(),
256 next_id: 1,
257 });
258
259 println!("fastapi_rust CRUD API Example");
260 println!("=============================\n");
261
262 let app = App::builder()
263 .post("/users", create_user)
264 .get("/users", list_users)
265 .get("/users/{id}", get_user)
266 .put("/users/{id}", update_user)
267 .delete("/users/{id}", delete_user)
268 .build();
269
270 println!("App created with {} route(s)\n", app.route_count());
271 let client = TestClient::new(app);
272
273 // 1. Create users
274 println!("1. Create users");
275 let resp = client
276 .post("/users")
277 .header("content-type", "application/json")
278 .body(r#"{"name": "Alice", "email": "alice@example.com"}"#)
279 .send();
280 println!(
281 " POST /users -> {} {}",
282 resp.status().as_u16(),
283 resp.text()
284 );
285 assert_eq!(resp.status().as_u16(), 201);
286
287 let resp = client
288 .post("/users")
289 .header("content-type", "application/json")
290 .body(r#"{"name": "Bob", "email": "bob@example.com"}"#)
291 .send();
292 println!(
293 " POST /users -> {} {}",
294 resp.status().as_u16(),
295 resp.text()
296 );
297 assert_eq!(resp.status().as_u16(), 201);
298
299 // 2. List users
300 println!("\n2. List all users");
301 let resp = client.get("/users").send();
302 println!(
303 " GET /users -> {} {}",
304 resp.status().as_u16(),
305 resp.text()
306 );
307 assert_eq!(resp.status().as_u16(), 200);
308
309 // 3. Get user by ID
310 println!("\n3. Get user by ID");
311 let resp = client.get("/users/1").send();
312 println!(
313 " GET /users/1 -> {} {}",
314 resp.status().as_u16(),
315 resp.text()
316 );
317 assert_eq!(resp.status().as_u16(), 200);
318
319 // 4. Get nonexistent user
320 println!("\n4. Get nonexistent user");
321 let resp = client.get("/users/999").send();
322 println!(
323 " GET /users/999 -> {} {}",
324 resp.status().as_u16(),
325 resp.text()
326 );
327 assert_eq!(resp.status().as_u16(), 404);
328
329 // 5. Update user
330 println!("\n5. Update user");
331 let resp = client
332 .put("/users/1")
333 .header("content-type", "application/json")
334 .body(r#"{"name": "Alice Smith", "email": "alice.smith@example.com"}"#)
335 .send();
336 println!(
337 " PUT /users/1 -> {} {}",
338 resp.status().as_u16(),
339 resp.text()
340 );
341 assert_eq!(resp.status().as_u16(), 200);
342
343 // 6. Validation: empty name
344 println!("\n6. Validation error (empty name)");
345 let resp = client
346 .post("/users")
347 .header("content-type", "application/json")
348 .body(r#"{"name": "", "email": "bad@example.com"}"#)
349 .send();
350 println!(
351 " POST /users -> {} {}",
352 resp.status().as_u16(),
353 resp.text()
354 );
355 assert_eq!(resp.status().as_u16(), 400);
356
357 // 7. Validation: invalid email
358 println!("\n7. Validation error (invalid email)");
359 let resp = client
360 .post("/users")
361 .header("content-type", "application/json")
362 .body(r#"{"name": "Charlie", "email": "not-an-email"}"#)
363 .send();
364 println!(
365 " POST /users -> {} {}",
366 resp.status().as_u16(),
367 resp.text()
368 );
369 assert_eq!(resp.status().as_u16(), 400);
370
371 // 8. Wrong Content-Type
372 println!("\n8. Wrong Content-Type");
373 let resp = client
374 .post("/users")
375 .header("content-type", "text/plain")
376 .body(r#"{"name": "Dan", "email": "dan@example.com"}"#)
377 .send();
378 println!(
379 " POST /users -> {} {}",
380 resp.status().as_u16(),
381 resp.text()
382 );
383 assert_eq!(resp.status().as_u16(), 415);
384
385 // 9. Delete user
386 println!("\n9. Delete user");
387 let resp = client.delete("/users/2").send();
388 println!(" DELETE /users/2 -> {}", resp.status().as_u16());
389 assert_eq!(resp.status().as_u16(), 204);
390
391 // 10. Verify deletion
392 println!("\n10. Verify deletion");
393 let resp = client.get("/users/2").send();
394 println!(
395 " GET /users/2 -> {} {}",
396 resp.status().as_u16(),
397 resp.text()
398 );
399 assert_eq!(resp.status().as_u16(), 404);
400
401 let resp = client.get("/users").send();
402 println!(
403 " GET /users -> {} {}",
404 resp.status().as_u16(),
405 resp.text()
406 );
407 assert_eq!(resp.status().as_u16(), 200);
408
409 println!("\nAll CRUD operations passed!");
410}More examples
examples/auth_example.rs (line 313)
248fn main() {
249 println!("fastapi_rust Authentication Example");
250 println!("====================================\n");
251
252 // Build the application with public and protected routes
253 let app = App::builder()
254 // Public endpoints - accessible to everyone
255 .get("/public", public_handler)
256 // Login endpoint - returns a token
257 .post("/login", login_handler)
258 // Protected endpoint - requires valid bearer token
259 .get("/protected", protected_handler)
260 .build();
261
262 println!("App created with {} route(s)\n", app.route_count());
263
264 // Create a test client
265 let client = TestClient::new(app);
266
267 // =========================================================================
268 // Test 1: Public endpoint - no auth required
269 // =========================================================================
270 println!("1. Public endpoint - no auth required");
271 let response = client.get("/public").send();
272 println!(
273 " GET /public -> {} {}",
274 response.status().as_u16(),
275 response.status().canonical_reason()
276 );
277 assert_eq!(response.status().as_u16(), 200);
278 assert!(response.text().contains("public endpoint"));
279
280 // =========================================================================
281 // Test 2: Protected endpoint - without token (should get 401)
282 // =========================================================================
283 println!("\n2. Protected endpoint - without token");
284 let response = client.get("/protected").send();
285 println!(
286 " GET /protected -> {} {}",
287 response.status().as_u16(),
288 response.status().canonical_reason()
289 );
290 assert_eq!(
291 response.status().as_u16(),
292 401,
293 "Protected endpoint should return 401 without token"
294 );
295
296 // Check for WWW-Authenticate header
297 let has_www_auth = response
298 .headers()
299 .iter()
300 .any(|(name, value)| name == "www-authenticate" && value == b"Bearer");
301 assert!(
302 has_www_auth,
303 "401 response should include WWW-Authenticate: Bearer header"
304 );
305
306 // =========================================================================
307 // Test 3: Login endpoint - get a token
308 // =========================================================================
309 println!("\n3. Login endpoint - get a token");
310 let response = client
311 .post("/login")
312 .header("content-type", "application/json")
313 .body(r#"{"username":"test","password":"test123"}"#)
314 .send();
315 println!(
316 " POST /login -> {} {}",
317 response.status().as_u16(),
318 response.status().canonical_reason()
319 );
320 assert_eq!(response.status().as_u16(), 200);
321
322 // Parse the response to get the token
323 let body: serde_json::Value = serde_json::from_str(response.text()).unwrap();
324 let token = body["access_token"].as_str().unwrap();
325 println!(" Token: {token}");
326 assert_eq!(token, SECRET_TOKEN);
327
328 // =========================================================================
329 // Test 4: Protected endpoint - with valid token (should get 200)
330 // =========================================================================
331 println!("\n4. Protected endpoint - with valid token");
332 let response = client
333 .get("/protected")
334 .header("authorization", format!("Bearer {SECRET_TOKEN}"))
335 .send();
336 println!(
337 " GET /protected (Authorization: Bearer {}) -> {} {}",
338 SECRET_TOKEN,
339 response.status().as_u16(),
340 response.status().canonical_reason()
341 );
342 assert_eq!(
343 response.status().as_u16(),
344 200,
345 "Protected endpoint should return 200 with valid token"
346 );
347 assert!(response.text().contains("protected resource"));
348
349 // =========================================================================
350 // Test 5: Protected endpoint - with invalid token (should get 403)
351 // =========================================================================
352 println!("\n5. Protected endpoint - with invalid token");
353 let response = client
354 .get("/protected")
355 .header("authorization", "Bearer wrong_token")
356 .send();
357 println!(
358 " GET /protected (Authorization: Bearer wrong_token) -> {} {}",
359 response.status().as_u16(),
360 response.status().canonical_reason()
361 );
362 assert_eq!(
363 response.status().as_u16(),
364 403,
365 "Protected endpoint should return 403 with invalid token"
366 );
367
368 // =========================================================================
369 // Test 6: Protected endpoint - with wrong auth scheme (should get 401)
370 // =========================================================================
371 println!("\n6. Protected endpoint - with wrong auth scheme");
372 let response = client
373 .get("/protected")
374 .header("authorization", "Basic dXNlcjpwYXNz")
375 .send();
376 println!(
377 " GET /protected (Authorization: Basic ...) -> {} {}",
378 response.status().as_u16(),
379 response.status().canonical_reason()
380 );
381 assert_eq!(
382 response.status().as_u16(),
383 401,
384 "Protected endpoint should return 401 with wrong auth scheme"
385 );
386
387 // =========================================================================
388 // Test 7: Login with wrong Content-Type (should get 415)
389 // =========================================================================
390 println!("\n7. Login with wrong Content-Type");
391 let response = client
392 .post("/login")
393 .header("content-type", "text/plain")
394 .body("username=test&password=test123")
395 .send();
396 println!(
397 " POST /login (Content-Type: text/plain) -> {} {}",
398 response.status().as_u16(),
399 response.status().canonical_reason()
400 );
401 assert_eq!(
402 response.status().as_u16(),
403 415,
404 "Login should return 415 with wrong Content-Type"
405 );
406
407 // =========================================================================
408 // Test 8: Token case sensitivity (lowercase 'bearer')
409 // =========================================================================
410 println!("\n8. Token case sensitivity (lowercase 'bearer')");
411 let response = client
412 .get("/protected")
413 .header("authorization", format!("bearer {SECRET_TOKEN}"))
414 .send();
415 println!(
416 " GET /protected (Authorization: bearer {}) -> {} {}",
417 SECRET_TOKEN,
418 response.status().as_u16(),
419 response.status().canonical_reason()
420 );
421 assert_eq!(
422 response.status().as_u16(),
423 200,
424 "Bearer scheme should be case-insensitive (lowercase accepted)"
425 );
426
427 println!("\nAll authentication tests passed!");
428}Sourcepub fn body_str(self, body: &str) -> RequestBuilder<'a, H>
pub fn body_str(self, body: &str) -> RequestBuilder<'a, H>
Sets the request body as a string.
Sourcepub fn json<T>(self, value: &T) -> RequestBuilder<'a, H>where
T: Serialize,
pub fn json<T>(self, value: &T) -> RequestBuilder<'a, H>where
T: Serialize,
Sets a cookie for this request only.
This does not affect the client’s cookie jar.
Sourcepub fn send(self) -> TestResponse
pub fn send(self) -> TestResponse
Examples found in repository?
examples/hello_world.rs (line 84)
51fn main() {
52 println!("fastapi_rust Hello World Example");
53 println!("================================\n");
54
55 // Build the application
56 //
57 // App::builder() creates a new application builder that lets you:
58 // - Add routes for different HTTP methods
59 // - Configure middleware
60 // - Set application state
61 // - Define exception handlers
62 let app = App::builder()
63 // Register a GET handler for the root path "/"
64 //
65 // This is equivalent to:
66 // @app.get("/")
67 // def hello():
68 // return "Hello, World!"
69 // in Python FastAPI
70 .get("/", hello_handler)
71 // Build the final immutable App
72 .build();
73
74 println!("App created with {} route(s)\n", app.route_count());
75
76 // Create a test client to make requests to our app
77 //
78 // TestClient wraps any Handler (including App) and provides
79 // a convenient API for making HTTP requests in tests.
80 let client = TestClient::new(app);
81
82 // Make a GET request to "/"
83 println!("Making request: GET /");
84 let response = client.get("/").send();
85
86 // Check the response
87 println!(
88 "GET / -> {} {}",
89 response.status().as_u16(),
90 response.status().canonical_reason()
91 );
92 println!("Response: {}\n", response.text());
93
94 // Verify success
95 assert_eq!(response.status().as_u16(), 200);
96 assert_eq!(response.text(), "Hello, World!");
97
98 // Try a path that doesn't exist - should get 404
99 println!("Making request: GET /not-found");
100 let response = client.get("/not-found").send();
101 println!(
102 "GET /not-found -> {} {}",
103 response.status().as_u16(),
104 response.status().canonical_reason()
105 );
106 assert_eq!(response.status().as_u16(), 404);
107
108 println!("\nAll assertions passed!");
109}More examples
examples/getting_started.rs (line 37)
24fn main() {
25 println!("Getting Started Guide - Code Validation\n");
26
27 // === Basic App Example ===
28 println!("1. Basic app with two routes:");
29 let app = App::builder()
30 .get("/", hello)
31 .get("/health", health)
32 .build();
33
34 println!(" Routes: {}", app.route_count());
35 let client = TestClient::new(app);
36
37 let response = client.get("/").send();
38 println!(
39 " GET / -> {} ({})",
40 response.status().as_u16(),
41 response.text()
42 );
43 assert_eq!(response.status().as_u16(), 200);
44 assert_eq!(response.text(), "Hello, World!");
45
46 let response = client.get("/health").send();
47 println!(
48 " GET /health -> {} ({})",
49 response.status().as_u16(),
50 response.text()
51 );
52 assert_eq!(response.status().as_u16(), 200);
53
54 // === App with Middleware ===
55 println!("\n2. App with middleware:");
56 let app = App::builder()
57 .middleware(RequestIdMiddleware::new())
58 .middleware(SecurityHeaders::new())
59 .get("/", hello)
60 .build();
61
62 let client = TestClient::new(app);
63 let response = client.get("/").send();
64 println!(" GET / -> {}", response.status().as_u16());
65 assert_eq!(response.status().as_u16(), 200);
66
67 // === App with Configuration ===
68 println!("\n3. App with configuration:");
69 let config = AppConfig::new()
70 .name("My API")
71 .version("1.0.0")
72 .debug(true)
73 .max_body_size(10 * 1024 * 1024)
74 .request_timeout_ms(30_000);
75
76 let app = App::builder().config(config).get("/", hello).build();
77
78 println!(" App name: {}", app.config().name);
79 println!(" Version: {}", app.config().version);
80 assert_eq!(app.config().name, "My API");
81 assert_eq!(app.config().version, "1.0.0");
82
83 // === 404 for unknown routes ===
84 println!("\n4. 404 for unknown routes:");
85 let app = App::builder().get("/", hello).build();
86
87 let client = TestClient::new(app);
88 let response = client.get("/nonexistent").send();
89 println!(" GET /nonexistent -> {}", response.status().as_u16());
90 assert_eq!(response.status().as_u16(), 404);
91
92 println!("\nAll getting started examples validated successfully!");
93}examples/crud_api.rs (line 279)
252fn main() {
253 // Initialize the global store
254 *STORE.lock().unwrap() = Some(UserDb {
255 users: HashMap::new(),
256 next_id: 1,
257 });
258
259 println!("fastapi_rust CRUD API Example");
260 println!("=============================\n");
261
262 let app = App::builder()
263 .post("/users", create_user)
264 .get("/users", list_users)
265 .get("/users/{id}", get_user)
266 .put("/users/{id}", update_user)
267 .delete("/users/{id}", delete_user)
268 .build();
269
270 println!("App created with {} route(s)\n", app.route_count());
271 let client = TestClient::new(app);
272
273 // 1. Create users
274 println!("1. Create users");
275 let resp = client
276 .post("/users")
277 .header("content-type", "application/json")
278 .body(r#"{"name": "Alice", "email": "alice@example.com"}"#)
279 .send();
280 println!(
281 " POST /users -> {} {}",
282 resp.status().as_u16(),
283 resp.text()
284 );
285 assert_eq!(resp.status().as_u16(), 201);
286
287 let resp = client
288 .post("/users")
289 .header("content-type", "application/json")
290 .body(r#"{"name": "Bob", "email": "bob@example.com"}"#)
291 .send();
292 println!(
293 " POST /users -> {} {}",
294 resp.status().as_u16(),
295 resp.text()
296 );
297 assert_eq!(resp.status().as_u16(), 201);
298
299 // 2. List users
300 println!("\n2. List all users");
301 let resp = client.get("/users").send();
302 println!(
303 " GET /users -> {} {}",
304 resp.status().as_u16(),
305 resp.text()
306 );
307 assert_eq!(resp.status().as_u16(), 200);
308
309 // 3. Get user by ID
310 println!("\n3. Get user by ID");
311 let resp = client.get("/users/1").send();
312 println!(
313 " GET /users/1 -> {} {}",
314 resp.status().as_u16(),
315 resp.text()
316 );
317 assert_eq!(resp.status().as_u16(), 200);
318
319 // 4. Get nonexistent user
320 println!("\n4. Get nonexistent user");
321 let resp = client.get("/users/999").send();
322 println!(
323 " GET /users/999 -> {} {}",
324 resp.status().as_u16(),
325 resp.text()
326 );
327 assert_eq!(resp.status().as_u16(), 404);
328
329 // 5. Update user
330 println!("\n5. Update user");
331 let resp = client
332 .put("/users/1")
333 .header("content-type", "application/json")
334 .body(r#"{"name": "Alice Smith", "email": "alice.smith@example.com"}"#)
335 .send();
336 println!(
337 " PUT /users/1 -> {} {}",
338 resp.status().as_u16(),
339 resp.text()
340 );
341 assert_eq!(resp.status().as_u16(), 200);
342
343 // 6. Validation: empty name
344 println!("\n6. Validation error (empty name)");
345 let resp = client
346 .post("/users")
347 .header("content-type", "application/json")
348 .body(r#"{"name": "", "email": "bad@example.com"}"#)
349 .send();
350 println!(
351 " POST /users -> {} {}",
352 resp.status().as_u16(),
353 resp.text()
354 );
355 assert_eq!(resp.status().as_u16(), 400);
356
357 // 7. Validation: invalid email
358 println!("\n7. Validation error (invalid email)");
359 let resp = client
360 .post("/users")
361 .header("content-type", "application/json")
362 .body(r#"{"name": "Charlie", "email": "not-an-email"}"#)
363 .send();
364 println!(
365 " POST /users -> {} {}",
366 resp.status().as_u16(),
367 resp.text()
368 );
369 assert_eq!(resp.status().as_u16(), 400);
370
371 // 8. Wrong Content-Type
372 println!("\n8. Wrong Content-Type");
373 let resp = client
374 .post("/users")
375 .header("content-type", "text/plain")
376 .body(r#"{"name": "Dan", "email": "dan@example.com"}"#)
377 .send();
378 println!(
379 " POST /users -> {} {}",
380 resp.status().as_u16(),
381 resp.text()
382 );
383 assert_eq!(resp.status().as_u16(), 415);
384
385 // 9. Delete user
386 println!("\n9. Delete user");
387 let resp = client.delete("/users/2").send();
388 println!(" DELETE /users/2 -> {}", resp.status().as_u16());
389 assert_eq!(resp.status().as_u16(), 204);
390
391 // 10. Verify deletion
392 println!("\n10. Verify deletion");
393 let resp = client.get("/users/2").send();
394 println!(
395 " GET /users/2 -> {} {}",
396 resp.status().as_u16(),
397 resp.text()
398 );
399 assert_eq!(resp.status().as_u16(), 404);
400
401 let resp = client.get("/users").send();
402 println!(
403 " GET /users -> {} {}",
404 resp.status().as_u16(),
405 resp.text()
406 );
407 assert_eq!(resp.status().as_u16(), 200);
408
409 println!("\nAll CRUD operations passed!");
410}examples/auth_example.rs (line 271)
248fn main() {
249 println!("fastapi_rust Authentication Example");
250 println!("====================================\n");
251
252 // Build the application with public and protected routes
253 let app = App::builder()
254 // Public endpoints - accessible to everyone
255 .get("/public", public_handler)
256 // Login endpoint - returns a token
257 .post("/login", login_handler)
258 // Protected endpoint - requires valid bearer token
259 .get("/protected", protected_handler)
260 .build();
261
262 println!("App created with {} route(s)\n", app.route_count());
263
264 // Create a test client
265 let client = TestClient::new(app);
266
267 // =========================================================================
268 // Test 1: Public endpoint - no auth required
269 // =========================================================================
270 println!("1. Public endpoint - no auth required");
271 let response = client.get("/public").send();
272 println!(
273 " GET /public -> {} {}",
274 response.status().as_u16(),
275 response.status().canonical_reason()
276 );
277 assert_eq!(response.status().as_u16(), 200);
278 assert!(response.text().contains("public endpoint"));
279
280 // =========================================================================
281 // Test 2: Protected endpoint - without token (should get 401)
282 // =========================================================================
283 println!("\n2. Protected endpoint - without token");
284 let response = client.get("/protected").send();
285 println!(
286 " GET /protected -> {} {}",
287 response.status().as_u16(),
288 response.status().canonical_reason()
289 );
290 assert_eq!(
291 response.status().as_u16(),
292 401,
293 "Protected endpoint should return 401 without token"
294 );
295
296 // Check for WWW-Authenticate header
297 let has_www_auth = response
298 .headers()
299 .iter()
300 .any(|(name, value)| name == "www-authenticate" && value == b"Bearer");
301 assert!(
302 has_www_auth,
303 "401 response should include WWW-Authenticate: Bearer header"
304 );
305
306 // =========================================================================
307 // Test 3: Login endpoint - get a token
308 // =========================================================================
309 println!("\n3. Login endpoint - get a token");
310 let response = client
311 .post("/login")
312 .header("content-type", "application/json")
313 .body(r#"{"username":"test","password":"test123"}"#)
314 .send();
315 println!(
316 " POST /login -> {} {}",
317 response.status().as_u16(),
318 response.status().canonical_reason()
319 );
320 assert_eq!(response.status().as_u16(), 200);
321
322 // Parse the response to get the token
323 let body: serde_json::Value = serde_json::from_str(response.text()).unwrap();
324 let token = body["access_token"].as_str().unwrap();
325 println!(" Token: {token}");
326 assert_eq!(token, SECRET_TOKEN);
327
328 // =========================================================================
329 // Test 4: Protected endpoint - with valid token (should get 200)
330 // =========================================================================
331 println!("\n4. Protected endpoint - with valid token");
332 let response = client
333 .get("/protected")
334 .header("authorization", format!("Bearer {SECRET_TOKEN}"))
335 .send();
336 println!(
337 " GET /protected (Authorization: Bearer {}) -> {} {}",
338 SECRET_TOKEN,
339 response.status().as_u16(),
340 response.status().canonical_reason()
341 );
342 assert_eq!(
343 response.status().as_u16(),
344 200,
345 "Protected endpoint should return 200 with valid token"
346 );
347 assert!(response.text().contains("protected resource"));
348
349 // =========================================================================
350 // Test 5: Protected endpoint - with invalid token (should get 403)
351 // =========================================================================
352 println!("\n5. Protected endpoint - with invalid token");
353 let response = client
354 .get("/protected")
355 .header("authorization", "Bearer wrong_token")
356 .send();
357 println!(
358 " GET /protected (Authorization: Bearer wrong_token) -> {} {}",
359 response.status().as_u16(),
360 response.status().canonical_reason()
361 );
362 assert_eq!(
363 response.status().as_u16(),
364 403,
365 "Protected endpoint should return 403 with invalid token"
366 );
367
368 // =========================================================================
369 // Test 6: Protected endpoint - with wrong auth scheme (should get 401)
370 // =========================================================================
371 println!("\n6. Protected endpoint - with wrong auth scheme");
372 let response = client
373 .get("/protected")
374 .header("authorization", "Basic dXNlcjpwYXNz")
375 .send();
376 println!(
377 " GET /protected (Authorization: Basic ...) -> {} {}",
378 response.status().as_u16(),
379 response.status().canonical_reason()
380 );
381 assert_eq!(
382 response.status().as_u16(),
383 401,
384 "Protected endpoint should return 401 with wrong auth scheme"
385 );
386
387 // =========================================================================
388 // Test 7: Login with wrong Content-Type (should get 415)
389 // =========================================================================
390 println!("\n7. Login with wrong Content-Type");
391 let response = client
392 .post("/login")
393 .header("content-type", "text/plain")
394 .body("username=test&password=test123")
395 .send();
396 println!(
397 " POST /login (Content-Type: text/plain) -> {} {}",
398 response.status().as_u16(),
399 response.status().canonical_reason()
400 );
401 assert_eq!(
402 response.status().as_u16(),
403 415,
404 "Login should return 415 with wrong Content-Type"
405 );
406
407 // =========================================================================
408 // Test 8: Token case sensitivity (lowercase 'bearer')
409 // =========================================================================
410 println!("\n8. Token case sensitivity (lowercase 'bearer')");
411 let response = client
412 .get("/protected")
413 .header("authorization", format!("bearer {SECRET_TOKEN}"))
414 .send();
415 println!(
416 " GET /protected (Authorization: bearer {}) -> {} {}",
417 SECRET_TOKEN,
418 response.status().as_u16(),
419 response.status().canonical_reason()
420 );
421 assert_eq!(
422 response.status().as_u16(),
423 200,
424 "Bearer scheme should be case-insensitive (lowercase accepted)"
425 );
426
427 println!("\nAll authentication tests passed!");
428}Auto Trait Implementations§
impl<'a, H> Freeze for RequestBuilder<'a, H>
impl<'a, H> !RefUnwindSafe for RequestBuilder<'a, H>
impl<'a, H> Send for RequestBuilder<'a, H>
impl<'a, H> Sync for RequestBuilder<'a, H>
impl<'a, H> Unpin for RequestBuilder<'a, H>
impl<'a, H> !UnwindSafe for RequestBuilder<'a, H>
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
Mutably borrows from an owned value. Read more
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, _span: NoopSpan) -> Self
fn instrument(self, _span: NoopSpan) -> Self
Instruments this future with a span (no-op when disabled).
Source§fn in_current_span(self) -> Self
fn in_current_span(self) -> Self
Instruments this future with the current span (no-op when disabled).