create-aziz-app 2.0.13 → 2.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/api/createUser.js +69 -0
- package/template/api/getUser.js +60 -0
- package/template/api/getUserWithDB.js +65 -0
- package/template/api/loginUser.js +61 -0
- package/template/docs/NEXTJS-APP-ROUTER.md +536 -0
- package/template/lib/db.js +67 -0
- package/template/models/User.js +102 -0
- package/template/modules/next-response.js +58 -0
- package/template/scripts/dev-server.js +106 -45
package/package.json
CHANGED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// API Route: /api/createUser
|
|
2
|
+
// Next.js App Router style
|
|
3
|
+
|
|
4
|
+
const { NextResponse } = require('../modules/next-response');
|
|
5
|
+
|
|
6
|
+
// Mock database
|
|
7
|
+
let users = [
|
|
8
|
+
{ _id: '1', name: 'Aziz Ahmed', email: 'aziz@example.com', role: 'admin', phone: '123-456-7890' }
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
// POST handler
|
|
12
|
+
async function POST(request) {
|
|
13
|
+
try {
|
|
14
|
+
// Parse request body
|
|
15
|
+
const body = await request.json();
|
|
16
|
+
const { name, email, password, role, phone } = body;
|
|
17
|
+
|
|
18
|
+
// Validation
|
|
19
|
+
if (!name || !email || !password) {
|
|
20
|
+
return NextResponse.json(
|
|
21
|
+
{
|
|
22
|
+
error: 'Validation failed',
|
|
23
|
+
message: 'Name, email, and password are required'
|
|
24
|
+
},
|
|
25
|
+
{ status: 400 }
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Check if email already exists
|
|
30
|
+
if (users.find(u => u.email === email)) {
|
|
31
|
+
return NextResponse.json(
|
|
32
|
+
{ error: 'User with this email already exists' },
|
|
33
|
+
{ status: 409 }
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Create new user
|
|
38
|
+
const newUser = {
|
|
39
|
+
_id: String(users.length + 1),
|
|
40
|
+
name,
|
|
41
|
+
email,
|
|
42
|
+
password, // In production, hash this with bcrypt!
|
|
43
|
+
role: role || 'user',
|
|
44
|
+
phone: phone || '',
|
|
45
|
+
createdAt: new Date().toISOString()
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
users.push(newUser);
|
|
49
|
+
|
|
50
|
+
// Return user data (without password)
|
|
51
|
+
const { password: _, ...userData } = newUser;
|
|
52
|
+
|
|
53
|
+
return NextResponse.json(
|
|
54
|
+
{
|
|
55
|
+
message: 'User created successfully',
|
|
56
|
+
user: userData
|
|
57
|
+
},
|
|
58
|
+
{ status: 201 }
|
|
59
|
+
);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error('Create user error:', error);
|
|
62
|
+
return NextResponse.json(
|
|
63
|
+
{ error: 'Failed to create user' },
|
|
64
|
+
{ status: 500 }
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = { POST };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// API Route: /api/getUser
|
|
2
|
+
// Next.js App Router style with NextResponse
|
|
3
|
+
|
|
4
|
+
const { NextResponse } = require('../modules/next-response');
|
|
5
|
+
|
|
6
|
+
// Mock database
|
|
7
|
+
const users = [
|
|
8
|
+
{ _id: '1', name: 'Aziz Ahmed', email: 'aziz@example.com', role: 'admin', phone: '123-456-7890' },
|
|
9
|
+
{ _id: '2', name: 'John Doe', email: 'john@example.com', role: 'user', phone: '098-765-4321' },
|
|
10
|
+
{ _id: '3', name: 'Jane Smith', email: 'jane@example.com', role: 'user', phone: '555-123-4567' }
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
// GET handler - Next.js App Router style
|
|
14
|
+
async function GET(request) {
|
|
15
|
+
try {
|
|
16
|
+
// Parse URL and get search params
|
|
17
|
+
const { searchParams } = new URL(request.url);
|
|
18
|
+
const email = searchParams.get('email');
|
|
19
|
+
const id = searchParams.get('id');
|
|
20
|
+
|
|
21
|
+
// Find by email
|
|
22
|
+
if (email) {
|
|
23
|
+
const user = users.find(u => u.email === email);
|
|
24
|
+
if (!user) {
|
|
25
|
+
return NextResponse.json(
|
|
26
|
+
{ error: 'User not found' },
|
|
27
|
+
{ status: 404 }
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
return NextResponse.json(user);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Find by ID
|
|
34
|
+
if (id) {
|
|
35
|
+
const user = users.find(u => u._id === id);
|
|
36
|
+
if (!user) {
|
|
37
|
+
return NextResponse.json(
|
|
38
|
+
{ error: 'User not found' },
|
|
39
|
+
{ status: 404 }
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
return NextResponse.json(user);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// No params provided
|
|
46
|
+
return NextResponse.json(
|
|
47
|
+
{ error: 'Email or ID required' },
|
|
48
|
+
{ status: 400 }
|
|
49
|
+
);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error('Error fetching user:', error);
|
|
52
|
+
return NextResponse.json(
|
|
53
|
+
{ error: 'Failed to fetch user' },
|
|
54
|
+
{ status: 500 }
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Export the handler
|
|
60
|
+
module.exports = { GET };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// API Route: /api/getUserWithDB
|
|
2
|
+
// Complete Next.js App Router style with DB and Model
|
|
3
|
+
|
|
4
|
+
const { NextResponse } = require('../modules/next-response');
|
|
5
|
+
const connectDB = require('../lib/db');
|
|
6
|
+
const User = require('../models/User');
|
|
7
|
+
|
|
8
|
+
// GET handler - Exactly like Next.js!
|
|
9
|
+
async function GET(request) {
|
|
10
|
+
try {
|
|
11
|
+
// Connect to database
|
|
12
|
+
await connectDB();
|
|
13
|
+
|
|
14
|
+
// Parse URL and get search params
|
|
15
|
+
const { searchParams } = new URL(request.url);
|
|
16
|
+
const email = searchParams.get('email');
|
|
17
|
+
const id = searchParams.get('id');
|
|
18
|
+
|
|
19
|
+
// Find by email
|
|
20
|
+
if (email) {
|
|
21
|
+
const user = await User.findOne({ email });
|
|
22
|
+
|
|
23
|
+
if (!user) {
|
|
24
|
+
return NextResponse.json(
|
|
25
|
+
{ error: 'User not found' },
|
|
26
|
+
{ status: 404 }
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Return user without sensitive fields
|
|
31
|
+
const { password, ...userData } = user;
|
|
32
|
+
return NextResponse.json(userData);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Find by ID
|
|
36
|
+
if (id) {
|
|
37
|
+
const user = await User.findById(id);
|
|
38
|
+
|
|
39
|
+
if (!user) {
|
|
40
|
+
return NextResponse.json(
|
|
41
|
+
{ error: 'User not found' },
|
|
42
|
+
{ status: 404 }
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Return user without sensitive fields
|
|
47
|
+
const { password, ...userData } = user;
|
|
48
|
+
return NextResponse.json(userData);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// No params - return error
|
|
52
|
+
return NextResponse.json(
|
|
53
|
+
{ error: 'Email or ID required' },
|
|
54
|
+
{ status: 400 }
|
|
55
|
+
);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error('Error fetching user:', error);
|
|
58
|
+
return NextResponse.json(
|
|
59
|
+
{ error: 'Failed to fetch user' },
|
|
60
|
+
{ status: 500 }
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = { GET };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// API Route: /api/loginUser
|
|
2
|
+
// Next.js App Router style
|
|
3
|
+
|
|
4
|
+
const { NextResponse } = require('../modules/next-response');
|
|
5
|
+
|
|
6
|
+
// Mock database
|
|
7
|
+
const users = [
|
|
8
|
+
{ _id: '1', name: 'Aziz Ahmed', email: 'aziz@example.com', password: 'admin123', role: 'admin' },
|
|
9
|
+
{ _id: '2', name: 'John Doe', email: 'john@example.com', password: 'user123', role: 'user' }
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
// POST handler
|
|
13
|
+
async function POST(request) {
|
|
14
|
+
try {
|
|
15
|
+
// Parse request body
|
|
16
|
+
const body = await request.json();
|
|
17
|
+
const { email, password } = body;
|
|
18
|
+
|
|
19
|
+
// Validation
|
|
20
|
+
if (!email || !password) {
|
|
21
|
+
return NextResponse.json(
|
|
22
|
+
{ error: 'Email and password are required' },
|
|
23
|
+
{ status: 400 }
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Find user
|
|
28
|
+
const user = users.find(u => u.email === email);
|
|
29
|
+
|
|
30
|
+
if (!user) {
|
|
31
|
+
return NextResponse.json(
|
|
32
|
+
{ error: 'Invalid credentials' },
|
|
33
|
+
{ status: 401 }
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Check password (in production, use bcrypt!)
|
|
38
|
+
if (user.password !== password) {
|
|
39
|
+
return NextResponse.json(
|
|
40
|
+
{ error: 'Invalid credentials' },
|
|
41
|
+
{ status: 401 }
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Return user data (without password)
|
|
46
|
+
const { password: _, ...userData } = user;
|
|
47
|
+
|
|
48
|
+
return NextResponse.json({
|
|
49
|
+
...userData,
|
|
50
|
+
message: 'Login successful'
|
|
51
|
+
});
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error('Login error:', error);
|
|
54
|
+
return NextResponse.json(
|
|
55
|
+
{ error: 'Failed to login' },
|
|
56
|
+
{ status: 500 }
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = { POST };
|
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
# Next.js App Router Style API Routes
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Write API routes **exactly like Next.js App Router** with `NextResponse` and named HTTP method exports!
|
|
6
|
+
|
|
7
|
+
## Quick Example
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
// api/getUser.js
|
|
11
|
+
const { NextResponse } = require('../modules/next-response');
|
|
12
|
+
|
|
13
|
+
export async function GET(request) {
|
|
14
|
+
const { searchParams } = new URL(request.url);
|
|
15
|
+
const email = searchParams.get('email');
|
|
16
|
+
|
|
17
|
+
if (!email) {
|
|
18
|
+
return NextResponse.json(
|
|
19
|
+
{ error: 'Email required' },
|
|
20
|
+
{ status: 400 }
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const user = await findUser(email);
|
|
25
|
+
return NextResponse.json(user);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = { GET };
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## NextResponse API
|
|
32
|
+
|
|
33
|
+
### NextResponse.json()
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
// Success response
|
|
37
|
+
return NextResponse.json({ message: 'Success' });
|
|
38
|
+
|
|
39
|
+
// With status code
|
|
40
|
+
return NextResponse.json(
|
|
41
|
+
{ error: 'Not found' },
|
|
42
|
+
{ status: 404 }
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// With custom headers
|
|
46
|
+
return NextResponse.json(
|
|
47
|
+
{ data: 'value' },
|
|
48
|
+
{
|
|
49
|
+
status: 200,
|
|
50
|
+
headers: {
|
|
51
|
+
'X-Custom-Header': 'value'
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### NextResponse.text()
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
return NextResponse.text('Hello World');
|
|
61
|
+
|
|
62
|
+
return NextResponse.text(
|
|
63
|
+
'Error message',
|
|
64
|
+
{ status: 500 }
|
|
65
|
+
);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### NextResponse.redirect()
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
return NextResponse.redirect('/login');
|
|
72
|
+
|
|
73
|
+
return NextResponse.redirect(
|
|
74
|
+
'/dashboard',
|
|
75
|
+
{ status: 307 }
|
|
76
|
+
);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### NextResponse.error()
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
return NextResponse.error();
|
|
83
|
+
// Returns 500 with generic error message
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## HTTP Method Exports
|
|
87
|
+
|
|
88
|
+
### Single Method
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
// api/getUser.js
|
|
92
|
+
const { NextResponse } = require('../modules/next-response');
|
|
93
|
+
|
|
94
|
+
async function GET(request) {
|
|
95
|
+
return NextResponse.json({ message: 'GET request' });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = { GET };
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Multiple Methods
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
// api/users.js
|
|
105
|
+
const { NextResponse } = require('../modules/next-response');
|
|
106
|
+
|
|
107
|
+
async function GET(request) {
|
|
108
|
+
const users = await getAllUsers();
|
|
109
|
+
return NextResponse.json(users);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function POST(request) {
|
|
113
|
+
const body = await request.json();
|
|
114
|
+
const user = await createUser(body);
|
|
115
|
+
return NextResponse.json(user, { status: 201 });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function PUT(request) {
|
|
119
|
+
const body = await request.json();
|
|
120
|
+
const user = await updateUser(body);
|
|
121
|
+
return NextResponse.json(user);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function DELETE(request) {
|
|
125
|
+
const { searchParams } = new URL(request.url);
|
|
126
|
+
const id = searchParams.get('id');
|
|
127
|
+
await deleteUser(id);
|
|
128
|
+
return NextResponse.json({ message: 'Deleted' });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
module.exports = { GET, POST, PUT, DELETE };
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Request Object
|
|
135
|
+
|
|
136
|
+
### URL and Search Params
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
async function GET(request) {
|
|
140
|
+
// Parse URL
|
|
141
|
+
const { searchParams } = new URL(request.url);
|
|
142
|
+
|
|
143
|
+
// Get query parameters
|
|
144
|
+
const email = searchParams.get('email');
|
|
145
|
+
const id = searchParams.get('id');
|
|
146
|
+
const page = searchParams.get('page') || '1';
|
|
147
|
+
|
|
148
|
+
return NextResponse.json({ email, id, page });
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Request Body
|
|
153
|
+
|
|
154
|
+
```javascript
|
|
155
|
+
async function POST(request) {
|
|
156
|
+
// Parse JSON body
|
|
157
|
+
const body = await request.json();
|
|
158
|
+
const { name, email, password } = body;
|
|
159
|
+
|
|
160
|
+
return NextResponse.json({ name, email });
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Headers
|
|
165
|
+
|
|
166
|
+
```javascript
|
|
167
|
+
async function GET(request) {
|
|
168
|
+
// Access headers
|
|
169
|
+
const auth = request.headers.authorization;
|
|
170
|
+
const contentType = request.headers['content-type'];
|
|
171
|
+
|
|
172
|
+
return NextResponse.json({ auth, contentType });
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Method
|
|
177
|
+
|
|
178
|
+
```javascript
|
|
179
|
+
async function GET(request) {
|
|
180
|
+
console.log(request.method); // 'GET'
|
|
181
|
+
return NextResponse.json({ method: request.method });
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Complete Examples
|
|
186
|
+
|
|
187
|
+
### Example 1: User Login
|
|
188
|
+
|
|
189
|
+
```javascript
|
|
190
|
+
// api/loginUser.js
|
|
191
|
+
const { NextResponse } = require('../modules/next-response');
|
|
192
|
+
const connectDB = require('../lib/db');
|
|
193
|
+
const User = require('../models/User');
|
|
194
|
+
|
|
195
|
+
async function POST(request) {
|
|
196
|
+
try {
|
|
197
|
+
await connectDB();
|
|
198
|
+
|
|
199
|
+
const { email, password } = await request.json();
|
|
200
|
+
|
|
201
|
+
// Validation
|
|
202
|
+
if (!email || !password) {
|
|
203
|
+
return NextResponse.json(
|
|
204
|
+
{ error: 'Email and password required' },
|
|
205
|
+
{ status: 400 }
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Find user
|
|
210
|
+
const user = await User.findOne({ email });
|
|
211
|
+
if (!user) {
|
|
212
|
+
return NextResponse.json(
|
|
213
|
+
{ error: 'Invalid credentials' },
|
|
214
|
+
{ status: 401 }
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Check password (use bcrypt in production!)
|
|
219
|
+
if (user.password !== password) {
|
|
220
|
+
return NextResponse.json(
|
|
221
|
+
{ error: 'Invalid credentials' },
|
|
222
|
+
{ status: 401 }
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Return user data
|
|
227
|
+
const { password: _, ...userData } = user;
|
|
228
|
+
return NextResponse.json(userData);
|
|
229
|
+
|
|
230
|
+
} catch (error) {
|
|
231
|
+
console.error('Login error:', error);
|
|
232
|
+
return NextResponse.json(
|
|
233
|
+
{ error: 'Failed to login' },
|
|
234
|
+
{ status: 500 }
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
module.exports = { POST };
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Example 2: Create User
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
// api/createUser.js
|
|
246
|
+
const { NextResponse } = require('../modules/next-response');
|
|
247
|
+
const connectDB = require('../lib/db');
|
|
248
|
+
const User = require('../models/User');
|
|
249
|
+
|
|
250
|
+
async function POST(request) {
|
|
251
|
+
try {
|
|
252
|
+
await connectDB();
|
|
253
|
+
|
|
254
|
+
const body = await request.json();
|
|
255
|
+
const { name, email, password, role, phone } = body;
|
|
256
|
+
|
|
257
|
+
// Validation
|
|
258
|
+
if (!name || !email || !password) {
|
|
259
|
+
return NextResponse.json(
|
|
260
|
+
{ error: 'Name, email, and password required' },
|
|
261
|
+
{ status: 400 }
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Check if exists
|
|
266
|
+
const existing = await User.findOne({ email });
|
|
267
|
+
if (existing) {
|
|
268
|
+
return NextResponse.json(
|
|
269
|
+
{ error: 'User already exists' },
|
|
270
|
+
{ status: 409 }
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Create user
|
|
275
|
+
const user = await User.create({
|
|
276
|
+
name,
|
|
277
|
+
email,
|
|
278
|
+
password, // Hash with bcrypt in production!
|
|
279
|
+
role: role || 'user',
|
|
280
|
+
phone
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// Return without password
|
|
284
|
+
const { password: _, ...userData } = user;
|
|
285
|
+
return NextResponse.json(
|
|
286
|
+
{ message: 'User created', user: userData },
|
|
287
|
+
{ status: 201 }
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
} catch (error) {
|
|
291
|
+
console.error('Create user error:', error);
|
|
292
|
+
return NextResponse.json(
|
|
293
|
+
{ error: 'Failed to create user' },
|
|
294
|
+
{ status: 500 }
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
module.exports = { POST };
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Example 3: Get User
|
|
303
|
+
|
|
304
|
+
```javascript
|
|
305
|
+
// api/getUser.js
|
|
306
|
+
const { NextResponse } = require('../modules/next-response');
|
|
307
|
+
const connectDB = require('../lib/db');
|
|
308
|
+
const User = require('../models/User');
|
|
309
|
+
|
|
310
|
+
async function GET(request) {
|
|
311
|
+
try {
|
|
312
|
+
await connectDB();
|
|
313
|
+
|
|
314
|
+
const { searchParams } = new URL(request.url);
|
|
315
|
+
const email = searchParams.get('email');
|
|
316
|
+
const id = searchParams.get('id');
|
|
317
|
+
|
|
318
|
+
if (email) {
|
|
319
|
+
const user = await User.findOne({ email });
|
|
320
|
+
if (!user) {
|
|
321
|
+
return NextResponse.json(
|
|
322
|
+
{ error: 'User not found' },
|
|
323
|
+
{ status: 404 }
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
return NextResponse.json(user);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (id) {
|
|
330
|
+
const user = await User.findById(id);
|
|
331
|
+
if (!user) {
|
|
332
|
+
return NextResponse.json(
|
|
333
|
+
{ error: 'User not found' },
|
|
334
|
+
{ status: 404 }
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
return NextResponse.json(user);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
return NextResponse.json(
|
|
341
|
+
{ error: 'Email or ID required' },
|
|
342
|
+
{ status: 400 }
|
|
343
|
+
);
|
|
344
|
+
|
|
345
|
+
} catch (error) {
|
|
346
|
+
console.error('Error:', error);
|
|
347
|
+
return NextResponse.json(
|
|
348
|
+
{ error: 'Failed to fetch user' },
|
|
349
|
+
{ status: 500 }
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
module.exports = { GET };
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Client-Side Usage
|
|
358
|
+
|
|
359
|
+
### Basic Fetch
|
|
360
|
+
|
|
361
|
+
```javascript
|
|
362
|
+
async function LoginUser(email, password) {
|
|
363
|
+
try {
|
|
364
|
+
const response = await fetch('/api/loginUser', {
|
|
365
|
+
method: 'POST',
|
|
366
|
+
headers: { 'Content-Type': 'application/json' },
|
|
367
|
+
body: JSON.stringify({ email, password })
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
const result = await response.json();
|
|
371
|
+
|
|
372
|
+
if (!response.ok) {
|
|
373
|
+
throw new Error(result.error);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return result;
|
|
377
|
+
} catch (error) {
|
|
378
|
+
console.error('Login failed:', error);
|
|
379
|
+
throw error;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### With React Hooks
|
|
385
|
+
|
|
386
|
+
```javascript
|
|
387
|
+
function LoginForm() {
|
|
388
|
+
const [email, setEmail] = useState('');
|
|
389
|
+
const [password, setPassword] = useState('');
|
|
390
|
+
const [error, setError] = useState('');
|
|
391
|
+
const [loading, setLoading] = useState(false);
|
|
392
|
+
|
|
393
|
+
const handleLogin = async (e) => {
|
|
394
|
+
e.preventDefault();
|
|
395
|
+
setLoading(true);
|
|
396
|
+
setError('');
|
|
397
|
+
|
|
398
|
+
try {
|
|
399
|
+
const response = await fetch('/api/loginUser', {
|
|
400
|
+
method: 'POST',
|
|
401
|
+
headers: { 'Content-Type': 'application/json' },
|
|
402
|
+
body: JSON.stringify({ email, password })
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
const result = await response.json();
|
|
406
|
+
|
|
407
|
+
if (!response.ok) {
|
|
408
|
+
setError(result.error);
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Success!
|
|
413
|
+
localStorage.setItem('user', JSON.stringify(result));
|
|
414
|
+
window.location.href = '/dashboard';
|
|
415
|
+
|
|
416
|
+
} catch (err) {
|
|
417
|
+
setError('Failed to login');
|
|
418
|
+
} finally {
|
|
419
|
+
setLoading(false);
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
return (
|
|
424
|
+
<form onSubmit={handleLogin}>
|
|
425
|
+
<input
|
|
426
|
+
type="email"
|
|
427
|
+
value={email}
|
|
428
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
429
|
+
placeholder="Email"
|
|
430
|
+
/>
|
|
431
|
+
<input
|
|
432
|
+
type="password"
|
|
433
|
+
value={password}
|
|
434
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
435
|
+
placeholder="Password"
|
|
436
|
+
/>
|
|
437
|
+
{error && <p style={{ color: 'red' }}>{error}</p>}
|
|
438
|
+
<button type="submit" disabled={loading}>
|
|
439
|
+
{loading ? 'Loading...' : 'Login'}
|
|
440
|
+
</button>
|
|
441
|
+
</form>
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
## Database Integration
|
|
447
|
+
|
|
448
|
+
### Setup (MongoDB Example)
|
|
449
|
+
|
|
450
|
+
```bash
|
|
451
|
+
npm install mongoose
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
```javascript
|
|
455
|
+
// lib/db.js
|
|
456
|
+
const mongoose = require('mongoose');
|
|
457
|
+
|
|
458
|
+
async function connectDB() {
|
|
459
|
+
if (mongoose.connections[0].readyState) {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
await mongoose.connect(process.env.MONGODB_URI);
|
|
464
|
+
console.log('✅ MongoDB connected');
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
module.exports = connectDB;
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### Model (Mongoose Example)
|
|
471
|
+
|
|
472
|
+
```javascript
|
|
473
|
+
// models/User.js
|
|
474
|
+
const mongoose = require('mongoose');
|
|
475
|
+
|
|
476
|
+
const userSchema = new mongoose.Schema({
|
|
477
|
+
name: { type: String, required: true },
|
|
478
|
+
email: { type: String, required: true, unique: true },
|
|
479
|
+
password: { type: String, required: true },
|
|
480
|
+
role: { type: String, enum: ['user', 'admin'], default: 'user' },
|
|
481
|
+
phone: String
|
|
482
|
+
}, { timestamps: true });
|
|
483
|
+
|
|
484
|
+
module.exports = mongoose.models.User || mongoose.model('User', userSchema);
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
## Environment Variables
|
|
488
|
+
|
|
489
|
+
```bash
|
|
490
|
+
# .env.local
|
|
491
|
+
MONGODB_URI=mongodb://localhost:27017/myapp
|
|
492
|
+
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
|
|
493
|
+
API_KEY=your_secret_key
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
```javascript
|
|
497
|
+
// Access in API routes
|
|
498
|
+
const dbUrl = process.env.MONGODB_URI;
|
|
499
|
+
const apiKey = process.env.API_KEY;
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
## Migration from Old Style
|
|
503
|
+
|
|
504
|
+
### Old Style
|
|
505
|
+
|
|
506
|
+
```javascript
|
|
507
|
+
export default async function handler(req, res) {
|
|
508
|
+
if (req.method === 'GET') {
|
|
509
|
+
return res.status(200).json({ data: 'value' });
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
### New Style
|
|
515
|
+
|
|
516
|
+
```javascript
|
|
517
|
+
const { NextResponse } = require('../modules/next-response');
|
|
518
|
+
|
|
519
|
+
async function GET(request) {
|
|
520
|
+
return NextResponse.json({ data: 'value' });
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
module.exports = { GET };
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
## Summary
|
|
527
|
+
|
|
528
|
+
✅ **Identical to Next.js App Router**
|
|
529
|
+
✅ **NextResponse API**
|
|
530
|
+
✅ **Named HTTP method exports**
|
|
531
|
+
✅ **URL and search params**
|
|
532
|
+
✅ **Request body parsing**
|
|
533
|
+
✅ **Database integration ready**
|
|
534
|
+
✅ **Easy migration path**
|
|
535
|
+
|
|
536
|
+
Write your APIs exactly like Next.js! 🎉
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Database connection helper
|
|
2
|
+
// This is a mock - replace with real database connection
|
|
3
|
+
|
|
4
|
+
let isConnected = false;
|
|
5
|
+
|
|
6
|
+
async function connectDB() {
|
|
7
|
+
if (isConnected) {
|
|
8
|
+
console.log('✅ Using existing database connection');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
// In production, connect to real database here:
|
|
14
|
+
// await mongoose.connect(process.env.MONGODB_URI);
|
|
15
|
+
// or
|
|
16
|
+
// db = await new Database(process.env.DATABASE_URL);
|
|
17
|
+
|
|
18
|
+
console.log('✅ Database connected (mock)');
|
|
19
|
+
isConnected = true;
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error('❌ Database connection failed:', error);
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = connectDB;
|
|
27
|
+
|
|
28
|
+
// Example usage with MongoDB:
|
|
29
|
+
/*
|
|
30
|
+
const mongoose = require('mongoose');
|
|
31
|
+
|
|
32
|
+
async function connectDB() {
|
|
33
|
+
if (mongoose.connections[0].readyState) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
await mongoose.connect(process.env.MONGODB_URI, {
|
|
38
|
+
useNewUrlParser: true,
|
|
39
|
+
useUnifiedTopology: true,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
console.log('✅ MongoDB connected');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = connectDB;
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
// Example usage with PostgreSQL:
|
|
49
|
+
/*
|
|
50
|
+
const { Pool } = require('pg');
|
|
51
|
+
|
|
52
|
+
const pool = new Pool({
|
|
53
|
+
connectionString: process.env.DATABASE_URL,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
async function connectDB() {
|
|
57
|
+
try {
|
|
58
|
+
await pool.query('SELECT NOW()');
|
|
59
|
+
console.log('✅ PostgreSQL connected');
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error('❌ PostgreSQL connection failed:', error);
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = connectDB;
|
|
67
|
+
*/
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// User Model
|
|
2
|
+
// This is a mock - replace with real database model
|
|
3
|
+
|
|
4
|
+
// Mock in-memory database
|
|
5
|
+
let users = [
|
|
6
|
+
{ _id: '1', name: 'Aziz Ahmed', email: 'aziz@example.com', role: 'admin', phone: '123-456-7890' },
|
|
7
|
+
{ _id: '2', name: 'John Doe', email: 'john@example.com', role: 'user', phone: '098-765-4321' }
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
class User {
|
|
11
|
+
// Find one user
|
|
12
|
+
static async findOne(query) {
|
|
13
|
+
const user = users.find(u => {
|
|
14
|
+
return Object.keys(query).every(key => u[key] === query[key]);
|
|
15
|
+
});
|
|
16
|
+
return user || null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Find by ID
|
|
20
|
+
static async findById(id) {
|
|
21
|
+
return users.find(u => u._id === id) || null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Find all users
|
|
25
|
+
static async find(query = {}) {
|
|
26
|
+
if (Object.keys(query).length === 0) {
|
|
27
|
+
return users;
|
|
28
|
+
}
|
|
29
|
+
return users.filter(u => {
|
|
30
|
+
return Object.keys(query).every(key => u[key] === query[key]);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Create new user
|
|
35
|
+
static async create(userData) {
|
|
36
|
+
const newUser = {
|
|
37
|
+
_id: String(users.length + 1),
|
|
38
|
+
...userData,
|
|
39
|
+
createdAt: new Date().toISOString()
|
|
40
|
+
};
|
|
41
|
+
users.push(newUser);
|
|
42
|
+
return newUser;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Update user
|
|
46
|
+
static async findByIdAndUpdate(id, updates) {
|
|
47
|
+
const index = users.findIndex(u => u._id === id);
|
|
48
|
+
if (index === -1) return null;
|
|
49
|
+
|
|
50
|
+
users[index] = { ...users[index], ...updates, updatedAt: new Date().toISOString() };
|
|
51
|
+
return users[index];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Delete user
|
|
55
|
+
static async findByIdAndDelete(id) {
|
|
56
|
+
const index = users.findIndex(u => u._id === id);
|
|
57
|
+
if (index === -1) return null;
|
|
58
|
+
|
|
59
|
+
const deleted = users.splice(index, 1)[0];
|
|
60
|
+
return deleted;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Select specific fields
|
|
64
|
+
select(fields) {
|
|
65
|
+
// This is a chainable method for field selection
|
|
66
|
+
// In real Mongoose, this would be: User.findOne().select('name email')
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = User;
|
|
72
|
+
|
|
73
|
+
// Example usage with Mongoose:
|
|
74
|
+
/*
|
|
75
|
+
const mongoose = require('mongoose');
|
|
76
|
+
|
|
77
|
+
const userSchema = new mongoose.Schema({
|
|
78
|
+
name: {
|
|
79
|
+
type: String,
|
|
80
|
+
required: true
|
|
81
|
+
},
|
|
82
|
+
email: {
|
|
83
|
+
type: String,
|
|
84
|
+
required: true,
|
|
85
|
+
unique: true
|
|
86
|
+
},
|
|
87
|
+
password: {
|
|
88
|
+
type: String,
|
|
89
|
+
required: true
|
|
90
|
+
},
|
|
91
|
+
role: {
|
|
92
|
+
type: String,
|
|
93
|
+
enum: ['user', 'admin'],
|
|
94
|
+
default: 'user'
|
|
95
|
+
},
|
|
96
|
+
phone: String
|
|
97
|
+
}, {
|
|
98
|
+
timestamps: true
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
module.exports = mongoose.models.User || mongoose.model('User', userSchema);
|
|
102
|
+
*/
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// NextResponse - Next.js-compatible response helper
|
|
2
|
+
class NextResponse {
|
|
3
|
+
constructor(body, init = {}) {
|
|
4
|
+
this.body = body;
|
|
5
|
+
this.status = init.status || 200;
|
|
6
|
+
this.headers = new Map(Object.entries(init.headers || {}));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
static json(data, init = {}) {
|
|
10
|
+
return new NextResponse(JSON.stringify(data), {
|
|
11
|
+
...init,
|
|
12
|
+
headers: {
|
|
13
|
+
'Content-Type': 'application/json',
|
|
14
|
+
...(init.headers || {})
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static text(text, init = {}) {
|
|
20
|
+
return new NextResponse(text, {
|
|
21
|
+
...init,
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': 'text/plain',
|
|
24
|
+
...(init.headers || {})
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static redirect(url, init = {}) {
|
|
30
|
+
return new NextResponse(null, {
|
|
31
|
+
...init,
|
|
32
|
+
status: init.status || 307,
|
|
33
|
+
headers: {
|
|
34
|
+
'Location': url,
|
|
35
|
+
...(init.headers || {})
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static error() {
|
|
41
|
+
return new NextResponse(JSON.stringify({ error: 'Internal Server Error' }), {
|
|
42
|
+
status: 500,
|
|
43
|
+
headers: {
|
|
44
|
+
'Content-Type': 'application/json'
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Export for Node.js (server-side)
|
|
51
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
52
|
+
module.exports = { NextResponse };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Export for browser (if needed)
|
|
56
|
+
if (typeof window !== 'undefined') {
|
|
57
|
+
window.NextResponse = NextResponse;
|
|
58
|
+
}
|
|
@@ -30,17 +30,34 @@ function loadApiRoutes() {
|
|
|
30
30
|
// Clear require cache to allow hot reload
|
|
31
31
|
delete require.cache[require.resolve(filePath)];
|
|
32
32
|
|
|
33
|
-
// Load the API
|
|
33
|
+
// Load the API module
|
|
34
34
|
const module = require(filePath);
|
|
35
35
|
|
|
36
|
-
// Support both
|
|
37
|
-
|
|
36
|
+
// Support both styles:
|
|
37
|
+
// 1. Default export function (old style)
|
|
38
|
+
// 2. Named exports: GET, POST, PUT, DELETE (new Next.js App Router style)
|
|
38
39
|
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
if (module.GET || module.POST || module.PUT || module.DELETE || module.PATCH) {
|
|
41
|
+
// New style: Named exports
|
|
42
|
+
const methods = {};
|
|
43
|
+
if (module.GET) methods.GET = module.GET;
|
|
44
|
+
if (module.POST) methods.POST = module.POST;
|
|
45
|
+
if (module.PUT) methods.PUT = module.PUT;
|
|
46
|
+
if (module.DELETE) methods.DELETE = module.DELETE;
|
|
47
|
+
if (module.PATCH) methods.PATCH = module.PATCH;
|
|
48
|
+
|
|
49
|
+
apiHandlers[routeName] = methods;
|
|
50
|
+
console.log(` ✅ /api/${routeName} [${Object.keys(methods).join(', ')}]`);
|
|
42
51
|
} else {
|
|
43
|
-
|
|
52
|
+
// Old style: Default export
|
|
53
|
+
const handler = module.default || module;
|
|
54
|
+
|
|
55
|
+
if (typeof handler === 'function') {
|
|
56
|
+
apiHandlers[routeName] = handler;
|
|
57
|
+
console.log(` ✅ /api/${routeName}`);
|
|
58
|
+
} else {
|
|
59
|
+
console.log(` ⚠️ /api/${routeName} - No handler function exported`);
|
|
60
|
+
}
|
|
44
61
|
}
|
|
45
62
|
} catch (error) {
|
|
46
63
|
console.error(` ❌ /api/${routeName} - ${error.message}`);
|
|
@@ -49,6 +66,7 @@ function loadApiRoutes() {
|
|
|
49
66
|
|
|
50
67
|
console.log('');
|
|
51
68
|
}
|
|
69
|
+
}
|
|
52
70
|
|
|
53
71
|
// Parse request body
|
|
54
72
|
function parseBody(req) {
|
|
@@ -103,48 +121,91 @@ async function handleApiRequest(req, res) {
|
|
|
103
121
|
const body = await parseBody(req);
|
|
104
122
|
const query = parseQuery(req.url);
|
|
105
123
|
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
+
// Check if handler is a function (old style) or object with HTTP methods (new style)
|
|
125
|
+
let result;
|
|
126
|
+
|
|
127
|
+
if (typeof handler === 'function') {
|
|
128
|
+
// Old style: default export function
|
|
129
|
+
const apiReq = {
|
|
130
|
+
method: req.method,
|
|
131
|
+
body: body,
|
|
132
|
+
query: query,
|
|
133
|
+
headers: req.headers,
|
|
134
|
+
url: req.url
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const apiRes = {
|
|
138
|
+
statusCode: 200,
|
|
139
|
+
headers: {},
|
|
140
|
+
status(code) {
|
|
141
|
+
this.statusCode = code;
|
|
142
|
+
return this;
|
|
143
|
+
},
|
|
144
|
+
json(data) {
|
|
145
|
+
res.writeHead(this.statusCode, {
|
|
146
|
+
'Content-Type': 'application/json',
|
|
147
|
+
'Access-Control-Allow-Origin': '*',
|
|
148
|
+
...this.headers
|
|
149
|
+
});
|
|
150
|
+
res.end(JSON.stringify(data));
|
|
151
|
+
return this;
|
|
152
|
+
},
|
|
153
|
+
send(data) {
|
|
154
|
+
res.writeHead(this.statusCode, {
|
|
155
|
+
'Content-Type': 'text/plain',
|
|
156
|
+
'Access-Control-Allow-Origin': '*',
|
|
157
|
+
...this.headers
|
|
158
|
+
});
|
|
159
|
+
res.end(data);
|
|
160
|
+
return this;
|
|
161
|
+
},
|
|
162
|
+
setHeader(key, value) {
|
|
163
|
+
this.headers[key] = value;
|
|
164
|
+
return this;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
await handler(apiReq, apiRes);
|
|
169
|
+
} else if (typeof handler === 'object') {
|
|
170
|
+
// New style: Named exports (GET, POST, PUT, DELETE)
|
|
171
|
+
const methodHandler = handler[req.method];
|
|
172
|
+
|
|
173
|
+
if (!methodHandler) {
|
|
174
|
+
res.writeHead(405, {
|
|
124
175
|
'Content-Type': 'application/json',
|
|
125
|
-
'
|
|
126
|
-
...this.headers
|
|
127
|
-
});
|
|
128
|
-
res.end(JSON.stringify(data));
|
|
129
|
-
return this;
|
|
130
|
-
},
|
|
131
|
-
send(data) {
|
|
132
|
-
res.writeHead(this.statusCode, {
|
|
133
|
-
'Content-Type': 'text/plain',
|
|
134
|
-
'Access-Control-Allow-Origin': '*',
|
|
135
|
-
...this.headers
|
|
176
|
+
'Allow': Object.keys(handler).join(', ')
|
|
136
177
|
});
|
|
137
|
-
res.end(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return this;
|
|
178
|
+
res.end(JSON.stringify({
|
|
179
|
+
error: 'Method not allowed',
|
|
180
|
+
allowedMethods: Object.keys(handler)
|
|
181
|
+
}));
|
|
182
|
+
return;
|
|
143
183
|
}
|
|
144
|
-
};
|
|
145
184
|
|
|
146
|
-
|
|
147
|
-
|
|
185
|
+
// Create Next.js-style request object
|
|
186
|
+
const request = {
|
|
187
|
+
method: req.method,
|
|
188
|
+
headers: req.headers,
|
|
189
|
+
url: `http://localhost:${PORT}${req.url}`,
|
|
190
|
+
json: async () => body,
|
|
191
|
+
text: async () => typeof body === 'string' ? body : JSON.stringify(body)
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// Call the handler
|
|
195
|
+
result = await methodHandler(request);
|
|
196
|
+
|
|
197
|
+
// Handle NextResponse
|
|
198
|
+
if (result && result.body !== undefined) {
|
|
199
|
+
const statusCode = result.status || 200;
|
|
200
|
+
const headers = {
|
|
201
|
+
'Access-Control-Allow-Origin': '*',
|
|
202
|
+
...Object.fromEntries(result.headers || [])
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
res.writeHead(statusCode, headers);
|
|
206
|
+
res.end(result.body);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
148
209
|
|
|
149
210
|
} catch (error) {
|
|
150
211
|
console.error(`❌ API Error on /api/${routeName}:`, error);
|