feat: init drizzle implementation for backend (express) and frontend (vite-react)
This commit is contained in:
parent
fc3a21263a
commit
aca6a4da98
17 changed files with 1608 additions and 35 deletions
2
apps/express-template/.env.example
Normal file
2
apps/express-template/.env.example
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# Drizzle ORM configuration for Supabase PostgreSQL database
|
||||
DATABASE_URL=
|
||||
78
apps/express-template/src/routes/users.ts
Normal file
78
apps/express-template/src/routes/users.ts
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
import { Router } from "express";
|
||||
import { getUsers, createUser } from "@repo/db/index.ts";
|
||||
import { randomUUID } from "crypto";
|
||||
|
||||
const router = Router();
|
||||
|
||||
// GET /api/users - Get all users
|
||||
router.get("/", async (req, res) => {
|
||||
try {
|
||||
const users = await getUsers();
|
||||
res.json(users);
|
||||
} catch (error: any) {
|
||||
console.error("Error fetching users:", error);
|
||||
res.status(500).json({
|
||||
error: "Failed to fetch users",
|
||||
message: error.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// POST /api/users - Create new user
|
||||
router.post("/", async (req, res) => {
|
||||
try {
|
||||
const { name, email, password, role, isActive } = req.body;
|
||||
|
||||
// Validation
|
||||
if (!name || !email || !password) {
|
||||
return res.status(400).json({
|
||||
error: "Missing required fields: name, email, and password are required",
|
||||
});
|
||||
}
|
||||
|
||||
// Email format validation
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(email)) {
|
||||
return res.status(400).json({ error: "Invalid email format" });
|
||||
}
|
||||
|
||||
// Password length validation
|
||||
if (password.length < 6) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: "Password must be at least 6 characters long" });
|
||||
}
|
||||
|
||||
// Role validation (based on schema enum)
|
||||
const validRoles = ["admin", "user"];
|
||||
if (role && !validRoles.includes(role)) {
|
||||
return res.status(400).json({
|
||||
error: "Invalid role. Must be 'admin' or 'user'",
|
||||
});
|
||||
}
|
||||
const userData = {
|
||||
id: randomUUID(),
|
||||
name: name.trim(),
|
||||
email: email.toLowerCase().trim(),
|
||||
role: role || "user", // Default role
|
||||
};
|
||||
|
||||
const newUser = await createUser(userData);
|
||||
|
||||
res.status(201).json(newUser);
|
||||
} catch (error: any) {
|
||||
console.error("Error creating user:", error);
|
||||
|
||||
// Handle unique constraint violation (duplicate email)
|
||||
if (error.message?.includes("duplicate") || error.code === "23505") {
|
||||
return res.status(409).json({ error: "Email already exists" });
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
error: "Failed to create user",
|
||||
message: error.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
|
@ -2,21 +2,25 @@ import { json, urlencoded } from "body-parser";
|
|||
import express, { type Express } from "express";
|
||||
import morgan from "morgan";
|
||||
import cors from "cors";
|
||||
import productRoutes from "./routes/products";
|
||||
import userRoutes from "./routes/users";
|
||||
|
||||
export const createServer = (): Express => {
|
||||
const app = express();
|
||||
app
|
||||
.disable("x-powered-by")
|
||||
.use(morgan("dev"))
|
||||
.use(urlencoded({ extended: true }))
|
||||
.use(json())
|
||||
.use(cors())
|
||||
.get("/message/:name", (req, res) => {
|
||||
return res.json({ message: `hello ${req.params.name}` });
|
||||
})
|
||||
.get("/status", (_, res) => {
|
||||
return res.json({ ok: true });
|
||||
});
|
||||
const app = express();
|
||||
app.disable("x-powered-by")
|
||||
.use(morgan("dev"))
|
||||
.use(urlencoded({ extended: true }))
|
||||
.use(json())
|
||||
.use(cors())
|
||||
|
||||
return app;
|
||||
.get("/message/:name", (req, res) => {
|
||||
return res.json({ message: `hello ${req.params.name}` });
|
||||
})
|
||||
.get("/status", (_, res) => {
|
||||
return res.json({ ok: true });
|
||||
})
|
||||
|
||||
.use("/api/products", productRoutes)
|
||||
.use("/api/users", userRoutes);
|
||||
return app;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"extends": "@repo/typescript-config/base.json",
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2015"],
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"exclude": ["node_modules"],
|
||||
"include": ["."]
|
||||
"extends": "@repo/typescript-config/base.json",
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2015"],
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"exclude": ["node_modules"],
|
||||
"include": ["."]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue