From ceeb4675ad20b9c23e4eced40801fd75301a13d5 Mon Sep 17 00:00:00 2001 From: Liam Connolly Date: Wed, 20 Dec 2017 11:19:01 +0000 Subject: [PATCH] Adding in allOf functionality --- README.md | 11 ++++++----- lib/swagger.js | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/typeMap.js | 16 ++++++++++++--- package.json | 15 +++++++++----- 4 files changed, 82 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 8abee84..5f630be 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Swagger2GraphQL +# Swagger2graphQL -Swagger2GraphQL converts your existing Swagger schema to GraphQL types where resolvers perform HTTP calls to certain real endpoints. +Swagger2graphQL converts your existing Swagger schema to GraphQL types where resolvers perform HTTP calls to certain real endpoints. It allows you to move your API to GraphQL with nearly zero afford and maintain both: REST and GraphQL APIs. Why? @@ -12,8 +12,9 @@ It allows you to move your API to GraphQL with nearly zero afford and maintain b ```js const express = require('express'); const app = express(); -const graphqlHTTP = require('express-graphql'); -const graphQLSchema = require('swagger-to-graphql'); +var graphqlHTTP = require('express-graphql'); +var graphql = require('graphql'); +var graphQLSchema = require('swagger-to-graphql'); graphQLSchema('./petstore.json').then(schema => { app.use('/graphql', graphqlHTTP(() => { @@ -51,4 +52,4 @@ swagger-to-graphql --swagger=/path/to/swagger_schema.json > ./types.graphql ... ``` - All context options + All context options \ No newline at end of file diff --git a/lib/swagger.js b/lib/swagger.js index b7a3a20..3a0718d 100644 --- a/lib/swagger.js +++ b/lib/swagger.js @@ -39,12 +39,49 @@ var getSuccessResponse = function getSuccessResponse(responses) { (0, _keys2.default)(responses).some(function (code) { resp = responses[code]; + return code[0] === '2'; }); + // If there is an allOf reference, flatten its properties and the + // additional properties into a single respone. + if (resp.schema && resp.schema.allOf) { + return flattenAllOfProperties(resp.schema); + } + + // If it's an array of a definition that uses an allOf, change the items + // to be the flattened definition. + else if (resp.schema && resp.schema.items && resp.schema.items.allOf) { + return { + items: flattenAllOfProperties(resp.schema.items), + type: 'array' + }; + } + return resp && resp.schema; }; +var flattenAllOfProperties = function flattenAllOfProperties(schemaDefinition) { + let parentSchema = JSON.parse(JSON.stringify(schemaDefinition.allOf[0])); + let additionalSchema = schemaDefinition.allOf[1] || {}; + let finalSchema = parentSchema; + for (const key in additionalSchema) { + // If it's an object, we need to merge in all properties. + if (additionalSchema[key] === Object(additionalSchema[key])) { + for (const propertyKey in additionalSchema[key]) { + finalSchema[key][propertyKey] = additionalSchema[key][propertyKey]; + } + } + // If it's not, just add it on. E.g. the 'type' property is a string. + else { + finalSchema[key] = additionalSchema[key]; + } + } + // Return this flattened response (instead of the standard one, which would + // contain the allOf elements). + return finalSchema; +} + var loadSchema = exports.loadSchema = function loadSchema(pathToSchema) { var schema = _jsonSchemaRefParser2.default.dereference(pathToSchema); __schema = schema; @@ -55,6 +92,22 @@ var replaceOddChars = function replaceOddChars(str) { return str.replace(/[^_a-zA-Z0-9]/g, '_'); }; +var censor = function censor(censor) { + var i = 0; + + return function(key, value) { + if(i !== 0 && typeof(censor) === 'object' && typeof(value) == 'object' && censor == value) + return '[Circular]'; + + if(i >= 29) // seems to be a harded maximum of 30 serialized objects? + return '[Unknown]'; + + ++i; // so we know we aren't using the original object anymore + + return value; + } +} + /** * Going throw schema and grab routes */ diff --git a/lib/typeMap.js b/lib/typeMap.js index 14ecb17..7a944a0 100644 --- a/lib/typeMap.js +++ b/lib/typeMap.js @@ -38,7 +38,7 @@ var primitiveTypes = { }; var isObjectType = function isObjectType(jsonSchema) { - return jsonSchema.properties || jsonSchema.type === 'object' || jsonSchema.type === 'array' || jsonSchema.schema; + return jsonSchema.properties || jsonSchema.type === 'object' || jsonSchema.type === 'array' || jsonSchema.schema || jsonSchema.allOf; }; var getTypeNameFromRef = function getTypeNameFromRef(ref) { @@ -64,6 +64,7 @@ var getRefProp = function getRefProp(jsonSchema) { }; var createGQLObject = exports.createGQLObject = function createGQLObject(jsonSchema, title, isInputType) { + if (!jsonSchema) { jsonSchema = { // eslint-disable-line no-param-reassign type: 'object', @@ -74,7 +75,7 @@ var createGQLObject = exports.createGQLObject = function createGQLObject(jsonSch } var reference = getRefProp(jsonSchema); - + if (reference) { return getExistingType(reference, isInputType); } @@ -104,7 +105,13 @@ var createGQLObject = exports.createGQLObject = function createGQLObject(jsonSch }; var getTypeFields = exports.getTypeFields = function getTypeFields(jsonSchema, title, isInputType) { - var fields = _lodash2.default.mapValues(jsonSchema.properties || {}, function (propertySchema, propertyName) { + let properties = {}; + + if (jsonSchema.properties) { + properties = jsonSchema.properties; + } + + var fields = _lodash2.default.mapValues(properties, function (propertySchema, propertyName) { return { description: propertySchema.description, type: jsonSchemaTypeToGraphQL(title, propertySchema, propertyName, isInputType) @@ -122,6 +129,9 @@ var getTypeFields = exports.getTypeFields = function getTypeFields(jsonSchema, t var jsonSchemaTypeToGraphQL = function jsonSchemaTypeToGraphQL(title, jsonSchema, schemaName, isInputType) { if (isObjectType(jsonSchema)) { + if (title.length > 40) { + throw new Error('got too far'); + } return createGQLObject(jsonSchema, title + '_' + schemaName, isInputType); } else if (jsonSchema.type) { return getPrimitiveTypes(jsonSchema); diff --git a/package.json b/package.json index 241d8cd..064487e 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,10 @@ { - "name": "swagger-to-graphql", - "version": "1.1.7", - "author": "Roman Krivtsov", - "bin": "./bin/swagger2graphql", + "author": { + "name": "Roman Krivtsov" + }, + "bin": { + "swagger-to-graphql": "./bin/swagger2graphql" + }, "dependencies": { "babel-runtime": "^6.25.0", "graphql": "^0.10.1", @@ -15,6 +17,7 @@ "request-promise": "^4.1.1", "yargs": "^8.0.2" }, + "description": "Swagger2graphQL converts your existing Swagger schema to GraphQL types where resolvers perform HTTP calls to certain real endpoints. It allows you to move your API to GraphQL with nearly zero afford and maintain both: REST and GraphQL APIs.", "devDependencies": { "babel-cli": "^6.24.1", "babel-core": "^6.24.1", @@ -39,11 +42,13 @@ ], "license": "MIT", "main": "lib/index.js", + "name": "swagger-to-graphql", "scripts": { "build": "babel src -d lib", "lint": "eslint src/", "prepublish": "npm run build", "start": "node example/app.js", "test": "mocha" - } + }, + "version": "1.1.7" }