Skip to content

Commit 5ce7c71

Browse files
committed
fix: fixes interrupt behavior (#9)
1 parent 5b3d931 commit 5ce7c71

4 files changed

Lines changed: 28 additions & 70 deletions

File tree

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1 @@
1-
export const ENDPOINT_NAME = '/api/@cancel';
2-
export const REQUEST_ID = 'requestId';
3-
export const REQUEST_NOT_FOUND_MESSAGE = 'Request not found';
41
export const ENDPOINT_WAS_INTERRUPTED_MESSAGE = 'The endpoint was interrupted';

src/packages/frameworks/express/express.service.ts

Lines changed: 2 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -95,86 +95,21 @@ class ExpressRequestInterruptionService {
9595

9696
next();
9797
};
98-
99-
public existsRequest = (requestId: string): boolean => {
100-
return this.abortRegistries.has(requestId);
101-
};
102-
103-
public removeRequest = (requestId: string): void => {
104-
this.abortRegistries.delete(requestId);
105-
};
10698
}
10799

108100
/**
109101
* Initializes request interruption support for an Express application.
110102
*
111103
* This function:
112104
* - Adds a middleware that attaches an `AbortSignal` to every request.
113-
* - Adds a POST endpoint (default `/api/@cancel`) that can be called to abort a
114-
* specific request by sending its request ID in the request body.
115105
*
116106
* @param app - Express application instance.
117-
* @param options - Configuration options.
118-
* @param options.endpointName - The path where the abort endpoint will be mounted.
119-
* Defaults to `/api/@cancel`.
107+
120108
* @returns An `ExpressRequestInterruptionService` instance, which can be used
121109
* to manually abort requests if needed.
122110
*/
123-
export const initRequestInterrupts = (
124-
app: Express,
125-
{ endpointName = Constants.ENDPOINT_NAME }: { endpointName?: string } = {}
126-
) => {
111+
export const initRequestInterrupts = (app: Express): void => {
127112
const requestInterruptionService = new ExpressRequestInterruptionService();
128113

129114
app.use(requestInterruptionService.expressMiddleware);
130-
131-
app.post(endpointName, async (req, res) => {
132-
const requestId = await new Promise<string>((resolve) => {
133-
let rawBody = '';
134-
135-
req.on('data', (chunk) => {
136-
rawBody += chunk;
137-
});
138-
req.on('end', () => {
139-
resolve(rawBody);
140-
});
141-
});
142-
143-
if (!requestInterruptionService.existsRequest(requestId)) {
144-
return res.status(202).send();
145-
}
146-
147-
if (requestId && requestInterruptionService.abort(requestId)) {
148-
res.status(200).json({ aborted: true });
149-
} else {
150-
res.status(404).json({ error: Constants.REQUEST_NOT_FOUND_MESSAGE });
151-
}
152-
153-
requestInterruptionService.removeRequest(requestId);
154-
});
155115
};
156-
157-
/**
158-
* Retrieves the `signal` property from an Express Request object.
159-
*
160-
* @param {import('express').Request} req - The Express request object.
161-
* @returns {AbortSignal | undefined} The abort signal attached to the request,
162-
* or `undefined` if the property does not exist.
163-
*
164-
* @example
165-
* // In a route handler
166-
* app.get('/data', (req, res) => {
167-
* const signal = getAbortSignal(req);
168-
* fetch('https://api.example.com/data', { signal })
169-
* .then(response => response.json())
170-
* .then(data => res.json(data))
171-
* .catch(err => {
172-
* if (err.name === 'AbortError') {
173-
* res.status(499).end();
174-
* } else {
175-
* res.status(500).end();
176-
* }
177-
* });
178-
* });
179-
*/
180-
export const getAbortSignal = (req: Request): AbortSignal | undefined => (req as any).signal;

src/packages/frameworks/express/express.utils.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,28 @@ import { Request } from 'express';
2121
export const setSignalInExpressRequest = (req: Request, controller: AbortController): void => {
2222
(req as any).signal = controller.signal;
2323
};
24+
25+
/**
26+
* Retrieves the `signal` property from an Express Request object.
27+
*
28+
* @param {import('express').Request} req - The Express request object.
29+
* @returns {AbortSignal | undefined} The abort signal attached to the request,
30+
* or `undefined` if the property does not exist.
31+
*
32+
* @example
33+
* // In a route handler
34+
* app.get('/data', (req, res) => {
35+
* const signal = getAbortSignal(req);
36+
* fetch('https://api.example.com/data', { signal })
37+
* .then(response => response.json())
38+
* .then(data => res.json(data))
39+
* .catch(err => {
40+
* if (err.name === 'AbortError') {
41+
* res.status(499).end();
42+
* } else {
43+
* res.status(500).end();
44+
* }
45+
* });
46+
* });
47+
*/
48+
export const getAbortSignal = (req: Request): AbortSignal | undefined => (req as any).signal;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './express.service';
2+
export { getAbortSignal } from './express.utils';

0 commit comments

Comments
 (0)