Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save u-na-gi/7d42a2029c23cc6074432a219ced2d3e to your computer and use it in GitHub Desktop.

Select an option

Save u-na-gi/7d42a2029c23cc6074432a219ced2d3e to your computer and use it in GitHub Desktop.

Building a Web App with Cloudflare Workers, D1, and Rust**

Chapter 1: Integrating Cloudflare D1 with Workers

  1. Introduction to D1
    D1 is Cloudflare’s SQLite-compatible database that is perfect for serverless environments like Cloudflare Workers. It brings SQL to the edge, enabling performant and durable queries.

  2. Setting Up D1 in Your Project
    Explain how to set up D1 by creating a new Cloudflare project and connecting D1. You can follow this process:

    • Install the Wrangler CLI
    • Set up D1 bindings in wrangler.toml
    • Create database migrations for tables

    Example:

    -- Create a table for storing quiz questions
    CREATE TABLE quiz (
        id UUID PRIMARY KEY,
        user_id UUID NOT NULL,
        question TEXT NOT NULL,
        correct_answer TEXT NOT NULL,
        explanation TEXT NOT NULL,
        time_limit INTEGER NOT NULL
    );
    
    -- Create a table for storing user answers
    CREATE TABLE user_answers (
        id UUID PRIMARY KEY,
        quiz_id UUID NOT NULL,
        answer TEXT NOT NULL,
        FOREIGN KEY (quiz_id) REFERENCES quiz(id) ON DELETE CASCADE
    );
  3. Performing Basic Queries with D1
    Show how to run basic queries like inserting and fetching data using Cloudflare Workers’ native support for SQL with D1. For instance:

    export async function fetch(request, env) {
        const { user_id, question, correct_answer, explanation, time_limit } = await request.json();
        const query = `
            INSERT INTO quiz (id, user_id, question, correct_answer, explanation, time_limit)
            VALUES (uuid(), ?, ?, ?, ?, ?)
        `;
        await env.DB.prepare(query).bind(user_id, question, correct_answer, explanation, time_limit).run();
        return new Response("Quiz created", { status: 201 });
    }

Chapter 2: Using Rust for Cloudflare Workers

  1. Why Use Rust?
    Rust is fast, memory-efficient, and offers great concurrency support. In serverless environments like Cloudflare Workers, this makes it ideal for handling backend logic that needs to be secure and scalable.

  2. Setting Up Rust with Cloudflare Workers
    Walk through installing Rust and configuring it in a Cloudflare Workers project. The Wrangler CLI makes this simple:

    • Install wasm-pack for building Rust projects targeting WebAssembly.
    • Set up a basic Rust function that handles an HTTP request.

    Example:

    use worker::*;
    
    #[event(fetch)]
    pub async fn main(req: Request, env: Env) -> Result<Response> {
        Response::ok("Hello from Rust on Cloudflare Workers!")
    }
  3. Implementing Rust Functions for API Calls
    Walk through how to create and handle logic like creating a new quiz in Rust. This integrates with D1:

    use worker::*;
    
    #[event(fetch)]
    pub async fn main(req: Request, env: Env) -> Result<Response> {
        let data: serde_json::Value = req.json().await?;
        let quiz_id = Uuid::new_v4().to_string();
        let query = format!(
            "INSERT INTO quiz (id, user_id, question, correct_answer, explanation, time_limit) VALUES ('{}', '{}', '{}', '{}', '{}', {})",
            quiz_id, data["user_id"].as_str().unwrap(), data["question"].as_str().unwrap(), data["correct_answer"].as_str().unwrap(), data["explanation"].as_str().unwrap(), data["time_limit"].as_i64().unwrap()
        );
        env.db().prepare(&query).run().await?;
        Response::ok("Quiz created!")
    }

Chapter 3: Handling Database Operations in Rust with D1

  1. Fetching Data from D1
    Show how to retrieve data from the D1 database using Rust and handle it within the worker. For example, fetching all quiz data:

    #[event(fetch)]
    pub async fn main(req: Request, env: Env) -> Result<Response> {
        let query = "SELECT id, question, correct_answer FROM quiz";
        let results = env.db().prepare(query).query_map().await?;
        
        let quizzes: Vec<Quiz> = results.map(|row| {
            Quiz {
                id: row.get("id"),
                question: row.get("question"),
                correct_answer: row.get("correct_answer")
            }
        }).collect();
        
        Response::from_json(&quizzes)
    }
    
    #[derive(serde::Serialize)]
    struct Quiz {
        id: String,
        question: String,
        correct_answer: String,
    }
  2. Updating and Deleting Data
    Demonstrate how to update a record, such as when a user answers a question, or delete outdated quizzes:

    #[event(fetch)]
    pub async fn main(req: Request, env: Env) -> Result<Response> {
        let data: serde_json::Value = req.json().await?;
        let quiz_id = data["quiz_id"].as_str().unwrap();
        let new_answer = data["new_answer"].as_str().unwrap();
        let query = format!("UPDATE quiz SET correct_answer = '{}' WHERE id = '{}'", new_answer, quiz_id);
        env.db().prepare(&query).run().await?;
        Response::ok("Answer updated!")
    }

Conclusion: By focusing on Rust and D1, developers can harness the full power of serverless environments to create fast, secure, and scalable web apps. Cloudflare Workers combined with Rust makes handling API calls, database queries, and serverless logic both efficient and effective.

@u-na-gi

u-na-gi commented Sep 30, 2024

Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment