serverless-fn 0.1.0

A Rust library for simplifying serverless function development and invocation
Documentation
//! Example usage of the serverless function library

use serde::{Deserialize, Serialize};
use serverless_fn::server::Server;
use serverless_fn::{ServerlessError, serverless};

// Example serverless function
#[serverless]
pub async fn read_posts(how_many: usize, query: String) -> Result<Vec<Post>, ServerlessError> {
    // Simulate reading posts from a database
    let posts = (0..how_many)
        .map(|i| Post {
            id: i as u64,
            title: format!("{query} {}", i),
            content: format!("Content of post {}", i),
        })
        .collect();

    Ok(posts)
}

// Another example function
#[serverless]
pub async fn create_post(title: String, content: String) -> Result<Post, ServerlessError> {
    let post = Post {
        id: 1,
        title,
        content,
    };

    Ok(post)
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Post {
    pub id: u64,
    pub title: String,
    pub content: String,
}

// Main function demonstrating usage
#[tokio::main]
async fn main() -> Result<(), ServerlessError> {
    // Check command line arguments to decide whether to run as server or client
    let args: Vec<String> = std::env::args().collect();

    if args.len() > 1 && args[1] == "--serve" {
        // Run as server
        run_server().await?;
    } else {
        // Run as client
        run_client().await?;
    }

    Ok(())
}

async fn run_client() -> Result<(), ServerlessError> {
    // Initialize logging
    let config = serverless_fn::config::Config::from_env();
    config.init_logging();

    // Initialize telemetry if enabled
    serverless_fn::telemetry::init_telemetry();

    // Call the serverless function as if it were a regular function
    let posts = read_posts(3, "my search".to_string()).await?;
    println!("Retrieved {} posts", posts.len());

    for post in &posts {
        println!("Post {}: {}", post.id, post.title);
    }

    // Call another function
    let new_post =
        create_post("New Post Title".to_string(), "New Post Content".to_string()).await?;

    println!("Created post: {}", new_post.title);

    Ok(())
}

async fn run_server() -> Result<(), ServerlessError> {
    println!("Starting serverless function server...");
    let host = "0.0.0.0";
    let port = 3000;
    println!("Server listening on http://{}:{}", host, port);

    // Start the server - all functions marked with #[serverless] are automatically registered
    // via the inventory crate
    Server::new()
        .host(host)
        .port(port)
        .start()
        .await
        .map_err(|e| ServerlessError::RemoteExecution(e.to_string()))?;

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_read_posts() {
        let posts = read_posts(2, "test".to_string()).await.unwrap();
        assert_eq!(posts.len(), 2);
        assert_eq!(posts[0].title, "Post 0");
        assert_eq!(posts[1].title, "Post 1");
    }

    #[tokio::test]
    async fn test_create_post() {
        let post = create_post("Test Title".to_string(), "Test Content".to_string())
            .await
            .unwrap();
        assert_eq!(post.title, "Test Title");
        assert_eq!(post.content, "Test Content");
    }
}