-
-
Notifications
You must be signed in to change notification settings - Fork 5k
/
batch.ts
98 lines (80 loc) · 2.78 KB
/
batch.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { bodyFields } from '../../utils/requestUtils';
import { SubPath } from '../../utils/routeUtils';
import Router from '../../utils/Router';
import { HttpMethod, RouteType } from '../../utils/types';
import { AppContext } from '../../utils/types';
import routeHandler from '../../middleware/routeHandler';
import config from '../../config';
import { ErrorBadRequest } from '../../utils/errors';
const router = new Router(RouteType.Api);
const maxSubRequests = 50;
interface SubRequest {
method: HttpMethod;
url: string;
headers: Record<string, string>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
body: any;
}
type SubRequests = Record<string, SubRequest>;
interface SubRequestResponse {
status: number;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
body: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
header: Record<string, any>;
}
type BatchResponse = Record<string, SubRequestResponse>;
function createSubRequestContext(ctx: AppContext, subRequest: SubRequest): AppContext {
const fullUrl = `${config().apiBaseUrl}/${subRequest.url.trim()}`;
const newContext: AppContext = {
...ctx,
URL: new URL(fullUrl),
request: {
...ctx.request,
method: subRequest.method,
},
method: subRequest.method,
headers: {
...ctx.headers,
...subRequest.headers,
},
body: subRequest.body,
joplin: {
...ctx.joplin,
appLogger: ctx.joplin.appLogger,
services: ctx.joplin.services,
db: ctx.joplin.db,
models: ctx.joplin.models,
routes: ctx.joplin.routes,
},
path: `/${subRequest.url}`,
url: fullUrl,
};
return newContext;
}
function validateRequest(request: SubRequest): SubRequest {
const output = { ...request };
if (!output.method) output.method = HttpMethod.GET;
if (!output.url) throw new Error('"url" is required');
return output;
}
router.post('api/batch', async (_path: SubPath, ctx: AppContext) => {
throw new Error('Not enabled');
// eslint-disable-next-line no-unreachable
const subRequests = await bodyFields<SubRequests>(ctx.req);
if (Object.keys(subRequests).length > maxSubRequests) throw new ErrorBadRequest(`Can only process up to ${maxSubRequests} requests`);
const response: BatchResponse = {};
for (const subRequestId of Object.keys(subRequests)) {
const subRequest = validateRequest(subRequests[subRequestId]);
const subRequestContext = createSubRequestContext(ctx, subRequest);
await routeHandler(subRequestContext);
const r = subRequestContext.response;
response[subRequestId] = {
status: r.status,
body: typeof r.body === 'object' ? { ...(r.body as object) } : r.body,
header: r.header ? { ...r.header } : {},
};
}
return response;
});
export default router;