Ejemplos de Redes Web Rust

Ejemplos de redes Web Rust incluyendo solicitudes HTTP, servidor HTTP y sockets TCP

💻 Solicitudes HTTP rust

🟢 simple ⭐⭐⭐

Enviar solicitudes GET y POST usando reqwest o hyper crates

⏱️ 20 min 🏷️ rust, web, networking, http
Prerequisites: Basic Rust, reqwest crate, tokio
// Web Rust HTTP Request Examples
// Using reqwest crate for HTTP client functionality

use std::collections::HashMap;
use std::time::Duration;

// Note: This requires the reqwest crate
// Add to Cargo.toml:
// [dependencies]
// reqwest = { version = "0.11", features = ["json"] }
// tokio = { version = "1", features = ["full"] }

// 1. Basic GET Request

/// Simple GET request
async fn simple_get_request(url: &str) -> Result<String, Box<dyn std::error::Error>> {
    let response = reqwest::get(url).await?;
    let body = response.text().await?;
    Ok(body)
}

/// GET request with headers
async fn get_with_headers(url: &str) -> Result<String, Box<dyn std::error::Error>> {
    let client = reqwest::Client::builder()
        .timeout(Duration::from_secs(10))
        .build()?;

    let response = client
        .get(url)
        .header("User-Agent", "My Rust Client")
        .header("Accept", "application/json")
        .send()
        .await?;

    let body = response.text().await?;
    Ok(body)
}

/// GET request with query parameters
async fn get_with_query_params(
    base_url: &str,
    params: &HashMap<String, String>,
) -> Result<String, Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .get(base_url)
        .query(params)
        .send()
        .await?;

    let body = response.text().await?;
    Ok(body)
}

// 2. POST Request

/// POST JSON data
async fn post_json(
    url: &str,
    data: &serde_json::Value,
) -> Result<String, Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post(url)
        .header("Content-Type", "application/json")
        .json(data)
        .send()
        .await?;

    let body = response.text().await?;
    Ok(body)
}

/// POST form data
async fn post_form(
    url: &str,
    form_data: &HashMap<String, String>,
) -> Result<String, Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post(url)
        .form(form_data)
        .send()
        .await?;

    let body = response.text().await?;
    Ok(body)
}

/// POST raw bytes
async fn post_bytes(
    url: &str,
    data: &[u8],
) -> Result<String, Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .post(url)
        .body(data.to_vec())
        .send()
        .await?;

    let body = response.text().await?;
    Ok(body)
}

// 3. Response Handling

/// Get response headers
async fn get_response_headers(url: &str) -> Result<HashMap<String, String>, Box<dyn std::error::Error>> {
    let response = reqwest::get(url).await?;

    let mut headers = HashMap::new();
    for (key, value) in response.headers() {
        headers.insert(
            key.as_str().to_string(),
            value.to_str().unwrap_or("").to_string(),
        );
    }

    Ok(headers)
}

/// Check response status
async fn check_status(url: &str) -> Result<bool, Box<dyn std::error::Error>> {
    let response = reqwest::get(url).await?;
    Ok(response.status().is_success())
}

/// Download file
async fn download_file(url: &str, output_path: &str) -> Result<(), Box<dyn std::error::Error>> {
    let response = reqwest::get(url).await?;
    let bytes = response.bytes().await?;
    tokio::fs::write(output_path, &bytes).await?;
    Ok(())
}

// 4. HTTP Client with Configuration

/// Create custom HTTP client
fn create_http_client() -> reqwest::Client {
    reqwest::Client::builder()
        .timeout(Duration::from_secs(30))
        .connect_timeout(Duration::from_secs(10))
        .pool_max_idle_per_host(10)
        .build()
        .expect("Failed to create client")
}

/// Reusable client for multiple requests
async fn multiple_requests(base_url: &str) -> Result<(), Box<dyn std::error::Error>> {
    let client = create_http_client();

    // First request
    let _response1 = client.get(&format!("{}/users", base_url)).send().await?;

    // Second request
    let _response2 = client
        .get(&format!("{}/posts", base_url))
        .send()
        .await?;

    Ok(())
}

