This document describes the HTTP endpoints and request/response formats for the Cosmopolitan web application.
http://localhost:8080
- HTML Responses:
text/html; charset=utf-8 - Form Submissions:
application/x-www-form-urlencoded - File Uploads:
multipart/form-data
All GET requests support the lang parameter for internationalization:
?lang=en # English
?lang=zh-cn # Simplified Chinese
The language preference is also stored in a cookie (lang) with 1-year expiry.
GET /
List all message boards.
Parameters:
lang(optional) - Language code (en, zh-cn)
Response:
<!DOCTYPE html>
<html>
<head>
<title>Message Boards</title>
...
</head>
<body>
<div class="board-list">
<div class="board-item">
<h2>General</h2>
<p>General discussion</p>
<a href="/board?id=1">View Board</a>
</div>
...
</div>
</body>
</html>Status Codes:
200 OK- Success
GET /board
View a specific board with its threads.
Parameters:
id(required) - Board ID (integer)lang(optional) - Language code
Example:
GET /board?id=1&lang=en
Response:
<!DOCTYPE html>
<html>
<head>
<title>General - Board</title>
...
</head>
<body>
<h1>General</h1>
<p>General discussion</p>
<!-- Thread creation form -->
<form method="POST" action="/thread">
<input type="hidden" name="board_id" value="1">
<input type="text" name="subject" required>
<textarea name="content" required></textarea>
<button type="submit">Create Thread</button>
</form>
<!-- Thread list -->
<div class="thread-list">
<div class="thread-item">
<h3><a href="/thread?id=1">Welcome!</a></h3>
<p>By Admin - 2 hours ago</p>
</div>
...
</div>
</body>
</html>Status Codes:
200 OK- Success404 Not Found- Board not found
GET /thread
View a specific thread with all its posts.
Parameters:
id(required) - Thread ID (integer)lang(optional) - Language code
Example:
GET /thread?id=1&lang=en
Response:
<!DOCTYPE html>
<html>
<head>
<title>Welcome! - Thread</title>
...
</head>
<body>
<h1>Welcome!</h1>
<!-- Original post -->
<div class="post original-post">
<div class="post-author">Admin</div>
<div class="post-content">Welcome to the forum!</div>
<div class="post-time">2 hours ago</div>
</div>
<!-- Replies -->
<div class="post-list">
<div class="post">
<div class="post-author">User123</div>
<div class="post-content">Thanks! (^_^)</div>
<div class="post-time">1 hour ago</div>
</div>
...
</div>
<!-- Reply form -->
<form method="POST" action="/post">
<input type="hidden" name="thread_id" value="1">
<input type="text" name="author" required>
<textarea name="content" required></textarea>
<button type="submit">Reply</button>
</form>
</body>
</html>Status Codes:
200 OK- Success404 Not Found- Thread not found
POST /thread
Create a new thread in a board.
Content-Type: application/x-www-form-urlencoded
Parameters:
board_id(required) - Board ID (integer)subject(required) - Thread subject/titleauthor(required) - Author namecontent(required) - Thread content (first post)
Example Request:
POST /thread HTTP/1.1
Content-Type: application/x-www-form-urlencoded
board_id=1&subject=New+Thread&author=User123&content=This+is+my+threadResponse:
302 Found- Redirect to new thread- Location:
/thread?id={thread_id}
- Location:
Status Codes:
302 Found- Success (redirect)400 Bad Request- Missing required parameters404 Not Found- Board not found
POST /post
Create a new post (reply) in a thread.
Content-Type: application/x-www-form-urlencoded
Parameters:
thread_id(required) - Thread ID (integer)author(required) - Author namecontent(required) - Post contentreply_to(optional) - Post ID being replied to
Example Request:
POST /post HTTP/1.1
Content-Type: application/x-www-form-urlencoded
thread_id=1&author=User456&content=Great+post!&reply_to=5Response:
302 Found- Redirect to thread- Location:
/thread?id={thread_id}
- Location:
Status Codes:
302 Found- Success (redirect)400 Bad Request- Missing required parameters404 Not Found- Thread not found
All admin endpoints require authentication via session cookie.
GET /admin/login
Display the admin login form.
Parameters:
lang(optional) - Language code
Response:
<!DOCTYPE html>
<html>
<head>
<title>Admin Login</title>
...
</head>
<body>
<form method="POST" action="/admin/login">
<input type="text" name="username" required>
<input type="password" name="password" required>
<button type="submit">Login</button>
</form>
</body>
</html>Status Codes:
200 OK- Success
POST /admin/login
Authenticate admin user.
Content-Type: application/x-www-form-urlencoded
Parameters:
username(required) - Admin usernamepassword(required) - Admin password
Example Request:
POST /admin/login HTTP/1.1
Content-Type: application/x-www-form-urlencoded
username=admin&password=secret123Response (Success):
302 Found- Redirect to dashboard- Location:
/admin - Set-Cookie:
session={token}; Path=/; Max-Age=86400
- Location:
Response (Failure):
401 Unauthorized- Invalid credentials- HTML page with error message
Status Codes:
302 Found- Success (redirect)401 Unauthorized- Invalid credentials
GET /admin
Display the admin control panel.
Authentication: Required (session cookie)
Parameters:
lang(optional) - Language code
Response:
<!DOCTYPE html>
<html>
<head>
<title>Admin Dashboard</title>
...
</head>
<body>
<h1>Admin Dashboard</h1>
<!-- Statistics -->
<div class="stats">
<div class="stat-item">
<h3>5</h3>
<p>Boards</p>
</div>
<div class="stat-item">
<h3>42</h3>
<p>Threads</p>
</div>
<div class="stat-item">
<h3>157</h3>
<p>Posts</p>
</div>
</div>
<!-- Board management -->
<div class="board-management">
<h2>Boards</h2>
<form method="POST" action="/admin/board">
<input type="text" name="name" required>
<textarea name="description"></textarea>
<button type="submit">Create Board</button>
</form>
<div class="board-list">
<div class="board-item">
<h3>General</h3>
<form method="POST" action="/admin/board/delete">
<input type="hidden" name="board_id" value="1">
<button type="submit">Delete</button>
</form>
</div>
...
</div>
</div>
</body>
</html>Status Codes:
200 OK- Success401 Unauthorized- Not authenticated302 Found- Redirect to login if not authenticated
GET /admin/logout
Log out admin user.
Authentication: Required (session cookie)
Response:
302 Found- Redirect to home- Location:
/ - Set-Cookie:
session=; Path=/; Max-Age=0(clear cookie)
- Location:
Status Codes:
302 Found- Success (redirect)
POST /admin/board
Create a new board.
Authentication: Required (session cookie)
Content-Type: application/x-www-form-urlencoded
Parameters:
name(required) - Board name (unique)description(optional) - Board description
Example Request:
POST /admin/board HTTP/1.1
Cookie: session=abc123...
Content-Type: application/x-www-form-urlencoded
name=Technology&description=Tech+discussionsResponse:
302 Found- Redirect to admin dashboard- Location:
/admin
- Location:
Status Codes:
302 Found- Success (redirect)400 Bad Request- Missing name or duplicate name401 Unauthorized- Not authenticated
POST /admin/board/delete
Delete a board and all its threads/posts.
Authentication: Required (session cookie)
Content-Type: application/x-www-form-urlencoded
Parameters:
board_id(required) - Board ID (integer)
Example Request:
POST /admin/board/delete HTTP/1.1
Cookie: session=abc123...
Content-Type: application/x-www-form-urlencoded
board_id=3Response:
302 Found- Redirect to admin dashboard- Location:
/admin
- Location:
Status Codes:
302 Found- Success (redirect)400 Bad Request- Missing board_id401 Unauthorized- Not authenticated404 Not Found- Board not found
POST /upload
Upload a file to the server.
Content-Type: multipart/form-data
Parameters:
file(required) - File upload field
Example Request:
POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="image.jpg"
Content-Type: image/jpeg
[binary file data]
------WebKitFormBoundary--Response:
<!DOCTYPE html>
<html>
<body>
<h1>Upload Successful</h1>
<p>File saved: image.jpg</p>
</body>
</html>Status Codes:
200 OK- Success400 Bad Request- No file provided413 Payload Too Large- File too large (if implemented)
Response:
<!DOCTYPE html>
<html>
<head>
<title>404 - Not Found</title>
</head>
<body>
<h1>404 - Page Not Found</h1>
<p>The requested resource was not found.</p>
<a href="/">Back to Home</a>
</body>
</html>Response:
<!DOCTYPE html>
<html>
<head>
<title>401 - Unauthorized</title>
</head>
<body>
<h1>401 - Unauthorized</h1>
<p>You must be logged in to access this page.</p>
<a href="/admin/login">Login</a>
</body>
</html>Name: session
Format: Random 128-character alphanumeric string
Attributes:
Path=/- Available to all routesMax-Age=86400- 24 hour expiry (86400 seconds)HttpOnly- Not accessible via JavaScript (if implemented)Secure- Only sent over HTTPS (if HTTPS enabled)
Example:
Set-Cookie: session=abc123def456...; Path=/; Max-Age=86400
Sessions are validated on each admin request:
- Extract token from
sessioncookie - Query database:
SELECT user_id FROM sessions WHERE token = ? AND expires_at > now() - If found, user is authenticated
- If not found or expired, redirect to login
Currently not implemented. Future consideration for:
- Login attempts (prevent brute force)
- Post creation (prevent spam)
- File uploads (prevent abuse)
Currently not configured. All requests must be same-origin.
GET /api/boards
{
"boards": [
{
"id": 1,
"name": "General",
"description": "General discussion",
"thread_count": 42
}
]
}GET /api/threads?board_id=1
{
"threads": [
{
"id": 1,
"subject": "Welcome!",
"author": "Admin",
"post_count": 5,
"created_at": 1699000000
}
]
}GET /api/posts?thread_id=1
{
"posts": [
{
"id": 1,
"author": "Admin",
"content": "Welcome to the forum!",
"reply_to": null,
"created_at": 1699000000
}
]
}- README.md - Project overview
- DATABASE_SCHEMA.md - Database structure
- LOCALIZATION.md - Language support
- ARCHITECTURE.md - System design