-
Notifications
You must be signed in to change notification settings - Fork 130
/
Copy pathindex.ts
124 lines (119 loc) · 3.74 KB
/
index.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import { KoaBodyMiddlewareOptionsSchema } from './types';
import type { KoaBodyMiddlewareOptions } from './types';
import type { Context, Middleware, Next } from 'koa';
import * as Koa from 'koa';
import type { Files } from 'formidable';
import coBody from 'co-body';
import toHttpMethod from './utils/string-method-to-enum-method';
import throwableToError from './utils/throwable-to-error';
import { isJsonBody, isMultipartBody, isTextBody, isUrlencodedBody } from './utils/body-type-util';
import parseWithFormidable from './utils/parse-with-formidable';
import { patchNodeAndKoa } from './utils/patch-util';
import type { ContextWithBodyAndFiles } from './utils/patch-util';
export * from './types';
declare module 'koa' {
interface Request extends Koa.BaseRequest {
body?: any;
files?: Files;
}
}
export function koaBody(options: Partial<KoaBodyMiddlewareOptions> = {}): Middleware {
const validatedOptions = KoaBodyMiddlewareOptionsSchema.parse(options);
const optionsToUse = { ...options, ...validatedOptions };
return async (ctx: Context, next: Next) => {
const isJson = isJsonBody(ctx, optionsToUse);
const isText = isTextBody(ctx, optionsToUse);
const isUrlencoded = isUrlencodedBody(ctx, optionsToUse);
const isMultipart = isMultipartBody(ctx, optionsToUse);
const {
encoding,
jsonStrict,
jsonLimit,
includeUnparsed: returnRawBody,
formLimit,
textLimit,
queryString,
formidable,
onError,
patchNode,
patchKoa,
} = optionsToUse;
// only parse the body on specifically chosen methods
if (validatedOptions.parsedMethods.includes(toHttpMethod(ctx.method.toUpperCase()))) {
try {
if (isJson) {
const jsonBody = await coBody.json(ctx, {
encoding,
limit: jsonLimit,
strict: jsonStrict,
returnRawBody,
});
patchNodeAndKoa(ctx as ContextWithBodyAndFiles, jsonBody, {
isText,
includeUnparsed: returnRawBody,
isMultipart,
patchKoa,
patchNode,
});
} else if (isUrlencoded) {
const urlEncodedBody = await coBody.form(ctx, {
encoding,
limit: formLimit,
queryString: queryString,
returnRawBody,
});
patchNodeAndKoa(ctx as ContextWithBodyAndFiles, urlEncodedBody, {
isText,
includeUnparsed: returnRawBody,
isMultipart,
patchKoa,
patchNode,
});
} else if (isText) {
const textBody = await coBody.text(ctx, {
encoding,
limit: textLimit,
returnRawBody,
});
patchNodeAndKoa(ctx as ContextWithBodyAndFiles, textBody, {
isText,
includeUnparsed: returnRawBody,
isMultipart,
patchKoa,
patchNode,
});
} else if (isMultipart) {
const multipartBody = await parseWithFormidable(ctx, formidable || {});
patchNodeAndKoa(ctx as ContextWithBodyAndFiles, multipartBody, {
isText,
includeUnparsed: returnRawBody,
isMultipart,
patchKoa,
patchNode,
});
}
} catch (parsingError) {
const error = throwableToError(parsingError);
if (typeof onError === 'function') {
onError(error, ctx);
} else {
throw error;
}
}
} else {
patchNodeAndKoa(
ctx as ContextWithBodyAndFiles,
{},
{
isText,
includeUnparsed: returnRawBody,
isMultipart,
patchKoa,
patchNode,
},
);
}
return next();
};
}
export default koaBody;