// 5. Authentication

/// Basic authentication
async fn basic_auth_request(
    url: &str,
    username: &str,
    password: &str,
) -> Result<String, Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .get(url)
        .basic_auth(username, Some(password))
        .send()
        .await?;

    Ok(response.text().await?)
}

/// Bearer token authentication
async fn bearer_auth_request(
    url: &str,
    token: &str,
) -> Result<String, Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let response = client
        .get(url)
        .header("Authorization", format!("Bearer {}", token))
        .send()
        .await?;

    Ok(response.text().await?)
}

// Usage Examples
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Web Rust HTTP Request Examples ===\n");

    // 1. Simple GET
    println!("--- 1. Simple GET Request ---");
    match simple_get_request("https://httpbin.org/get").await {
        Ok(body) => println!("Response: {}\n", &body[..std::cmp::min(200, body.len())]),
        Err(e) => println!("Error: {}\n", e),
    }

    // 2. GET with headers
    println!("--- 2. GET with Headers ---");
    match get_with_headers("https://httpbin.org/headers").await {
        Ok(body) => println!("Response: {}\n", &body[..std::cmp::min(200, body.len())]),
        Err(e) => println!("Error: {}\n", e),
    }

    // 3. POST JSON
    println!("--- 3. POST JSON ---");
    let data = serde_json::json!({"key": "value", "number": 42});
    match post_json("https://httpbin.org/post", &data).await {
        Ok(body) => println!("Response: {}\n", &body[..std::cmp::min(200, body.len())]),
        Err(e) => println!("Error: {}\n", e),
    }

    // 4. Check status
    println!("--- 4. Check Status ---");
    match check_status("https://httpbin.org/status/200").await {
        Ok(success) => println!("Request successful: {}\n", success),
        Err(e) => println!("Error: {}\n", e),
    }

    println!("=== All HTTP Request Examples Completed ===");
    Ok(())
}

💻 Servidor HTTP rust

🟡 intermediate ⭐⭐⭐⭐

Crear servidores HTTP usando hyper o actix-web frameworks

⏱️ 30 min 🏷️ rust, web, networking, server
Prerequisites: Intermediate Rust, hyper crate, tokio
// Web Rust HTTP Server Examples
// Using hyper crate for HTTP server functionality

use std::collections::HashMap;
use std::convert::Infallible;
use std::net::SocketAddr;

// Note: This requires the hyper and tokio crates
// Add to Cargo.toml:
// [dependencies]
// hyper = { version = "0.14", features = ["full"] }
// tokio = { version = "1", features = ["full"] }

// 1. Basic HTTP Server

/// Basic hello world server
async fn basic_server() {
    #[hyper::server::macros::service]
    fn hello_world(_req: hyper::Body) -> hyper::Response<hyper::Body> {
        hyper::Response::new(hyper::Body::from("Hello, World!"))
    }

    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    let server = hyper::Server::bind(&addr).serve(hyper::service(hello_world));

    println!("Listening on http://{}", addr);

    if let Err(e) = server.await {
        eprintln!("Server error: {}", e);
    }
}

// 2. Route-Based Server

/// Simple router
struct Router {
    routes: HashMap<String, hyper::Body>,
}

impl Router {
    fn new() -> Self {
        let mut routes = HashMap::new();
        routes.insert("/".to_string(), hyper::Body::from("Home Page"));
        routes.insert("/about".to_string(), hyper::Body::from("About Page"));
        routes.insert("/contact".to_string(), hyper::Body::from("Contact Page"));
        Router { routes }
    }

    fn handle(&self, req: hyper::Request<hyper::Body>) -> hyper::Response<hyper::Body> {
        let path = req.uri().path();

        match self.routes.get(path) {
            Some(body) => hyper::Response::new(body.clone()),
            None => hyper::Response::builder()
                .status(hyper::StatusCode::NOT_FOUND)
                .body(hyper::Body::from("404 - Not Found"))
                .unwrap(),
        }
    }
}

