Skip to content

Commit d682a8c

Browse files
committed
Update node-fetch-server README
1 parent c303f7c commit d682a8c

File tree

1 file changed

+93
-46
lines changed

1 file changed

+93
-46
lines changed

packages/node-fetch-server/README.md

Lines changed: 93 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
# node-fetch-server
22

3-
Build portable Node.js servers using web-standard Fetch API primitives 🚀
3+
Build portable Node.js servers using web-standard Fetch API primitives
44

55
`node-fetch-server` brings the simplicity and familiarity of the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to Node.js server development. Instead of dealing with Node's traditional `req`/`res` objects, you work with web-standard [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) and [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects—the same APIs you already use in the browser and modern JavaScript runtimes.
66

77
## Why node-fetch-server?
88

9-
- **Write once, run anywhere**: Your server code becomes portable across Node.js, Deno, Bun, Cloudflare Workers, and other platforms
10-
- **Familiar API**: Use the same Request/Response APIs you already know from client-side development
11-
- **Future-proof**: Align with web standards that are here to stay
12-
- **TypeScript-friendly**: Full type safety with standard web APIs
13-
- **Lightweight**: Minimal overhead while providing a cleaner, more intuitive API
14-
159
The Fetch API is already the standard for server development in:
1610

1711
- [`Bun.serve`](https://bun.sh/docs/api/http#bun-serve)
@@ -40,22 +34,39 @@ npm install @mjackson/node-fetch-server
4034

4135
### Basic Server
4236

37+
Here's a complete working example with a simple in-memory data store:
38+
4339
```ts
4440
import * as http from 'node:http';
4541
import { createRequestListener } from '@mjackson/node-fetch-server';
4642

47-
// Your request handler uses standard Request/Response objects
43+
// Example: Simple in-memory user storage
44+
let users = new Map([
45+
['1', { id: '1', name: 'Alice', email: '[email protected]' }],
46+
['2', { id: '2', name: 'Bob', email: '[email protected]' }],
47+
]);
48+
4849
async function handler(request: Request) {
4950
let url = new URL(request.url);
5051

51-
// Route based on pathname
52-
if (url.pathname === '/') {
53-
return new Response('Welcome to the home page!');
52+
// GET / - Home page
53+
if (url.pathname === '/' && request.method === 'GET') {
54+
return new Response('Welcome to the User API! Try GET /api/users');
5455
}
5556

56-
if (url.pathname === '/api/users') {
57-
let users = await getUsers(); // Your async logic here
58-
return Response.json(users);
57+
// GET /api/users - List all users
58+
if (url.pathname === '/api/users' && request.method === 'GET') {
59+
return Response.json(Array.from(users.values()));
60+
}
61+
62+
// GET /api/users/:id - Get specific user
63+
let userMatch = url.pathname.match(/^\/api\/users\/(\w+)$/);
64+
if (userMatch && request.method === 'GET') {
65+
let user = users.get(userMatch[1]);
66+
if (user) {
67+
return Response.json(user);
68+
}
69+
return new Response('User not found', { status: 404 });
5970
}
6071

6172
return new Response('Not Found', { status: 404 });
@@ -71,24 +82,47 @@ server.listen(3000, () => {
7182

7283
### Working with Request Data
7384

85+
Handle different types of request data using standard web APIs:
86+
7487
```ts
7588
async function handler(request: Request) {
76-
// Access request method, headers, and body just like in the browser
77-
if (request.method === 'POST' && request.url.endsWith('/api/users')) {
78-
// Parse JSON body
79-
let userData = await request.json();
80-
81-
// Validate and process...
82-
let newUser = await createUser(userData);
83-
84-
// Return JSON response
85-
return Response.json(newUser, {
86-
status: 201,
87-
headers: { 'Content-Type': 'application/json' },
89+
let url = new URL(request.url);
90+
91+
// Handle JSON data
92+
if (request.method === 'POST' && url.pathname === '/api/users') {
93+
try {
94+
let userData = await request.json();
95+
96+
// Validate required fields
97+
if (!userData.name || !userData.email) {
98+
return Response.json({ error: 'Name and email are required' }, { status: 400 });
99+
}
100+
101+
// Create user (your implementation)
102+
let newUser = {
103+
id: Date.now().toString(),
104+
...userData,
105+
};
106+
107+
return Response.json(newUser, { status: 201 });
108+
} catch (error) {
109+
return Response.json({ error: 'Invalid JSON' }, { status: 400 });
110+
}
111+
}
112+
113+
// Handle URL search params
114+
if (url.pathname === '/api/search') {
115+
let query = url.searchParams.get('q');
116+
let limit = parseInt(url.searchParams.get('limit') || '10');
117+
118+
return Response.json({
119+
query,
120+
limit,
121+
results: [], // Your search results here
88122
});
89123
}
90124

91-
return new Response('Method not allowed', { status: 405 });
125+
return new Response('Not Found', { status: 404 });
92126
}
93127
```
94128

@@ -204,10 +238,17 @@ let server = http.createServer(async (req, res) => {
204238
let request = createRequest(req, res, { host: process.env.HOST });
205239

206240
try {
207-
// Your custom middleware pipeline
208-
let response = await pipeline(authenticate, authorize, handleRequest)(request);
241+
// Add custom headers or middleware logic
242+
let startTime = Date.now();
209243

210-
// Convert Fetch API Response back to Node.js response
244+
// Process the request with your handler
245+
let response = await handler(request);
246+
247+
// Add response timing header
248+
let duration = Date.now() - startTime;
249+
response.headers.set('X-Response-Time', `${duration}ms`);
250+
251+
// Send the response
211252
await sendResponse(res, response);
212253
} catch (error) {
213254
console.error('Server error:', error);
@@ -233,42 +274,48 @@ This is useful for:
233274

234275
## Migration from Express
235276

236-
Transitioning from Express? Here's a quick comparison:
277+
Transitioning from Express? Here's a comparison of common patterns:
278+
279+
### Basic Routing
237280

238281
```ts
239-
// Express way
282+
// Express
283+
let app = express();
284+
240285
app.get('/users/:id', async (req, res) => {
241-
let user = await getUser(req.params.id);
286+
let user = await db.getUser(req.params.id);
287+
if (!user) {
288+
return res.status(404).json({ error: 'User not found' });
289+
}
242290
res.json(user);
243291
});
244292

245-
// node-fetch-server way
293+
app.listen(3000);
294+
295+
// node-fetch-server
296+
import { createRequestListener } from '@mjackson/node-fetch-server';
297+
246298
async function handler(request: Request) {
247299
let url = new URL(request.url);
248300
let match = url.pathname.match(/^\/users\/(\w+)$/);
249301

250-
if (match) {
251-
let user = await getUser(match[1]);
302+
if (match && request.method === 'GET') {
303+
let user = await db.getUser(match[1]);
304+
if (!user) {
305+
return Response.json({ error: 'User not found' }, { status: 404 });
306+
}
252307
return Response.json(user);
253308
}
254309

255310
return new Response('Not Found', { status: 404 });
256311
}
257-
```
258312

259-
Common patterns:
260-
261-
- `req.body``await request.json()`
262-
- `req.params` → Parse from `new URL(request.url).pathname`
263-
- `req.query``new URL(request.url).searchParams`
264-
- `res.json(data)``Response.json(data)`
265-
- `res.status(404).send()``new Response('', { status: 404 })`
266-
- `res.redirect()``new Response(null, { status: 302, headers: { Location: '/path' } })`
313+
http.createServer(createRequestListener(handler)).listen(3000);
314+
```
267315

268316
## Related Packages
269317

270318
- [`fetch-proxy`](https://github.com/mjackson/remix-the-web/tree/main/packages/fetch-proxy) - Build HTTP proxy servers using the web fetch API
271-
- [`fetch-router`](https://github.com/mjackson/remix-the-web/tree/main/packages/fetch-router) - URL pattern routing for Fetch API servers
272319

273320
## License
274321

0 commit comments

Comments
 (0)