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

Add the ability to remove the bits of JSON Schema that Swagger doesn't support #7

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ Options:

-r, --dereference Fully dereference all $ref pointers

-j, --swagger-json-schema Remove any JSON Schema pieces not supported by Swagger's implementation of JSON Schema

-f, --format <spaces> Formats the JSON output using the given number of spaces
(the default is 2 spaces)
```
Expand Down
1 change: 1 addition & 0 deletions bin/swagger.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ program.command('validate <filename>')
program.command('bundle <filename>')
.description('Bundles a multi-file Swagger API into a single file')
.option('-o, --outfile <filename>', 'The output file')
.option('-j, --swagger-json-schema', 'Remove any JSON Schema pieces that aren\'t supported by Swagger')
.option('-r, --dereference', 'Fully dereference all $ref pointers')
.option('-f, --format <spaces>', 'Formats the JSON output using the given number of spaces (default is 2)')
.action(function(filename, options) {
Expand Down
52 changes: 52 additions & 0 deletions lib/bundle.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

var fs = require('fs');
var jsonPath = require('jsonpath-plus');

/**
* Bundles the given Swagger API
Expand Down Expand Up @@ -28,6 +29,11 @@ module.exports = function bundle(api, options, cb) {

return SwaggerParser[method](api, opts)
.then(function(api) {
// Remove JSON Schema pieces that Swagger trips over
if (options.swaggerJsonSchema) {
deJsonSchemafy(api);
}

// Serialize the bundled/dereferenced API as JSON
var json = toJSON(api, options.format);

Expand All @@ -45,6 +51,52 @@ module.exports = function bundle(api, options, cb) {
});
};

/**
* Looks in the Swagger JSON object for JSON Schema keywords that aren't
* supported by Swagger's subset of JSON Schema
*
* @param {object} api - The Swagger object
*/
function deJsonSchemafy(api) {
jsonPath({json: api, path: '$.paths[*][*].responses[*].schema', callback: removeJsonSchemaParts});
jsonPath({json: api, path: '$.paths[*][*].parameters[*].schema', callback: removeJsonSchemaParts});
jsonPath({json: api, path: '$.paths[*].parameters[*].schema', callback: removeJsonSchemaParts});
jsonPath({json: api, path: '$.definitions[*].schema', callback: removeJsonSchemaParts});
jsonPath({json: api, path: '$.parameters[*].schema', callback: removeJsonSchemaParts});
}

/**
* Modifies the given JSON Schema object to remove any pieces that Swagger
* doesn't support
*
* @param {object} schemaObj - A JSON Schema object
*/
function removeJsonSchemaParts(schemaObj) {
delete schemaObj.$schema;
delete schemaObj.id;

//If this type is an array, then we have to delete the required object.
//We'll be deleting any related ids that could identify the related objects
if (schemaObj.type === 'array') {
delete schemaObj.required;
}

//Swagger only supports additionalProperties as an object
if (typeof schemaObj.additionalProperties !== 'object') {
delete schemaObj.additionalProperties;
} else {
jsonPath({json: schemaObj, path: '$.additionalProperties', callback: removeJsonSchemaParts});
}

jsonPath({json: schemaObj, path: '$.properties.*', callback: removeJsonSchemaParts});

if (Array.isArray(schemaObj.items)) {
jsonPath({json: schemaObj, path: '$.items[*]', callback: removeJsonSchemaParts});
} else {
jsonPath({json: schemaObj, path: '$.items', callback: removeJsonSchemaParts});
}
}

/**
* Serializes the given API as JSON, using the given spaces for formatting.
*
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"chalk": "^1.1.1",
"commander": "^2.8.1",
"es6-promise": "^3.0.2",
"jsonpath-plus": "0.15.0",
"lodash": "^3.10.1",
"swagger-parser": "^3.1.0",
"swagger-server": "^1.0.0-alpha.18"
Expand All @@ -70,4 +71,4 @@
"bin": {
"swagger": "bin/swagger.js"
}
}
}
40 changes: 40 additions & 0 deletions tests/files/definitions/definitions-with-schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"additionalProperties": false,
"properties": {
"firstName": {
"id": "http://fake-swagger-cli.com/definitions/name",
"type": "string",
"description": "This is the first, given, non-familial name"
},
"phoneNumber": {
"id": "http://fake-swagger-cli.com/definitions/phoneNumber",
"type": "array",
"items": {
"id": "http://fake-swagger-cli.com/definitions/phoneNumber/0",
"type": "object",
"properties": {
"areaCode": {
"id": "http://fake-swagger-cli.com/definitions/phoneNumber/0/areaCode",
"type": "string",
"description": "The 123 in '(123) 456-7890'"
},
"localNumber": {
"id": "http://fake-swagger-cli.com/definitions/phoneNumber/0/areaCode",
"type": "string",
"description": "The 456-7890 in '(123) 456-7890'"
}
},
"required": [
"areaCode",
"localNumber"
]
}
}
},
"required": [
"firstName",
"phoneNumber"
]
}
33 changes: 33 additions & 0 deletions tests/files/swagger-with-schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"swagger": "2.0",
"info": {
"version": "1.0.0",
"description": "This is an intentionally over-complicated API that returns a person's name",
"title": "Name API"
},
"paths": {
"/people/{name}": {
"parameters": [
{
"name": "name",
"in": "path",
"type": "string",
"required": true
}
],
"get": {
"responses": {
"200": {
"description": "Returns the requested name",
"schema": {
"$ref": "#/definitions/name"
}
}
}
}
}
},
"definitions": {
"$ref": "definitions/definitions-with-schema.json"
}
}
31 changes: 31 additions & 0 deletions tests/specs/swagger.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,37 @@ describe('swagger-cli commands', function() {
}
);

it('running the \'swagger bundle -j\' command removes json schema parts that swagger can\'t handle', function() {
//remove potential leftover testfile from previous failed test
if (fs.existsSync('tests/swaggerSample/test.json')) {
fs.unlinkSync('tests/swaggerSample/test.json');
}

//Bundle the file while specifying -j to remove json-schema parts
var returnBuf = execSync('swagger bundle -j -o tests/swaggerSample/test.json tests/swaggerSample/swagger-with-schema.json');
var outputArray = returnBuf.toString().split('\n');
outputArray = _.dropRight(outputArray);

//Command should run successfully
expect(outputArray).to.deep.equal([
'Bundling file: tests/swaggerSample/swagger.yaml',
'File parsed successfully',
'Writing parsed data to file tests/swaggerSample/test.json',
'Parsed data successfully written to file'
]);

//Now validate the resulting file to ensure the troublesome json-schema parts don't result in errors
var returnBuffer = execSync(swaggerCmd + ' validate tests/swaggerSample/test.json');
var outputArray = returnBuffer.toString().split('\n');

outputArray = _.dropRight(outputArray);

expect(outputArray).to.deep.equal([
'Validating file: tests/swaggerSample/test.yaml',
'File validated successfully'
]);
});

it('running the \'swagger bundle\' command on an invalid swagger file produces the expected error', function() {
var errorMessageArray = [];
try {
Expand Down