@flink-app/generic-request-plugin 0.12.1-alpha.4 → 0.12.1-alpha.44

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.
Files changed (2) hide show
  1. package/package.json +4 -4
  2. package/readme.md +355 -18
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@flink-app/generic-request-plugin",
3
- "version": "0.12.1-alpha.4",
3
+ "version": "0.12.1-alpha.44",
4
4
  "description": "Flink plugin that makes it possible to override default request handlers and handle specific requests manually",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\"",
7
- "prepublish": "tsc"
7
+ "prepare": "tsc"
8
8
  },
9
9
  "author": "johan@frost.se",
10
10
  "publishConfig": {
@@ -18,11 +18,11 @@
18
18
  "node-color-log": "^5.3.1"
19
19
  },
20
20
  "devDependencies": {
21
- "@flink-app/flink": "^0.12.1-alpha.4",
21
+ "@flink-app/flink": "^0.12.1-alpha.44",
22
22
  "@types/express": "4.17.11",
23
23
  "@types/node": "22.13.10",
24
24
  "ts-node": "^9.1.1",
25
25
  "typescript": "5.4.5"
26
26
  },
27
- "gitHead": "8f06a4ab98e7179322d36546756d4305fd196f5a"
27
+ "gitHead": "4243e3b3cd6d4e1ca001a61baa8436bf2bbe4113"
28
28
  }
package/readme.md CHANGED
@@ -1,35 +1,372 @@
1
- # Flink API Docs
1
+ # @flink-app/generic-request-plugin
2
2
 
3
- A FLINK plugin that makes it possible to overide the default request handler and handle a request by your own code.
3
+ A lightweight Flink plugin that allows you to register custom request handlers with direct access to Express request and response objects. This plugin is useful when you need to bypass Flink's standard handler system and implement custom request handling logic.
4
4
 
5
- ## Usage
5
+ ## Features
6
6
 
7
- Install plugin to your flink app project:
7
+ - Register custom Express route handlers
8
+ - Direct access to Express `req`, `res`, and Flink `app` objects
9
+ - Support for all HTTP methods (GET, POST, PUT, DELETE)
10
+ - Bypass Flink's standard validation and response handling
11
+ - Useful for webhooks, custom integrations, and special endpoints
8
12
 
9
- ```
10
- npm i -S @flink-app/generic-request-plugin
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install @flink-app/generic-request-plugin
11
17
  ```
12
18
 
13
- Add and configure plugin in your app startup (probable the `index.ts` in root project):
19
+ ## Usage
14
20
 
15
- ```
16
- import { genericRequestPlugin, HttpMethod} from "@flink-app/generic-request-plugin";
21
+ ### Basic Setup
22
+
23
+ ```typescript
24
+ import { FlinkApp } from "@flink-app/flink";
25
+ import { genericRequestPlugin, HttpMethod } from "@flink-app/generic-request-plugin";
17
26
 
18
27
  function start() {
19
28
  new FlinkApp<AppContext>({
20
29
  name: "My app",
21
30
  plugins: [
22
- // Register plugin
23
- genericRequestPlugin({
24
- "path" : "/url",
25
- "method" : HttpMethod.get,
26
- "handler" : (req, res, app) => {
27
- res.setHeader('Content-type','text/html');
28
- res.end("Hello world!")
29
- }
30
- })
31
+ genericRequestPlugin({
32
+ path: "/custom-endpoint",
33
+ method: HttpMethod.get,
34
+ handler: (req, res, app) => {
35
+ res.setHeader("Content-Type", "text/html");
36
+ res.end("Hello world!");
37
+ },
38
+ }),
31
39
  ],
32
40
  }).start();
33
41
  }
