blog

A modern blog platform where users can register with username/password, create their own blog posts, and view all posts in a global timeline as well as individual user blogs.

Preview
Source CodeVersion 2
export default {
  async fetch(request, env) {
    const url = new URL(request.url);

    // API routes
    if (url.pathname.startsWith('/api/')) {
      return handleAPI(request, env, url);
    }

    // Serve HTML
    return new Response(getHTML(), {
      headers: { 'Content-Type': 'text/html' }
    });
  }
};

async function handleAPI(request, env, url) {
  const path = url.pathname;
  
  if (path === '/api/register' && request.method === 'POST') {
    const { username, password } = await request.json();
    
    if (!username || !password) {
      return new Response(JSON.stringify({ error: 'Username and password required' }), {
        status: 400,
        headers: { 'Content-Type': 'application/json' }
      });
    }

    // Check if user exists
    const existing = await env.DB.prepare('SELECT id FROM users WHERE username = ?1').bind(username).first();
    if (existing) {
      return new Response(JSON.stringify({ error: 'Username already taken' }), {
        status: 409,
        headers: { 'Content-Type': 'application/json' }
      });
    }

    // Create user
    const userId = crypto.randomUUID();
    await env.DB.prepare('INSERT INTO users (id, username, password, created_at) VALUES (?1, ?2, ?3, datetime("now"))')
      .bind(userId, username, password).run();

    return new Response(JSON.stringify({ data: { id: userId, username } }), {
      headers: { 'Content-Type': 'application/json' }
    });
  }

  if (path === '/api/login' && request.method === 'POST') {
    const { username, password } = await request.json();
    
    const user = await env.DB.prepare('SELECT * FROM users WHERE username = ?1 AND password = ?2')
      .bind(username, password).first();
    
    if (!user) {
      return new Response(JSON.stringify({ error: 'Invalid credentials' }), {
        status: 401,
        headers: { 'Content-Type': 'application/json' }
      });
    }

    return new Response(JSON.stringify({ data: { id: user.id, username: user.username } }), {
      headers: { 'Content-Type': 'application/json' }
    });
  }

  if (path === '/api/posts' && request.method === 'GET') {
    const userId = url.searchParams.get('userId');
    
    let query = `
      SELECT p.*, u.username 
      FROM posts p 
      JOIN users u ON p.user_id = u.id
    `;
    
    if (userId) {
      query += ' WHERE p.user_id = ?1';
    }
    
    query += ' ORDER BY p.created_at DESC LIMIT 50';
    
    const stmt = userId ? env.DB.prepare(query).bind(userId) : env.DB.prepare(query);
    const posts = await stmt.all();

    return new Response(JSON.stringify({ data: posts.results || [] }), {
      headers: { 'Content-Type': 'application/json' }
    });
  }

  if (path === '/api/posts' && request.method === 'POST') {
    const { userId, title, content } = await request.json();
    
    if (!userId || !title || !content) {
      return new Response(JSON.stringify({ error: 'User ID, title and content required' }), {
        status: 400,
        headers: { 'Content-Type': 'application/json' }
      });
    }

    const postId = crypto.randomUUID();
    await env.DB.prepare('INSERT INTO posts (id, user_id, title, content, created_at) VALUES (?1, ?2, ?3, ?4, datetime("now"))')
      .bind(postId, userId, title, content).run();

    return new Response(JSON.stringify({ data: { id: postId } }), {
      headers: { 'Content-Type': 'application/json' }
    });
  }

  if (path === '/api/user' && request.method === 'GET') {
    const username = url.searchParams.get('username');
    
    if (!username) {
      return new Response(JSON.stringify({ error: 'Username required' }), {
        status: 400,
        headers: { 'Content-Type': 'application/json' }
      });
    }

    const user = await env.DB.prepare('SELECT id, username, created_at FROM users WHERE username = ?1')
      .bind(username).first();
    
    if (!user) {
      return new Response(JSON.stringify({ error: 'User not found' }), {
        status: 404,
        headers: { 'Content-Type': 'application/json' }
      });
    }

    return new Response(JSON.stringify({ data: user }), {
      headers: { 'Content-Type': 'application/json' }
    });
  }

  return new Response(JSON.stringify({ error: 'Not found' }), {
    status: 404,
    headers: { 'Content-Type': 'application/json' }
  });
}

function getHTML() {
  return `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>BlogSpace - Your Creative Platform</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
  <style>
    body { font-family: 'Inter', sans-serif; }
    .gradient-bg { background: linear-gradient(135deg, #8B5CF6 0%, #3B82F6 100%); }
    .glass { background: rgba(255, 255, 255, 0.05); backdrop-filter: blur(10px); }
    .shimmer {
      background: linear-gradient(90deg, transparent, rgba(255,255,255,0.1)
...

Comments (0)

No comments yet. Be the first!