/// Run router server
async fn router_server() {
    let router = Router::new();

    let make_service = hyper::service::make_service_fn(move |_| {
        let router = router.clone();
        async move {
            Ok::<_, Infallible>(hyper::service::service_fn(move |req| {
                async move { Ok::<_, Infallible>(router.handle(req)) }
            }))
        }
    });

    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    let server = hyper::Server::bind(&addr).serve(make_service);

    println!("Router listening on http://{}", addr);

    if let Err(e) = server.await {
        eprintln!("Server error: {}", e);
    }
}

// 3. JSON API Server

/// User data structure
#[derive(serde::Serialize, serde::Deserialize)]
struct User {
    id: u32,
    name: String,
    email: String,
}

/// Handle GET /users
async fn get_users() -> hyper::Response<hyper::Body> {
    let users = vec![
        User { id: 1, name: "Alice".to_string(), email: "[email protected]".to_string() },
        User { id: 2, name: "Bob".to_string(), email: "[email protected]".to_string() },
    ];

    match serde_json::to_string(&users) {
        Ok(json) => hyper::Response::new(hyper::Body::from(json)),
        Err(_) => hyper::Response::builder()
            .status(hyper::StatusCode::INTERNAL_SERVER_ERROR)
            .body(hyper::Body::from("Error serializing JSON"))
            .unwrap(),
    }
}

/// Handle POST /users
async fn create_user(body: hyper::Body) -> hyper::Response<hyper::Body> {
    let whole_body = match hyper::body::to_bytes(body).await {
        Ok(bytes) => bytes,
        Err(e) => {
            return hyper::Response::builder()
                .status(hyper::StatusCode::BAD_REQUEST)
                .body(hyper::Body::from(format!("Error reading body: {}", e)))
                .unwrap();
        }
    };

    match serde_json::from_slice::<User>(&whole_body) {
        Ok(user) => {
            match serde_json::to_string(&user) {
                Ok(json) => hyper::Response::builder()
                    .status(hyper::StatusCode::CREATED)
                    .body(hyper::Body::from(json))
                    .unwrap(),
                Err(_) => hyper::Response::builder()
                    .status(hyper::StatusCode::INTERNAL_SERVER_ERROR)
                    .body(hyper::Body::from("Error serializing JSON"))
                    .unwrap(),
            }
        }
        Err(e) => hyper::Response::builder()
            .status(hyper::StatusCode::BAD_REQUEST)
            .body(hyper::Body::from(format!("Invalid JSON: {}", e)))
            .unwrap(),
    }
}

/// API request handler
async fn api_handler(req: hyper::Request<hyper::Body>) -> hyper::Response<hyper::Body> {
    let method = req.method().clone();
    let uri = req.uri().clone();
    let path = uri.path();

    match (method.as_str(), path) {
        ("GET", "/users") => get_users().await,
        ("POST", "/users") => create_user(req.into_body()).await,
        _ => hyper::Response::builder()
            .status(hyper::StatusCode::NOT_FOUND)
            .body(hyper::Body::from("404 - Not Found"))
            .unwrap(),
    }
}

/// Run API server
async fn api_server() {
    let make_service = hyper::service::make_service_fn(|_| async {
        Ok::<_, Infallible>(hyper::service::service_fn(|req| {
            async move { Ok::<_, Infallible>(api_handler(req).await) }
        }))
    });

    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    let server = hyper::Server::bind(&addr).serve(make_service);

    println!("API server listening on http://{}", addr);

    if let Err(e) = server.await {
        eprintln!("Server error: {}", e);
    }
}

// 4. Server with Middleware

/// Middleware to log requests
async fn logging_middleware(
    req: hyper::Request<hyper::Body>,
    next: hyper::body::Sender,
) -> Result<hyper::Response<hyper::Body>, Infallible> {
    println!("{} {}", req.method(), req.uri().path());
    // In a real implementation, you would call the next handler here
    Ok(hyper::Response::new(hyper::Body::from("Logged")))
}