42
+ ```
43
+
44
+ ## Configuration Options
45
+
46
+ - `path` (required): The URL path for the endpoint (e.g., `/webhook`, `/custom`)
47
+ - `method` (required): HTTP method for the request
48
+ - `handler` (required): Function that handles the request
49
+
50
+ ## HTTP Methods
51
+
52
+ The plugin supports the following HTTP methods via the `HttpMethod` enum:
53
+
54
+ - `HttpMethod.get` - GET requests
55
+ - `HttpMethod.post` - POST requests
56
+ - `HttpMethod.put` - PUT requests
57
+ - `HttpMethod.delete` - DELETE requests
58
+
59
+ ## Handler Function
60
+
61
+ The handler function receives three parameters:
62
+
63
+ ```typescript
64
+ handler: (req, res, app) => void
65
+ ```
66
+
67
+ - `req` - Express Request object
68
+ - `res` - Express Response object
69
+ - `app` - FlinkApp instance (provides access to context, repos, etc.)
70
+
71
+ ## Examples
72
+
73
+ ### Simple GET Endpoint
74
+
75
+ ```typescript
76
+ genericRequestPlugin({
77
+ path: "/hello",
78
+ method: HttpMethod.get,
79
+ handler: (req, res, app) => {
80
+ res.json({ message: "Hello from Flink!" });
81
+ },
82
+ });
83
+ ```
84
+
85
+ ### POST Endpoint with JSON Body
86
+
87
+ ```typescript
88
+ genericRequestPlugin({
89
+ path: "/webhook",
90
+ method: HttpMethod.post,
91
+ handler: (req, res, app) => {
92
+ const payload = req.body;
93
+ console.log("Received webhook:", payload);
94
+ res.status(200).json({ received: true });
95
+ },
96
+ });
97
+ ```
98
+
99
+ ### Endpoint with Database Access
100
+
101
+ ```typescript
102
+ genericRequestPlugin({
103
+ path: "/custom-data",
104
+ method: HttpMethod.get,
105
+ handler: async (req, res, app) => {
106
+ try {
107
+ const data = await app.ctx.repos.myRepo.findAll();
108
+ res.json({ data });
109
+ } catch (error) {
110
+ res.status(500).json({ error: "Failed to fetch data" });
111
+ }
112
+ },
113
+ });
114
+ ```
115
+
116
+ ### Endpoint with Query Parameters
117
+
118
+ ```typescript
119
+ genericRequestPlugin({
120
+ path: "/search",
121
+ method: HttpMethod.get,
122
+ handler: (req, res, app) => {
123
+ const query = req.query.q;
124
+ const results = performSearch(query);
125
+ res.json({ results });
126
+ },
127
+ });
128
+ ```
129
+
130
+ ### Endpoint with Path Parameters
131
+
132
+ ```typescript
133
+ genericRequestPlugin({
134
+ path: "/user/:id",
135
+ method: HttpMethod.get,
136
+ handler: async (req, res, app) => {
137
+ const userId = req.params.id;
138
+ const user = await app.ctx.repos.userRepo.findById(userId);
139
+
140
+ if (!user) {
141
+ res.status(404).json({ error: "User not found" });
142
+ return;
143
+ }
144
+
145
+ res.json({ user });
146
+ },
147
+ });
148
+ ```
149
+
150
+ ### Custom HTML Response
151
+
152
+ ```typescript
153
+ genericRequestPlugin({
154
+ path: "/status",
155
+ method: HttpMethod.get,
156
+ handler: (req, res, app) => {
157
+ const html = `
158
+ <!DOCTYPE html>
159
+ <html>
160
+ <head><title>Status</title></head>
161
+ <body>
162
+ <h1>System Status: OK</h1>
163
+ <p>All systems operational</p>
164
+ </body>
165
+ </html>
166
+ `;
167
+ res.setHeader("Content-Type", "text/html");
168
+ res.end(html);
169
+ },
170
+ });
171
+ ```
172
+
173
+ ### Webhook Handler
174
+
175
+ ```typescript
176
+ genericRequestPlugin({
177
+ path: "/webhook/stripe",
178
+ method: HttpMethod.post,
179
+ handler: async (req, res, app) => {
180
+ const signature = req.headers["stripe-signature"];
181
+ const payload = req.body;
182
+
183
+ // Verify webhook signature
184
+ if (!verifyStripeSignature(payload, signature)) {
185
+ res.status(401).json({ error: "Invalid signature" });
186
+ return;
187
+ }
188
+
189
+ // Process webhook
190
+ await app.ctx.repos.orderRepo.updatePaymentStatus(payload.data);
191
+
192
+ res.status(200).json({ received: true });
193
+ },
194
+ });
195
+ ```
196
+
197
+ ### File Download Endpoint
198
+
199
+ ```typescript
200
+ genericRequestPlugin({
201
+ path: "/download/:fileId",
202
+ method: HttpMethod.get,
203
+ handler: async (req, res, app) => {
204
+ const fileId = req.params.fileId;
205
+ const file = await app.ctx.repos.fileRepo.findById(fileId);
206
+
207
+ if (!file) {
208
+ res.status(404).json({ error: "File not found" });
209
+ return;
210
+ }
211
+
212
+ res.setHeader("Content-Type", file.mimeType);
213
+ res.setHeader("Content-Disposition", `attachment; filename="${file.name}"`);
214
+ res.end(file.buffer);
215
+ },
216
+ });
217
+ ```
218
+
219
+ ### Custom Authentication
220
+
221
+ ```typescript
222
+ genericRequestPlugin({
223
+ path: "/admin/action",
224
+ method: HttpMethod.post,
225
+ handler: async (req, res, app) => {
226
+ const apiKey = req.headers["x-api-key"];
227
+
228
+ // Custom authentication logic
229
+ if (apiKey !== process.env.ADMIN_API_KEY) {
230
+ res.status(401).json({ error: "Unauthorized" });
231
+ return;
232
+ }
233
+
234
+ // Perform admin action
235
+ const result = await performAdminAction(req.body);
236
+ res.json({ success: true, result });
237
+ },
238
+ });
239
+ ```
240
+
241
+ ## Multiple Endpoints
242
+
243
+ You can register multiple generic request handlers by including multiple plugin instances:
244
+
245
+ ```typescript
246
+ new FlinkApp<AppContext>({
247
+ name: "My app",
248
+ plugins: [
249
+ genericRequestPlugin({
250
+ path: "/webhook/stripe",
251
+ method: HttpMethod.post,
252
+ handler: stripeWebhookHandler,
253
+ }),
254
+ genericRequestPlugin({
255
+ path: "/webhook/github",
256
+ method: HttpMethod.post,
257
+ handler: githubWebhookHandler,
258
+ }),
259
+ genericRequestPlugin({
260
+ path: "/status",
261
+ method: HttpMethod.get,
262
+ handler: statusHandler,
263
+ }),
264
+ ],
265
+ }).start();
266
+ ```
267
+
268
+ ## When to Use This Plugin
269
+
270
+ Use the generic request plugin when you need to:
271
+
272
+ - Handle webhooks from external services
273
+ - Implement custom authentication or authorization logic
274
+ - Return non-JSON responses (HTML, XML, plain text, binary files)
275
+ - Bypass Flink's request validation
276
+ - Access low-level Express request/response objects
277
+ - Implement server-sent events (SSE)
278
+ - Handle file uploads/downloads with custom logic
279
+ - Integrate with third-party services requiring specific response formats
280
+
281
+ ## When NOT to Use This Plugin
282
+
283
+ For standard API endpoints, use Flink's built-in handler system instead:
284
+
285
+ - Standard CRUD operations - Use `FlinkHttpHandler` with GET/POST/PUT/DELETE
286
+ - Endpoints requiring validation - Use Flink's schema validation
287
+ - Type-safe endpoints - Use Flink's typed handlers
288
+ - Auto-documented endpoints - Use standard handlers with the API docs plugin
289
+
290
+ ## Access to FlinkApp Context
291
+
292
+ The handler receives the full FlinkApp instance, giving you access to:
293
+
294
+ ```typescript
295
+ handler: (req, res, app) => {
296
+ // Access repositories
297
+ const data = await app.ctx.repos.myRepo.findAll();
298
+
299
+ // Access plugins
300
+ const stripeAPI = app.ctx.plugins.stripePlugin.stripeAPI;
301
+
302
+ // Access database
303
+ const collection = app.db.collection("myCollection");
304
+
305
+ // Access any custom context properties
306
+ const config = app.ctx.config;
307
+ }
308
+ ```
309
+
310
+ ## Error Handling
311
+
312
+ Always implement proper error handling in your custom handlers:
34
313
 
314
+ ```typescript
315
+ genericRequestPlugin({
316
+ path: "/custom",
317
+ method: HttpMethod.post,
318
+ handler: async (req, res, app) => {
319
+ try {
320
+ // Your logic here
321
+ const result = await performOperation(req.body);
322
+ res.json({ success: true, result });
323
+ } catch (error) {
324
+ console.error("Error in custom handler:", error);
325
+ res.status(500).json({
326
+ error: "Internal server error",
327
+ message: error.message
328
+ });
329
+ }
330
+ },
331
+ });
35
332
  ```
333
+
334
+ ## TypeScript Support
335
+
336
+ The plugin includes TypeScript definitions. For better type safety, you can type your handlers:
337
+
338
+ ```typescript
339
+ import { Request, Response } from "express";
340
+ import { FlinkApp } from "@flink-app/flink";
341
+
342
+ const myHandler = async (
343
+ req: Request,
344
+ res: Response,
345
+ app: FlinkApp<AppContext>
346
+ ) => {
347
+ // Fully typed handler
348
+ const userId: string = req.params.id;
349
+ const user = await app.ctx.repos.userRepo.findById(userId);
350
+ res.json({ user });
351
+ };
352
+
353
+ genericRequestPlugin({
354
+ path: "/user/:id",
355
+ method: HttpMethod.get,
356
+ handler: myHandler,
357
+ });
358
+ ```
359
+
360
+ ## Security Considerations
361
+
362
+ - Always validate and sanitize input data
363
+ - Implement authentication/authorization when needed
364
+ - Be careful with direct database access
365
+ - Validate webhook signatures for external integrations
366
+ - Use HTTPS in production
367
+ - Rate limit sensitive endpoints
368
+ - Never expose sensitive information in error messages
369
+
370
+ ## License
371
+
372
+ MIT