Add dotenv configuration and user management routes

- Introduced dotenv for environment variable management.
- Created config module to handle configuration settings.
- Added user controller with functions to get and create users.
- Implemented user routes for API endpoints.
- Updated package.json and yarn.lock to include dotenv dependency.
This commit is contained in:
marco.chan committed 2026-09-03 15:47:26 +08:00
1 parent f0f60add78
commit ea661d2afe
7 files changed
+121 -16

No files matched your search

+3
View File
@@ -15,3 +15,6 @@ node_modules
#!.yarn/cache
.pnp.*
.env
.env.*
+9 -7
View File
@@ -3,19 +3,21 @@
"packageManager": "yarn@4.18.0",
"type": "module",
"scripts": {
"dev": "tsx --watch ./src/index.ts",
"start": "node ./dist/index.js",
"build": "tsc",
"clean": "rm -rf dist",
"compile": "yarn clean && yarn build",
"script": "tsx"
"dev": "tsx --watch ./src/index.ts",
"start": "node ./dist/index.js",
"build": "tsc",
"clean": "rm -rf dist",
"compile": "yarn clean && yarn build",
"script": "tsx"
},
"dependencies": {
"@jig-software/trest": "2.0.0-beta",
"@koa/cors": "^5.0.0",
"@koa/router": "^15.7.0",
"dotenv": "^17.4.2",
"koa": "^3.2.1",
"koa-bodyparser": "^4.4.1"
"koa-bodyparser": "^4.4.1",
"path": "^0.12.7"
},
"devDependencies": {
"@types/koa": "^3.0.3",
+13
View File
@@ -0,0 +1,13 @@
import dotenv from 'dotenv';
import path from 'path';
// 💡 1. 讓 dotenv 去讀取根目錄的 .env 檔案並注入到 process.env
dotenv.config();
// 💡 2. 集中導出一個帶有型別的物件
export const config = {
port: parseInt(process.env.PORT || '3000', 10),
//dbUrl: process.env.DB_URL || 'mongodb://localhost:27017/default',
//jwtSecret: process.env.JWT_SECRET || 'fallback_secret',
//isConfigured: !!process.env.DB_URL
};
+31
View File
@@ -0,0 +1,31 @@
import type { Context } from "koa";
// Simulated database array
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
export async function getAllUsers(ctx:Context) {
ctx.body = { success: true, data: users };
}
export async function createUser(ctx: Context) {
const body = ctx.request.body;
if (
typeof body !== "object" ||
body === null ||
!("name" in body) ||
typeof body.name !== "string" ||
body.name.trim() === ""
) {
ctx.throw(400, 'Name field is required');
}
const newUser = { id: users.length + 1, name: body.name };
users.push(newUser);
ctx.status = 201;
ctx.body = { success: true, data: newUser };
}
+14 -9
View File
@@ -1,19 +1,24 @@
import Koa from 'koa';
import cors from '@koa/cors';
import bodyParser from 'koa-bodyparser';
//import { errorHandler } from './middleware/error';
//import userRouter from './routes/userRoutes';
import { errorHandler } from './middleware/error.js';
import userRouter from './routes/userRoutes.js';
import { config } from './configs/index.js';
const app = new Koa();
const PORT = 3000;
const PORT = config.port || 3000;
//app.use(errorHandler);
app.use(cors());
app.use(bodyParser());
// --- Middlewares Stack (Order Matters!) ---
//app.use(userRouter.routes());
//app.use(userRouter.allowedMethods());
app.use(errorHandler); // 1. Error interceptor (Outer Onion layer)
app.use(cors()); // 2. Enable Cross-Origin requests
app.use(bodyParser()); // 3. Parse JSON incoming bodies
// --- Routes Registration ---
app.use(userRouter.routes());
app.use(userRouter.allowedMethods()); // Handles automatic 405 Method Not Allowed responses
app.listen(PORT, () => {
console.log(`🚀 TypeScript Koa server running at http://localhost:${PORT}`);
console.log(`🚀 Koa server running smoothly at http://localhost:${PORT}`);
});
+9
View File
@@ -0,0 +1,9 @@
import Router from '@koa/router';
import { getAllUsers, createUser } from '../controllers/userController.js';
const router = new Router({ prefix: '/api/users' });
router.get('/', getAllUsers);
router.post('/', createUser);
export default router;
+42
View File
@@ -645,6 +645,13 @@ __metadata:
languageName: node
linkType: hard
"dotenv@npm:^17.4.2":
version: 17.4.2
resolution: "dotenv@npm:17.4.2"
checksum: 10c0/164f8e77a646c8446867d5b588d26ea6005c8ea7c5eb41cf926f6113d23f2191355f6e0cfd95ea9bab98394a5b0a3f1e51a8399711b666fe55cc7b0bd745f942
languageName: node
linkType: hard
"dunder-proto@npm:^1.0.1":
version: 1.0.1
resolution: "dunder-proto@npm:1.0.1"
@@ -1000,6 +1007,13 @@ __metadata:
languageName: node
linkType: hard
"inherits@npm:2.0.3":
version: 2.0.3
resolution: "inherits@npm:2.0.3"
checksum: 10c0/6e56402373149ea076a434072671f9982f5fad030c7662be0332122fe6c0fa490acb3cc1010d90b6eff8d640b1167d77674add52dfd1bb85d545cf29e80e73e7
languageName: node
linkType: hard
"inherits@npm:2.0.4, inherits@npm:~2.0.4":
version: 2.0.4
resolution: "inherits@npm:2.0.4"
@@ -1286,6 +1300,16 @@ __metadata:
languageName: node
linkType: hard
"path@npm:^0.12.7":
version: 0.12.7
resolution: "path@npm:0.12.7"
dependencies:
process: "npm:^0.11.1"
util: "npm:^0.10.3"
checksum: 10c0/f795ce5438a988a590c7b6dfd450ec9baa1c391a8be4c2dea48baa6e0f5b199e56cd83b8c9ebf3991b81bea58236d2c32bdafe2c17a2e70c3a2e4c69891ade59
languageName: node
linkType: hard
"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1":
version: 2.3.2
resolution: "picomatch@npm:2.3.2"
@@ -1307,6 +1331,13 @@ __metadata:
languageName: node
linkType: hard
"process@npm:^0.11.1":
version: 0.11.10
resolution: "process@npm:0.11.10"
checksum: 10c0/40c3ce4b7e6d4b8c3355479df77aeed46f81b279818ccdc500124e6a5ab882c0cc81ff7ea16384873a95a74c4570b01b120f287abbdd4c877931460eca6084b3
languageName: node
linkType: hard
"pstree.remy@npm:^1.1.8":
version: 1.1.8
resolution: "pstree.remy@npm:1.1.8"
@@ -1450,9 +1481,11 @@ __metadata:
"@types/koa-bodyparser": "npm:^4"
"@types/koa__cors": "npm:^5"
"@types/node": "npm:^26.4.1"
dotenv: "npm:^17.4.2"
koa: "npm:^3.2.1"
koa-bodyparser: "npm:^4.4.1"
nodemon: "npm:^3.1.14"
path: "npm:^0.12.7"
tsx: "npm:^4.23.13"
typescript: "npm:^5.9.3"
languageName: unknown
@@ -1606,6 +1639,15 @@ __metadata:
languageName: node
linkType: hard
"util@npm:^0.10.3":
version: 0.10.4
resolution: "util@npm:0.10.4"
dependencies:
inherits: "npm:2.0.3"
checksum: 10c0/d29f6893e406b63b088ce9924da03201df89b31490d4d011f1c07a386ea4b3dbe907464c274023c237da470258e1805d806c7e4009a5974cd6b1d474b675852a
languageName: node
linkType: hard
"vary@npm:^1.1.2":
version: 1.1.2
resolution: "vary@npm:1.1.2"