create-aziz-app 3.1.1 → 3.1.3
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/README.md +658 -207
- package/bin/create-aziz-app.js +302 -351
- package/package.json +1 -1
- package/template/README.md +14 -279
- package/template/_framework/api.js +219 -219
- package/template/_framework/boot.js +33 -33
- package/template/_framework/hooks.js +367 -291
- package/template/_framework/next-response.js +128 -128
- package/template/_framework/route-match.js +145 -145
- package/template/_framework/router.js +465 -259
- package/template/_framework/runtime.js +264 -264
- package/template/app/layout.js +3 -5
- package/template/app/page.js +9 -32
- package/template/docs/01-getting-started.md +151 -151
- package/template/docs/02-project-structure.md +109 -109
- package/template/docs/03-pages-and-layouts.md +140 -140
- package/template/docs/04-routing.md +120 -120
- package/template/docs/05-hooks.md +169 -169
- package/template/docs/06-api-routes.md +210 -210
- package/template/docs/07-api-client.md +151 -151
- package/template/docs/08-styling.md +94 -94
- package/template/docs/09-imports-and-modules.md +97 -97
- package/template/docs/10-database-and-models.md +154 -154
- package/template/docs/11-authentication.md +171 -171
- package/template/docs/12-production-and-deployment.md +121 -121
- package/template/docs/13-internals.md +179 -179
- package/template/docs/README.md +67 -67
- package/template/index.html +20 -20
- package/template/package.json +16 -16
- package/template/scripts/dev-server.js +493 -381
- package/template/scripts/lib/api-router.js +525 -525
- package/template/scripts/lib/js-transform.js +213 -141
- package/template/scripts/lib/module-resolver.js +132 -132
|
@@ -1,97 +1,97 @@
|
|
|
1
|
-
# 09 · Imports & Modules
|
|
2
|
-
|
|
3
|
-
Browser code imports work in two "flavors": **browser modules** served by the dev server, and **npm packages**. Everything goes through the same transform pipeline (JSX → `h()`, import rewriting).
|
|
4
|
-
|
|
5
|
-
## How imports are resolved
|
|
6
|
-
|
|
7
|
-
| Specifier | Becomes / behavior | Notes |
|
|
8
|
-
|------------|-------------------|-------|
|
|
9
|
-
| `./Component.js` or `../lib/utils` | stays relative | The dev server loads files by path |
|
|
10
|
-
| `/components/Navbar.js` | absolute in browser → maps to your project root | Works from anywhere |
|
|
11
|
-
| `@/lib/db` | rewritten to `/lib/db` | Handy when deeply nested |
|
|
12
|
-
| `mongoose` | rewritten to `/_modules/mongoose` | Bare npm package |
|
|
13
|
-
| `lodash-es` | rewritten to `/_modules/lodash-es` | Exports field respected |
|
|
14
|
-
| `node:fs`, `data:`, `file:`, `http://…` | left untouched | Skipped by the rewriter |
|
|
15
|
-
|
|
16
|
-
The rewriter runs on **entire modules** (so multi-line `import { … } from 'pkg'` is handled correctly). It rewrites:
|
|
17
|
-
|
|
18
|
-
- `import X from '…'` and `export … from '…'`
|
|
19
|
-
- side-effect `import '…'`
|
|
20
|
-
- dynamic `import('…')`
|
|
21
|
-
|
|
22
|
-
## In your pages/components
|
|
23
|
-
|
|
24
|
-
Pages and components run in the browser (ES modules). You can import shared components, utilities, or anything you ship.
|
|
25
|
-
|
|
26
|
-
```js
|
|
27
|
-
// app/dashboard/page.js
|
|
28
|
-
import Navbar from '/components/Navbar.js';
|
|
29
|
-
import { format } from '@/lib/format.js';
|
|
30
|
-
import Button from './Button.js'; // co-located
|
|
31
|
-
|
|
32
|
-
export default function Dashboard() {
|
|
33
|
-
return (
|
|
34
|
-
<div>
|
|
35
|
-
<Navbar />
|
|
36
|
-
<Button label={format('hello')} />
|
|
37
|
-
</div>
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
**No imports of React/hooks are needed.** `h`, `Fragment`, `useState`, etc. are global.
|
|
43
|
-
|
|
44
|
-
## npm packages
|
|
45
|
-
|
|
46
|
-
1. Install first:
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
npm install lodash-es
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
2. Import normally:
|
|
53
|
-
|
|
54
|
-
```js
|
|
55
|
-
import { pick } from 'lodash-es';
|
|
56
|
-
|
|
57
|
-
const user = pick(obj, ['id', 'name']);
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
The dev server resolves `lodash-es` to `/_modules/lodash-es`. Internally it looks into `node_modules/` and honors the `exports`/`browser`/`module`/`main` fields (see `scripts/lib/module-resolver.js`). If a module can't be found, the server returns a 404 and the browser throws — `npm install` fixes it.
|
|
61
|
-
|
|
62
|
-
## In API routes (server side)
|
|
63
|
-
|
|
64
|
-
API routes are **Node.js code** (`api/*.js` or `.mjs`). Use Node's resolution:
|
|
65
|
-
|
|
66
|
-
```js
|
|
67
|
-
// api/users.js
|
|
68
|
-
const { NextResponse } = require('../_framework/next-response');
|
|
69
|
-
const { connect } = require('../lib/db'); // server utility
|
|
70
|
-
const User = require('../models/User');
|
|
71
|
-
|
|
72
|
-
module.exports = {
|
|
73
|
-
GET: async () => {
|
|
74
|
-
await connect();
|
|
75
|
-
return NextResponse.json(await User.find());
|
|
76
|
-
},
|
|
77
|
-
};
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Bare `mongoose` in API routes is the usual `require('mongoose')` (no `/_modules` rewrite needed).
|
|
81
|
-
|
|
82
|
-
## Loading strategy
|
|
83
|
-
|
|
84
|
-
- `/_modules/*` is **on-the-fly**. The dev server reads the module file, runs the same transform pipeline (JSX transform only affects files inside your app tree; modules usually don't contain JSX), and serves it as ES module text.
|
|
85
|
-
- Transforms for your own files (`app/`, `components/`) are **mtime-cached** to make hot reload snappy.
|
|
86
|
-
- Framework internals (`/_framework/*`) are served as-is (no JSX rewrite).
|
|
87
|
-
|
|
88
|
-
## Tips
|
|
89
|
-
|
|
90
|
-
- Use **absolute** (`/…`) for imports from the root, or `@/` for ergonomic deep imports.
|
|
91
|
-
- Keep imports **explicit** with `.js` extensions when referencing local files in browser code (works fine in this system).
|
|
92
|
-
- Dynamic `import()` is rewritten in browser code (`import('lodash-es')` → `import('/_modules/lodash-es')`) and also works natively in Node (`.mjs` context).
|
|
93
|
-
- Avoid mixing `require` into browser code — it's never injected. Stick to `import/export`.
|
|
94
|
-
|
|
95
|
-
## Continue
|
|
96
|
-
|
|
97
|
-
→ [Database & Models](./10-database-and-models.md)
|
|
1
|
+
# 09 · Imports & Modules
|
|
2
|
+
|
|
3
|
+
Browser code imports work in two "flavors": **browser modules** served by the dev server, and **npm packages**. Everything goes through the same transform pipeline (JSX → `h()`, import rewriting).
|
|
4
|
+
|
|
5
|
+
## How imports are resolved
|
|
6
|
+
|
|
7
|
+
| Specifier | Becomes / behavior | Notes |
|
|
8
|
+
|------------|-------------------|-------|
|
|
9
|
+
| `./Component.js` or `../lib/utils` | stays relative | The dev server loads files by path |
|
|
10
|
+
| `/components/Navbar.js` | absolute in browser → maps to your project root | Works from anywhere |
|
|
11
|
+
| `@/lib/db` | rewritten to `/lib/db` | Handy when deeply nested |
|
|
12
|
+
| `mongoose` | rewritten to `/_modules/mongoose` | Bare npm package |
|
|
13
|
+
| `lodash-es` | rewritten to `/_modules/lodash-es` | Exports field respected |
|
|
14
|
+
| `node:fs`, `data:`, `file:`, `http://…` | left untouched | Skipped by the rewriter |
|
|
15
|
+
|
|
16
|
+
The rewriter runs on **entire modules** (so multi-line `import { … } from 'pkg'` is handled correctly). It rewrites:
|
|
17
|
+
|
|
18
|
+
- `import X from '…'` and `export … from '…'`
|
|
19
|
+
- side-effect `import '…'`
|
|
20
|
+
- dynamic `import('…')`
|
|
21
|
+
|
|
22
|
+
## In your pages/components
|
|
23
|
+
|
|
24
|
+
Pages and components run in the browser (ES modules). You can import shared components, utilities, or anything you ship.
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
// app/dashboard/page.js
|
|
28
|
+
import Navbar from '/components/Navbar.js';
|
|
29
|
+
import { format } from '@/lib/format.js';
|
|
30
|
+
import Button from './Button.js'; // co-located
|
|
31
|
+
|
|
32
|
+
export default function Dashboard() {
|
|
33
|
+
return (
|
|
34
|
+
<div>
|
|
35
|
+
<Navbar />
|
|
36
|
+
<Button label={format('hello')} />
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**No imports of React/hooks are needed.** `h`, `Fragment`, `useState`, etc. are global.
|
|
43
|
+
|
|
44
|
+
## npm packages
|
|
45
|
+
|
|
46
|
+
1. Install first:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install lodash-es
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
2. Import normally:
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
import { pick } from 'lodash-es';
|
|
56
|
+
|
|
57
|
+
const user = pick(obj, ['id', 'name']);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The dev server resolves `lodash-es` to `/_modules/lodash-es`. Internally it looks into `node_modules/` and honors the `exports`/`browser`/`module`/`main` fields (see `scripts/lib/module-resolver.js`). If a module can't be found, the server returns a 404 and the browser throws — `npm install` fixes it.
|
|
61
|
+
|
|
62
|
+
## In API routes (server side)
|
|
63
|
+
|
|
64
|
+
API routes are **Node.js code** (`api/*.js` or `.mjs`). Use Node's resolution:
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
// api/users.js
|
|
68
|
+
const { NextResponse } = require('../_framework/next-response');
|
|
69
|
+
const { connect } = require('../lib/db'); // server utility
|
|
70
|
+
const User = require('../models/User');
|
|
71
|
+
|
|
72
|
+
module.exports = {
|
|
73
|
+
GET: async () => {
|
|
74
|
+
await connect();
|
|
75
|
+
return NextResponse.json(await User.find());
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Bare `mongoose` in API routes is the usual `require('mongoose')` (no `/_modules` rewrite needed).
|
|
81
|
+
|
|
82
|
+
## Loading strategy
|
|
83
|
+
|
|
84
|
+
- `/_modules/*` is **on-the-fly**. The dev server reads the module file, runs the same transform pipeline (JSX transform only affects files inside your app tree; modules usually don't contain JSX), and serves it as ES module text.
|
|
85
|
+
- Transforms for your own files (`app/`, `components/`) are **mtime-cached** to make hot reload snappy.
|
|
86
|
+
- Framework internals (`/_framework/*`) are served as-is (no JSX rewrite).
|
|
87
|
+
|
|
88
|
+
## Tips
|
|
89
|
+
|
|
90
|
+
- Use **absolute** (`/…`) for imports from the root, or `@/` for ergonomic deep imports.
|
|
91
|
+
- Keep imports **explicit** with `.js` extensions when referencing local files in browser code (works fine in this system).
|
|
92
|
+
- Dynamic `import()` is rewritten in browser code (`import('lodash-es')` → `import('/_modules/lodash-es')`) and also works natively in Node (`.mjs` context).
|
|
93
|
+
- Avoid mixing `require` into browser code — it's never injected. Stick to `import/export`.
|
|
94
|
+
|
|
95
|
+
## Continue
|
|
96
|
+
|
|
97
|
+
→ [Database & Models](./10-database-and-models.md)
|
|
@@ -1,154 +1,154 @@
|
|
|
1
|
-
# 10 · Database & Models
|
|
2
|
-
|
|
3
|
-
Since API routes run in **real Node.js**, you can connect to databases, send emails, and touch secrets. Do **not** put secrets or DB connections in browser code.
|
|
4
|
-
|
|
5
|
-
## Where DB code lives
|
|
6
|
-
|
|
7
|
-
Put utilities and models under `lib/` and `models/`. Import them from API routes using CommonJS:
|
|
8
|
-
|
|
9
|
-
```text
|
|
10
|
-
api/users.js → talks to HTTP
|
|
11
|
-
lib/db.js → connects to MongoDB
|
|
12
|
-
models/User.js → schema + model
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## MongoDB + Mongoose (working example)
|
|
16
|
-
|
|
17
|
-
### 1. Install
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm install mongoose
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
### 2. `lib/db.js`
|
|
24
|
-
|
|
25
|
-
```js
|
|
26
|
-
// lib/db.js
|
|
27
|
-
const mongoose = require('mongoose');
|
|
28
|
-
|
|
29
|
-
const URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/azizjs';
|
|
30
|
-
|
|
31
|
-
let conn = null;
|
|
32
|
-
|
|
33
|
-
async function connectDB() {
|
|
34
|
-
if (conn) return conn;
|
|
35
|
-
conn = await mongoose.connect(URI, { maxPoolSize: 10 });
|
|
36
|
-
console.log('✅ MongoDB connected');
|
|
37
|
-
return conn;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
module.exports = { connectDB };
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### 3. `models/User.js`
|
|
44
|
-
|
|
45
|
-
```js
|
|
46
|
-
// models/User.js
|
|
47
|
-
const mongoose = require('mongoose');
|
|
48
|
-
|
|
49
|
-
const UserSchema = new mongoose.Schema({
|
|
50
|
-
name: String,
|
|
51
|
-
email: String,
|
|
52
|
-
createdAt: { type: Date, default: Date.now },
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
const User = mongoose.models.User || mongoose.model('User', UserSchema);
|
|
56
|
-
module.exports = User;
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### 4. `api/users.js`
|
|
60
|
-
|
|
61
|
-
```js
|
|
62
|
-
// api/users.js
|
|
63
|
-
const { NextResponse } = require('../_framework/next-response');
|
|
64
|
-
const { connectDB } = require('../lib/db');
|
|
65
|
-
const User = require('../models/User');
|
|
66
|
-
|
|
67
|
-
module.exports = {
|
|
68
|
-
GET: async () => {
|
|
69
|
-
await connectDB();
|
|
70
|
-
const users = await User.find().select('-__v').lean();
|
|
71
|
-
return NextResponse.json(users);
|
|
72
|
-
},
|
|
73
|
-
|
|
74
|
-
POST: async (request) => {
|
|
75
|
-
const body = await request.json();
|
|
76
|
-
await connectDB();
|
|
77
|
-
const user = await User.create(body);
|
|
78
|
-
return NextResponse.json(user, { status: 201 });
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### 5. `api/users/[id].js`
|
|
84
|
-
|
|
85
|
-
```js
|
|
86
|
-
// api/users/[id].js
|
|
87
|
-
const { NextResponse } = require('../_framework/next-response');
|
|
88
|
-
const { connectDB } = require('../lib/db');
|
|
89
|
-
const User = require('../models/User');
|
|
90
|
-
|
|
91
|
-
module.exports = {
|
|
92
|
-
GET: async (request) => {
|
|
93
|
-
await connectDB();
|
|
94
|
-
const user = await User.findById(request.params.id);
|
|
95
|
-
if (!user) return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
|
96
|
-
return NextResponse.json(user);
|
|
97
|
-
},
|
|
98
|
-
|
|
99
|
-
PUT: async (request) => {
|
|
100
|
-
const body = await request.json();
|
|
101
|
-
await connectDB();
|
|
102
|
-
const user = await User.findByIdAndUpdate(request.params.id, body, { new: true });
|
|
103
|
-
if (!user) return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
|
104
|
-
return NextResponse.json(user);
|
|
105
|
-
},
|
|
106
|
-
|
|
107
|
-
DELETE: async (request) => {
|
|
108
|
-
await connectDB();
|
|
109
|
-
const user = await User.findByIdAndDelete(request.params.id);
|
|
110
|
-
if (!user) return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
|
111
|
-
return NextResponse.json({ ok: true });
|
|
112
|
-
},
|
|
113
|
-
};
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
## Fetching from the browser
|
|
117
|
-
|
|
118
|
-
Use `api` or `useFetch`:
|
|
119
|
-
|
|
120
|
-
```js
|
|
121
|
-
// declarative
|
|
122
|
-
const { data, loading, error } = useFetch('/api/users');
|
|
123
|
-
|
|
124
|
-
// imperative
|
|
125
|
-
async function addUser() {
|
|
126
|
-
await api.post('/api/users', { name: 'Aziz', email: 'aziz@example.com' });
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## Other databases
|
|
131
|
-
|
|
132
|
-
You don't need to change anything. Use native drivers:
|
|
133
|
-
|
|
134
|
-
```js
|
|
135
|
-
// lib/pg.js
|
|
136
|
-
const { Pool } = require('pg');
|
|
137
|
-
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
138
|
-
module.exports = { query: (text, params) => pool.query(text, params) };
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
## Hot reload & caching
|
|
142
|
-
|
|
143
|
-
Editing `lib/db.js` or `models/User.js` triggers server reload — the dev server purges project `require.cache` entries (excluding `node_modules`). Active DB connections may persist; keep your connection logic idempotent (`conn = null` singleton) as above.
|
|
144
|
-
|
|
145
|
-
## Tips
|
|
146
|
-
|
|
147
|
-
- **Never** store DB credentials in browser files. Use environment variables (`.env`) and read them in API routes (`process.env.MONGODB_URI`). A future improvement could load `.env`, but today it's manual.
|
|
148
|
-
- **Return lean objects** (`.lean()`) to cut JSON overhead.
|
|
149
|
-
- **Validate input** — throw `Error` with `err.status = 400` on bad payloads.
|
|
150
|
-
- **Use transactions** for multi-step operations.
|
|
151
|
-
|
|
152
|
-
## Continue
|
|
153
|
-
|
|
154
|
-
→ [Authentication](./11-authentication.md)
|
|
1
|
+
# 10 · Database & Models
|
|
2
|
+
|
|
3
|
+
Since API routes run in **real Node.js**, you can connect to databases, send emails, and touch secrets. Do **not** put secrets or DB connections in browser code.
|
|
4
|
+
|
|
5
|
+
## Where DB code lives
|
|
6
|
+
|
|
7
|
+
Put utilities and models under `lib/` and `models/`. Import them from API routes using CommonJS:
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
api/users.js → talks to HTTP
|
|
11
|
+
lib/db.js → connects to MongoDB
|
|
12
|
+
models/User.js → schema + model
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## MongoDB + Mongoose (working example)
|
|
16
|
+
|
|
17
|
+
### 1. Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install mongoose
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 2. `lib/db.js`
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
// lib/db.js
|
|
27
|
+
const mongoose = require('mongoose');
|
|
28
|
+
|
|
29
|
+
const URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/azizjs';
|
|
30
|
+
|
|
31
|
+
let conn = null;
|
|
32
|
+
|
|
33
|
+
async function connectDB() {
|
|
34
|
+
if (conn) return conn;
|
|
35
|
+
conn = await mongoose.connect(URI, { maxPoolSize: 10 });
|
|
36
|
+
console.log('✅ MongoDB connected');
|
|
37
|
+
return conn;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = { connectDB };
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 3. `models/User.js`
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
// models/User.js
|
|
47
|
+
const mongoose = require('mongoose');
|
|
48
|
+
|
|
49
|
+
const UserSchema = new mongoose.Schema({
|
|
50
|
+
name: String,
|
|
51
|
+
email: String,
|
|
52
|
+
createdAt: { type: Date, default: Date.now },
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const User = mongoose.models.User || mongoose.model('User', UserSchema);
|
|
56
|
+
module.exports = User;
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 4. `api/users.js`
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
// api/users.js
|
|
63
|
+
const { NextResponse } = require('../_framework/next-response');
|
|
64
|
+
const { connectDB } = require('../lib/db');
|
|
65
|
+
const User = require('../models/User');
|
|
66
|
+
|
|
67
|
+
module.exports = {
|
|
68
|
+
GET: async () => {
|
|
69
|
+
await connectDB();
|
|
70
|
+
const users = await User.find().select('-__v').lean();
|
|
71
|
+
return NextResponse.json(users);
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
POST: async (request) => {
|
|
75
|
+
const body = await request.json();
|
|
76
|
+
await connectDB();
|
|
77
|
+
const user = await User.create(body);
|
|
78
|
+
return NextResponse.json(user, { status: 201 });
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 5. `api/users/[id].js`
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
// api/users/[id].js
|
|
87
|
+
const { NextResponse } = require('../_framework/next-response');
|
|
88
|
+
const { connectDB } = require('../lib/db');
|
|
89
|
+
const User = require('../models/User');
|
|
90
|
+
|
|
91
|
+
module.exports = {
|
|
92
|
+
GET: async (request) => {
|
|
93
|
+
await connectDB();
|
|
94
|
+
const user = await User.findById(request.params.id);
|
|
95
|
+
if (!user) return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
|
96
|
+
return NextResponse.json(user);
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
PUT: async (request) => {
|
|
100
|
+
const body = await request.json();
|
|
101
|
+
await connectDB();
|
|
102
|
+
const user = await User.findByIdAndUpdate(request.params.id, body, { new: true });
|
|
103
|
+
if (!user) return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
|
104
|
+
return NextResponse.json(user);
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
DELETE: async (request) => {
|
|
108
|
+
await connectDB();
|
|
109
|
+
const user = await User.findByIdAndDelete(request.params.id);
|
|
110
|
+
if (!user) return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
|
111
|
+
return NextResponse.json({ ok: true });
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Fetching from the browser
|
|
117
|
+
|
|
118
|
+
Use `api` or `useFetch`:
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
// declarative
|
|
122
|
+
const { data, loading, error } = useFetch('/api/users');
|
|
123
|
+
|
|
124
|
+
// imperative
|
|
125
|
+
async function addUser() {
|
|
126
|
+
await api.post('/api/users', { name: 'Aziz', email: 'aziz@example.com' });
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Other databases
|
|
131
|
+
|
|
132
|
+
You don't need to change anything. Use native drivers:
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
// lib/pg.js
|
|
136
|
+
const { Pool } = require('pg');
|
|
137
|
+
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
138
|
+
module.exports = { query: (text, params) => pool.query(text, params) };
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Hot reload & caching
|
|
142
|
+
|
|
143
|
+
Editing `lib/db.js` or `models/User.js` triggers server reload — the dev server purges project `require.cache` entries (excluding `node_modules`). Active DB connections may persist; keep your connection logic idempotent (`conn = null` singleton) as above.
|
|
144
|
+
|
|
145
|
+
## Tips
|
|
146
|
+
|
|
147
|
+
- **Never** store DB credentials in browser files. Use environment variables (`.env`) and read them in API routes (`process.env.MONGODB_URI`). A future improvement could load `.env`, but today it's manual.
|
|
148
|
+
- **Return lean objects** (`.lean()`) to cut JSON overhead.
|
|
149
|
+
- **Validate input** — throw `Error` with `err.status = 400` on bad payloads.
|
|
150
|
+
- **Use transactions** for multi-step operations.
|
|
151
|
+
|
|
152
|
+
## Continue
|
|
153
|
+
|
|
154
|
+
→ [Authentication](./11-authentication.md)
|