-
Notifications
You must be signed in to change notification settings - Fork 36
/
urlEncodedBodyParser.ts
111 lines (97 loc) · 4.37 KB
/
urlEncodedBodyParser.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
import * as oas3 from 'openapi3-ts';
import * as jsonPtr from 'json-ptr';
import querystring from 'querystring';
import BodyParserWrapper from '../bodyParsers/BodyParserWrapper';
import { MimeTypeParser, ParameterLocation, StringParser } from '../types';
import { resolveRef } from '../utils/json-schema-resolve-ref';
import { extractSchema } from '../utils/jsonSchema';
import Oas3CompileContext from './Oas3CompileContext';
import { ParameterDescriptor, ParameterParser, generateParser, parseQueryParameters } from './parameterParsers';
// OAS3 has special handling for 'application/x-www-form-urlencoded'. Parameters
// and bodies of this type are allowed to define an `encoding` section with
// special treatment for specific properties. This handles generating a parser
// for this content-type.
// Find a property in a JSON Schema.
function findProperty(path: string[], schema: oas3.SchemaObject, propertyName: string) : string[] | undefined {
if(schema.properties && schema.properties[propertyName]) {
return path;
}
const allOf = schema.allOf || [];
for(let index = 0; index < allOf.length; index++) {
const childSchema = resolveRef(schema, allOf[index]);
const answer = findProperty(path.concat(['allOf', `${index}`]), childSchema, propertyName);
if(answer) {
return answer;
}
}
return undefined;
}
export function generateStringParser(
context: Oas3CompileContext,
mediaType: oas3.MediaTypeObject,
parameterLocation: ParameterLocation
) : StringParser {
const parameterParsers: {
location: ParameterLocation,
parser: ParameterParser
}[] = [];
if(mediaType.encoding) {
if(!mediaType.schema) {
throw new Error(`Media Type Object ${context.jsonPointer} with 'content' must have a 'schema'`);
}
// Find the schema object for the mediaType.
const schema = resolveRef(context.openApiDoc, `${context.jsonPointer}/schema`);
// The encoding object describes how parameters should be parsed from the document.
for(const parameterName of Object.keys(mediaType.encoding)) {
const encoding: oas3.EncodingPropertyObject = mediaType.encoding[parameterName];
const parameterSchemaPath = findProperty([], schema, parameterName);
if(!parameterSchemaPath) {
throw new Error(`Cannot find parameter ${parameterName} in schema for ${context.jsonPointer}`);
}
const parameterSchema = extractSchema(context.openApiDoc, jsonPtr.encodePointer(parameterSchemaPath));
let parameterDescriptor: ParameterDescriptor;
if(encoding.contentType) {
const parser = context.options.parameterParsers.get(encoding.contentType);
if(!parser) {
throw new Error(`No string parser found for ${encoding.contentType} in ${context.jsonPointer}`);
}
parameterDescriptor = {
contentType: encoding.contentType,
parser,
uriEncoded: true,
schema: parameterSchema
};
} else {
parameterDescriptor = {
style: encoding.style || 'form',
explode: encoding.explode || false,
allowReserved: encoding.allowReserved || false,
schema: parameterSchema
};
}
parameterParsers.push({
location: {
in: parameterLocation.in,
name: parameterName,
docPath: context.childContext(['encoding', parameterName]).jsonPointer
},
parser: generateParser(parameterDescriptor)
});
}
}
return {
parseString(encoded: string) : any {
const rawResult = querystring.parse(encoded);
const parsedResult = parseQueryParameters(parameterParsers, encoded);
return Object.assign(rawResult, parsedResult);
}
};
}
export function generateBodyParser(
context: Oas3CompileContext,
mediaType: oas3.MediaTypeObject,
parameterLocation: ParameterLocation
) : MimeTypeParser {
const stringParser = generateStringParser(context, mediaType, parameterLocation);
return new BodyParserWrapper(stringParser, context.options.defaultMaxBodySize);
}