forked from syntaxbullet/aurorabot
refactor: rename web/ to api/ to better reflect its purpose
The web/ folder contains the REST API, WebSocket server, and OAuth routes — not a web frontend. Renaming to api/ clarifies this distinction since the actual web frontend lives in panel/. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
155
api/src/routes/classes.routes.ts
Normal file
155
api/src/routes/classes.routes.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* @fileoverview Class management endpoints for Aurora API.
|
||||
* Provides CRUD operations for player classes/guilds.
|
||||
*/
|
||||
|
||||
import type { RouteContext, RouteModule } from "./types";
|
||||
import {
|
||||
jsonResponse,
|
||||
errorResponse,
|
||||
parseBody,
|
||||
parseStringIdFromPath,
|
||||
withErrorHandling
|
||||
} from "./utils";
|
||||
import { CreateClassSchema, UpdateClassSchema } from "./schemas";
|
||||
|
||||
/**
|
||||
* Classes routes handler.
|
||||
*
|
||||
* Endpoints:
|
||||
* - GET /api/classes - List all classes
|
||||
* - POST /api/classes - Create a new class
|
||||
* - PUT /api/classes/:id - Update a class
|
||||
* - DELETE /api/classes/:id - Delete a class
|
||||
*/
|
||||
async function handler(ctx: RouteContext): Promise<Response | null> {
|
||||
const { pathname, method, req } = ctx;
|
||||
|
||||
// Only handle requests to /api/classes*
|
||||
if (!pathname.startsWith("/api/classes")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { classService } = await import("@shared/modules/class/class.service");
|
||||
|
||||
/**
|
||||
* @route GET /api/classes
|
||||
* @description Returns all classes/guilds in the system.
|
||||
*
|
||||
* @response 200 - `{ classes: Class[] }`
|
||||
* @response 500 - Error fetching classes
|
||||
*
|
||||
* @example
|
||||
* // Response
|
||||
* {
|
||||
* "classes": [
|
||||
* { "id": "1", "name": "Warrior", "balance": "5000", "roleId": "123456789" }
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
if (pathname === "/api/classes" && method === "GET") {
|
||||
return withErrorHandling(async () => {
|
||||
const classes = await classService.getAllClasses();
|
||||
return jsonResponse({ classes });
|
||||
}, "fetch classes");
|
||||
}
|
||||
|
||||
/**
|
||||
* @route POST /api/classes
|
||||
* @description Creates a new class/guild.
|
||||
*
|
||||
* @body {
|
||||
* id: string | number (required) - Unique class identifier,
|
||||
* name: string (required) - Class display name,
|
||||
* balance?: string | number - Initial class balance (default: 0),
|
||||
* roleId?: string - Associated Discord role ID
|
||||
* }
|
||||
* @response 201 - `{ success: true, class: Class }`
|
||||
* @response 400 - Missing required fields
|
||||
* @response 500 - Error creating class
|
||||
*
|
||||
* @example
|
||||
* // Request
|
||||
* POST /api/classes
|
||||
* { "id": "2", "name": "Mage", "balance": "0", "roleId": "987654321" }
|
||||
*/
|
||||
if (pathname === "/api/classes" && method === "POST") {
|
||||
return withErrorHandling(async () => {
|
||||
const data = await req.json() as Record<string, any>;
|
||||
|
||||
if (!data.id || !data.name || typeof data.name !== 'string') {
|
||||
return errorResponse("Missing required fields: id and name are required", 400);
|
||||
}
|
||||
|
||||
const newClass = await classService.createClass({
|
||||
id: BigInt(data.id),
|
||||
name: data.name,
|
||||
balance: data.balance ? BigInt(data.balance) : 0n,
|
||||
roleId: data.roleId || null,
|
||||
});
|
||||
|
||||
return jsonResponse({ success: true, class: newClass }, 201);
|
||||
}, "create class");
|
||||
}
|
||||
|
||||
/**
|
||||
* @route PUT /api/classes/:id
|
||||
* @description Updates an existing class.
|
||||
*
|
||||
* @param id - Class ID
|
||||
* @body {
|
||||
* name?: string - Updated class name,
|
||||
* balance?: string | number - Updated balance,
|
||||
* roleId?: string - Updated Discord role ID
|
||||
* }
|
||||
* @response 200 - `{ success: true, class: Class }`
|
||||
* @response 404 - Class not found
|
||||
* @response 500 - Error updating class
|
||||
*/
|
||||
if (pathname.match(/^\/api\/classes\/\d+$/) && method === "PUT") {
|
||||
const id = parseStringIdFromPath(pathname);
|
||||
if (!id) return null;
|
||||
|
||||
return withErrorHandling(async () => {
|
||||
const data = await req.json() as Record<string, any>;
|
||||
|
||||
const updateData: any = {};
|
||||
if (data.name !== undefined) updateData.name = data.name;
|
||||
if (data.balance !== undefined) updateData.balance = BigInt(data.balance);
|
||||
if (data.roleId !== undefined) updateData.roleId = data.roleId;
|
||||
|
||||
const updatedClass = await classService.updateClass(BigInt(id), updateData);
|
||||
|
||||
if (!updatedClass) {
|
||||
return errorResponse("Class not found", 404);
|
||||
}
|
||||
|
||||
return jsonResponse({ success: true, class: updatedClass });
|
||||
}, "update class");
|
||||
}
|
||||
|
||||
/**
|
||||
* @route DELETE /api/classes/:id
|
||||
* @description Deletes a class. Users assigned to this class will need to be reassigned.
|
||||
*
|
||||
* @param id - Class ID
|
||||
* @response 204 - Class deleted (no content)
|
||||
* @response 500 - Error deleting class
|
||||
*/
|
||||
if (pathname.match(/^\/api\/classes\/\d+$/) && method === "DELETE") {
|
||||
const id = parseStringIdFromPath(pathname);
|
||||
if (!id) return null;
|
||||
|
||||
return withErrorHandling(async () => {
|
||||
await classService.deleteClass(BigInt(id));
|
||||
return new Response(null, { status: 204 });
|
||||
}, "delete class");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export const classesRoutes: RouteModule = {
|
||||
name: "classes",
|
||||
handler
|
||||
};
|
||||
Reference in New Issue
Block a user