Skip to content
This repository has been archived by the owner on Nov 28, 2022. It is now read-only.

Commit

Permalink
Fix problem where nested objects would appear empty
Browse files Browse the repository at this point in the history
On production right now if there's a nested object in a form, it always get
in the code sample even if the form values are not set:

```
--data '{"category":{}}'
```

This PR recursively removes empty objects from the form values so they
do not get set when making the request.

This problem was slightly exacerbated by #179 which auto applied default
values from the form to the samples.
  • Loading branch information
domharrington committed Dec 12, 2018
1 parent 70a2ac0 commit 0b760c3
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 3 deletions.
44 changes: 42 additions & 2 deletions packages/api-explorer/__tests__/lib/oas-to-har.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ describe('body values', () => {
},
{ body: { RAW_BODY: {} } },
).log.entries[0].request.postData.text,
).toEqual(JSON.stringify({}));
).toEqual(undefined);
});

it('should return nothing for undefined body property', () => {
Expand All @@ -679,7 +679,7 @@ describe('body values', () => {
},
{ body: { a: undefined } },
).log.entries[0].request.postData.text,
).toEqual(JSON.stringify({}));
).toEqual(undefined);
});

it('should work for schemas that require a lookup', () => {
Expand Down Expand Up @@ -863,6 +863,46 @@ describe('body values', () => {
).toEqual(JSON.stringify({ a: JSON.parse('{ "b": "valid json" }') }));
});
});

it('should not include objects with undefined sub properties', () => {
expect(
oasToHar(
{},
{
path: '/body',
method: 'get',
requestBody: {
content: {
'application/json': {
schema: {
type: 'object',
properties: {
a: {
type: 'object',
properties: {
b: {
type: 'string',
},
c: {
type: 'object',
properties: {
d: {
type: 'string',
},
},
},
},
},
},
},
},
},
},
},
{ body: { a: { b: undefined, c: { d: undefined } } } },
).log.entries[0].request.postData.text,
).toEqual(undefined);
});
});

describe('formData values', () => {
Expand Down
40 changes: 39 additions & 1 deletion packages/api-explorer/src/lib/oas-to-har.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,42 @@ function isPrimitive(val) {
return typeof val === 'string' || typeof val === 'number' || typeof val === 'boolean';
}

function isEmptyObject(obj) {
// Then remove all empty objects from the top level object
return typeof obj === 'object' && Object.keys(obj).length === 0;
}

// Modified from here: https://stackoverflow.com/a/43781499
function stripEmptyObjects(obj) {
Object.keys(obj).forEach(key => {
const value = obj[key];
if (typeof value === 'object') {
// Recurse, strip out empty objects from children
stripEmptyObjects(value);
// Then remove all empty objects from the top level object
if (isEmptyObject(value)) {
delete obj[key];
}
}
});
}

function removeUndefinedObjects(obj) {
// JSON.stringify removes undefined values
const withoutUndefined = JSON.parse(JSON.stringify(obj));

// Then we recursively remove all empty objects
stripEmptyObjects(withoutUndefined);

// If the only thing that's leftover is an empty object
// then return nothing so we don't end up with default
// code samples with:
// --data '{}'
if (isEmptyObject(withoutUndefined)) return undefined;

return withoutUndefined;
}

module.exports = (
oas,
pathOperation = { path: '', method: '' },
Expand Down Expand Up @@ -174,7 +210,9 @@ module.exports = (

function stringify(json) {
// Default to JSON.stringify
har.postData.text = JSON.stringify(typeof json.RAW_BODY !== 'undefined' ? json.RAW_BODY : json);
har.postData.text = JSON.stringify(
removeUndefinedObjects(typeof json.RAW_BODY !== 'undefined' ? json.RAW_BODY : json),
);
}

if (schema.schema && Object.keys(schema.schema).length) {
Expand Down

0 comments on commit 0b760c3

Please sign in to comment.