/// Middleware to add CORS headers
fn add_cors_headers(mut response: hyper::Response<hyper::Body>) -> hyper::Response<hyper::Body> {
    response.headers_mut().insert("Access-Control-Allow-Origin", "*".parse().unwrap());
    response.headers_mut().insert("Access-Control-Allow-Methods", "GET, POST, OPTIONS".parse().unwrap());
    response
}

// 5. Static File Server

/// Serve static files
async fn serve_static(file_path: &str) -> hyper::Response<hyper::Body> {
    match tokio::fs::read(file_path).await {
        Ok(contents) => {
            let mime_type = mime_guess::from_path(file_path)
                .first_or_octet_stream()
                .to_string();

            hyper::Response::builder()
                .header("Content-Type", mime_type)
                .body(hyper::Body::from(contents))
                .unwrap()
        }
        Err(_) => hyper::Response::builder()
            .status(hyper::StatusCode::NOT_FOUND)
            .body(hyper::Body::from("File not found"))
            .unwrap(),
    }
}

// Usage Examples
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Web Rust HTTP Server Examples ===\n");

    println!("Choose server type:");
    println!("1. Basic server");
    println!("2. Router server");
    println!("3. API server");
    println!();
    println!("Uncomment the server you want to run:");
    println!("basic_server().await;");
    println!("router_server().await;");
    println!("api_server().await;");

    // Example: Start basic server (commented out)
    // basic_server().await;

    Ok(())
}

💻 Sockets TCP rust

🟡 intermediate ⭐⭐⭐

Crear conexiones TCP y construir servidores y clientes TCP

⏱️ 25 min 🏷️ rust, web, networking, tcp
Prerequisites: Intermediate Rust, std::net
// Web Rust TCP Socket Examples
// Using std::net for TCP networking

use std::io::{BufRead, BufReader, Write};
use std::net::{TcpListener, TcpStream};
use std::thread;
use std::time::Duration;

// 1. TCP Server

/// Simple echo server
fn run_echo_server(address: &str) -> std::io::Result<()> {
    let listener = TcpListener::bind(address)?;
    println!("Echo server listening on {}", address);

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                handle_client(stream)?;
            }
            Err(e) => {
                eprintln!("Error accepting connection: {}", e);
            }
        }
    }

    Ok(())
}

/// Handle individual client connection
fn handle_client(mut stream: TcpStream) -> std::io::Result<()> {
    let peer_addr = stream.peer_addr()?;
    println!("New connection from {}", peer_addr);

    let mut reader = BufReader::new(&stream);

    loop {
        let mut line = String::new();
        let bytes_read = reader.read_line(&mut line)?;

        if bytes_read == 0 {
            break;
        }

        print!("Received: {}", line);

        // Echo back
        stream.write_all(line.as_bytes())?;
    }

    println!("Connection closed from {}", peer_addr);
    Ok(())
}

// 2. TCP Client

/// Connect to TCP server
fn connect_to_server(address: &str) -> std::io::Result<TcpStream> {
    TcpStream::connect(address)
}

/// Send message to server
fn send_message(stream: &mut TcpStream, message: &str) -> std::io::Result<()> {
    stream.write_all(message.as_bytes())?;
    stream.flush()
}

/// Read response from server
fn read_response(stream: &mut TcpStream) -> std::io::Result<String> {
    let mut reader = BufReader::new(stream);
    let mut response = String::new();
    reader.read_line(&mut response)?;
    Ok(response)
}

/// Simple TCP client
fn run_echo_client(address: &str) -> std::io::Result<()> {
    let mut stream = connect_to_server(address)?;
    println!("Connected to {}", address);

    // Send message
    let message = "Hello, TCP Server!\n";
    send_message(&mut stream, message)?;
    println!("Sent: {}", message.trim());

    // Read response
    let response = read_response(&mut stream)?;
    println!("Received: {}", response.trim());

    Ok(())
}

// 3. Multi-threaded Server

/// Multi-threaded echo server
fn run_multi_threaded_server(address: &str) -> std::io::Result<()> {
    let listener = TcpListener::bind(address)?;
    println!("Multi-threaded server listening on {}", address);

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                thread::spawn(move || {
                    if let Err(e) = handle_client(stream) {
                        eprintln!("Error handling client: {}", e);
                    }
                });
            }
            Err(e) => {
                eprintln!("Error accepting connection: {}", e);
            }
        }
    }

    Ok(())
}

