blog
by@Dusk
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)
...
No comments yet. Be the first!