Skip to content
This repository was archived by the owner on Nov 8, 2024. It is now read-only.

Commit e8c110b

Browse files
committed
feat(oas3): support example inside Parameter Object schema
1 parent 75e2672 commit e8c110b

File tree

3 files changed

+83
-5
lines changed

3 files changed

+83
-5
lines changed

packages/openapi3-parser/CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
### Enhancements
66

7-
- Minimal support for 'Parameter Object' schemas, simplest schemas using 'type'
8-
are supported.
7+
- Minimal support for 'Parameter Object' schemas, simple schemas using 'type'
8+
and 'example' are supported.
99

1010
## 0.15.1 (2020-11-10)
1111

packages/openapi3-parser/lib/parser/oas/parseParameterObjectSchemaObject.js

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,48 @@ const unsupportedKeys = [
1919
'properties', 'items', 'required', 'nullable', 'title', 'description',
2020
'default', 'oneOf', 'allOf', 'anyOf', 'not', 'additionalProperties',
2121
'format', 'discriminator', 'readOnly', 'writeOnly', 'xml', 'externalDocs',
22-
'deprecated', 'example',
22+
'deprecated',
2323
];
2424
const isUnsupportedKey = R.anyPass(R.map(hasKey, unsupportedKeys));
2525

26-
// purposely in the order defined in the JSON Schema spec, integer is an OAS 3 specific addition and thus is at the end
2726
const types = ['boolean', 'object', 'array', 'number', 'string', 'integer'];
2827
const isValidType = R.anyPass(R.map(hasValue, types));
2928

29+
const typeToElementNameMap = {
30+
array: 'array',
31+
boolean: 'boolean',
32+
integer: 'number',
33+
null: 'null',
34+
number: 'number',
35+
object: 'object',
36+
string: 'string',
37+
};
38+
39+
// Returns whether the given element value matches the provided schema type
40+
const valueMatchesType = (type, value) => {
41+
const expectedElementType = typeToElementNameMap[type];
42+
return value.element === expectedElementType;
43+
};
44+
45+
function validateValuesMatchSchema(context, schema) {
46+
const validate = (member) => {
47+
const type = schema.getValue('type');
48+
if (type && !valueMatchesType(type, member.value)) {
49+
return createWarning(context.namespace,
50+
`'${name}' '${member.key.toValue()}' does not match expected type '${type}'`, member.value);
51+
}
52+
53+
return member;
54+
};
55+
56+
const parseMember = R.cond([
57+
[hasKey('example'), validate],
58+
[R.T, e => e],
59+
]);
60+
61+
return parseObject(context, name, parseMember)(schema);
62+
}
63+
3064
/**
3165
* Parse Parameter Object's Schema Object
3266
*
@@ -53,6 +87,7 @@ function parseSchemaObject(context) {
5387

5488
const parseMember = R.cond([
5589
[hasKey('type'), parseType],
90+
[hasKey('example'), e => e.clone()],
5691

5792
[isUnsupportedKey, createUnsupportedMemberWarning(namespace, name)],
5893
[isExtension, () => new namespace.elements.ParseResult()],
@@ -61,6 +96,7 @@ function parseSchemaObject(context) {
6196

6297
return pipeParseResult(namespace,
6398
parseObject(context, name, parseMember, []),
99+
R.curry(validateValuesMatchSchema)(context),
64100
(schema) => {
65101
const type = schema.getValue('type');
66102
let element;
@@ -76,7 +112,12 @@ function parseSchemaObject(context) {
76112
} else if (type === 'boolean') {
77113
element = new namespace.elements.Boolean();
78114
} else {
79-
element = new namespace.elements.ParseResult([]);
115+
return new namespace.elements.ParseResult([]);
116+
}
117+
118+
const example = schema.get('example');
119+
if (example) {
120+
element.attributes.set('samples', [example]);
80121
}
81122

82123
return element;

packages/openapi3-parser/test/unit/parser/oas/parseParameterObject-test.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,43 @@ describe('Parameter Object', () => {
593593
expect(member.value).to.be.undefined;
594594
});
595595

596+
it('warns when example does not match expected type', () => {
597+
const schema = new namespace.elements.Object({
598+
name: 'example',
599+
in: 'query',
600+
schema: {
601+
type: 'integer',
602+
example: true,
603+
},
604+
});
605+
const parseResult = parse(context, schema);
606+
607+
expect(parseResult.length).to.equal(2);
608+
expect(parseResult).to.contain.warning(
609+
"'Schema Object' 'example' does not match expected type 'integer'"
610+
);
611+
});
612+
613+
it('uses example with type as value', () => {
614+
const parameter = new namespace.elements.Object({
615+
name: 'example',
616+
in: 'query',
617+
schema: {
618+
type: 'integer',
619+
example: 2048,
620+
},
621+
});
622+
623+
const parseResult = parse(context, parameter);
624+
625+
expect(parseResult.length).to.equal(1);
626+
const member = parseResult.get(0);
627+
expect(member).to.be.instanceof(namespace.elements.Member);
628+
expect(member.value).to.be.instanceof(namespace.elements.Number);
629+
expect(member.value.content).to.be.undefined;
630+
expect(member.value.attributes.get('samples').toValue()).to.deep.equal([2048]);
631+
});
632+
596633
it('provides a warning when schema is not an object', () => {
597634
const parameter = new namespace.elements.Object({
598635
name: 'example',

0 commit comments

Comments
 (0)