// 4. Server with Protocol

/// Chat message
#[derive(Debug)]
struct ChatMessage {
    username: String,
    content: String,
}

impl ChatMessage {
    fn parse(line: &str) -> Option<ChatMessage> {
        let parts: Vec<&str> = line.splitn(2, ':').collect();
        if parts.len() == 2 {
            Some(ChatMessage {
                username: parts[0].trim().to_string(),
                content: parts[1].trim().to_string(),
            })
        } else {
            None
        }
    }

    fn format(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }
}

/// Chat server
fn run_chat_server(address: &str) -> std::io::Result<()> {
    let listener = TcpListener::bind(address)?;
    println!("Chat server listening on {}", address);

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                thread::spawn(move || {
                    if let Err(e) = handle_chat_client(stream) {
                        eprintln!("Error handling chat client: {}", e);
                    }
                });
            }
            Err(e) => {
                eprintln!("Error accepting connection: {}", e);
            }
        }
    }

    Ok(())
}

/// Handle chat client
fn handle_chat_client(mut stream: TcpStream) -> std::io::Result<()> {
    let peer_addr = stream.peer_addr()?;
    println!("Chat client connected from {}", peer_addr);

    // Welcome message
    stream.write_all(b"Welcome to the chat server!\n")?;

    let mut reader = BufReader::new(&stream);

    loop {
        let mut line = String::new();
        let bytes_read = reader.read_line(&mut line)?;

        if bytes_read == 0 {
            break;
        }

        if let Some(msg) = ChatMessage::parse(&line) {
            println!("Chat: {:?}", msg);
            let response = format!("Message received: {}\n", msg.content);
            stream.write_all(response.as_bytes())?;
        } else {
            stream.write_all(b"Invalid message format. Use: username: message\n")?;
        }
    }

    println!("Chat client disconnected: {}", peer_addr);
    Ok(())
}

// 5. TCP Client with Timeout

/// Connect with timeout
fn connect_with_timeout(address: &str, timeout: Duration) -> std::io::Result<TcpStream> {
    TcpStream::connect_timeout(&address.parse().unwrap(), timeout)
}

/// Client with timeout
fn run_timeout_client(address: &str) -> std::io::Result<()> {
    let timeout = Duration::from_secs(5);

    match connect_with_timeout(address, timeout) {
        Ok(mut stream) => {
            println!("Connected to {}", address);

            stream.set_read_timeout(Some(timeout))?;
            stream.set_write_timeout(Some(timeout))?;

            send_message(&mut stream, "Hello\n")?;
            let response = read_response(&mut stream)?;
            println!("Response: {}", response.trim());

            Ok(())
        }
        Err(e) => {
            Err(e)
        }
    }
}

// 6. Broadcast Server

/// Broadcast message to all connected clients
fn run_broadcast_server(address: &str) -> std::io::Result<()> {
    let listener = TcpListener::bind(address)?;
    println!("Broadcast server listening on {}", address);

    let mut clients: Vec<TcpStream> = Vec::new();

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                println!("Client connected");
                clients.push(stream);
            }
            Err(e) => {
                eprintln!("Error accepting connection: {}", e);
            }
        }
    }

    Ok(())
}

// Usage Examples
fn main() -> std::io::Result<()> {
    println!("=== Web Rust TCP Socket Examples ===\n");

    println!("Choose example:");
    println!("1. Echo server");
    println!("2. Echo client");
    println!("3. Multi-threaded server");
    println!("4. Chat server");
    println!();
    println!("Uncomment the example you want to run:");
    println!("run_echo_server('127.0.0.1:8080')?;");
    println!("run_echo_client('127.0.0.1:8080')?;");
    println!("run_multi_threaded_server('127.0.0.1:8080')?;");
    println!("run_chat_server('127.0.0.1:8080')?;");

    // Example: Start echo server (commented out)
    // run_echo_server("127.0.0.1:8080")?;

    Ok(())
}