soap-graphql
Version:
Create a GraphQL schema from a WSDL-defined SOAP endpoint.
392 lines • 17.5 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [0, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var name_resolver_1 = require("./name-resolver");
var custom_type_resolver_1 = require("./custom-type-resolver");
var scalars_1 = require("graphql/type/scalars");
var util_1 = require("util");
var graphql_1 = require("graphql");
var SchemaResolver = /** @class */ (function () {
function SchemaResolver(soapEndpoint, soapCaller, options, logger) {
this.soapEndpoint = soapEndpoint;
this.soapCaller = soapCaller;
this.logger = logger;
this.outputResolver = null;
this.inputResolver = null;
this.options = this.defaultOptions(options);
}
SchemaResolver.prototype.defaultOptions = function (options) {
options = !options ? {} : Object.assign({}, options);
if (!options.outputNameResolver) {
options.outputNameResolver = name_resolver_1.defaultOutputNameResolver;
}
if (!options.interfaceNameResolver) {
options.interfaceNameResolver = name_resolver_1.defaultInterfaceNameResolver;
}
if (!options.inputNameResolver) {
options.inputNameResolver = name_resolver_1.defaultInputNameResolver;
}
if (!options.customResolver) {
options.customResolver = new custom_type_resolver_1.DefaultTypeResolver();
}
return options;
};
SchemaResolver.prototype.resolve = function () {
this.outputResolver = new GraphqlOutputFieldResolver(this.options, this.logger);
this.inputResolver = new GraphqlInputFieldResolver(this.options, this.logger);
return {
query: this.createQueryObject(),
mutation: this.createMutationObject(),
};
};
SchemaResolver.prototype.createQueryObject = function () {
var _this = this;
return new graphql_1.GraphQLObjectType({
name: 'Query',
fields: {
'description': {
type: scalars_1.GraphQLString,
resolve: function () {
return _this.soapEndpoint.description();
}
}
}
});
};
SchemaResolver.prototype.createMutationObject = function () {
var _this = this;
var fieldsThunk = function () {
var fields = {};
_this.soapEndpoint.services().forEach(function (service) {
if (!!_this.options.includeServices) {
fields[service.name()] = _this.createSoapServiceField(service);
}
else if (!!_this.options.includePorts) {
service.ports().forEach(function (port) {
fields[port.name()] = _this.createSoapPortField(service, port);
});
}
else {
service.ports().forEach(function (port) {
port.operations().forEach(function (operation) {
fields[operation.name()] = _this.createSoapOperationField(operation);
});
});
}
});
return fields;
};
return new graphql_1.GraphQLObjectType({
name: 'Mutation',
fields: fieldsThunk,
});
};
SchemaResolver.prototype.createSoapServiceField = function (service) {
var _this = this;
var fieldsThunk = function () {
var fields = {};
service.ports().forEach(function (port) {
if (!!_this.options.includePorts) {
fields[port.name()] = _this.createSoapPortField(service, port);
}
else {
port.operations().forEach(function (operation) {
fields[operation.name()] = _this.createSoapOperationField(operation);
});
}
});
return fields;
};
var returnType = new graphql_1.GraphQLObjectType({
name: service.name() + 'Service',
description: "Service " + service.name(),
fields: fieldsThunk,
});
return {
type: returnType,
description: "Service " + service.name(),
resolve: function () { return {}; }
};
};
SchemaResolver.prototype.createSoapPortField = function (service, port) {
var _this = this;
var fieldsThunk = function () {
var fields = {};
port.operations().forEach(function (operation) {
fields[operation.name()] = _this.createSoapOperationField(operation);
});
return fields;
};
var returnType = new graphql_1.GraphQLObjectType({
name: port.name() + 'Port',
description: "Port " + port.name() + ", service " + service.name(),
fields: fieldsThunk,
});
return {
type: returnType,
description: "Port " + port.name() + ", service " + service.name(),
resolve: function () { return {}; }
};
};
SchemaResolver.prototype.createSoapOperationField = function (operation) {
var args = this.createSoapOperationFieldArgs(operation);
var returnType = this.resolveSoapOperationReturnType(operation);
var resolver = this.createSoapOperationFieldResolver(operation);
return {
type: returnType,
description: "Operation " + operation.name() + ", port " + operation.port().name() + ", service " + operation.service().name(),
args: args,
resolve: resolver
};
};
SchemaResolver.prototype.createSoapOperationFieldArgs = function (operation) {
var _this = this;
var args = {};
operation.args().forEach(function (soapField) {
args[soapField.name] = {
type: _this.inputResolver.resolve(soapField),
};
});
return args;
};
SchemaResolver.prototype.resolveSoapOperationReturnType = function (operation) {
return this.outputResolver.resolve(operation.output());
};
SchemaResolver.prototype.createSoapOperationFieldResolver = function (operation) {
var _this = this;
return function (graphqlSource, graphqlArgs, graphqlContext, graphqlInfo) { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.soapCaller.call({
operation: operation,
graphqlSource: graphqlSource,
graphqlArgs: graphqlArgs,
graphqlContext: graphqlContext,
graphqlInfo: graphqlInfo,
})];
case 1: return [2 /*return*/, _a.sent()];
}
});
}); };
};
return SchemaResolver;
}());
exports.SchemaResolver = SchemaResolver;
var GraphqlOutputFieldResolver = /** @class */ (function () {
function GraphqlOutputFieldResolver(options, logger) {
this.options = options;
this.logger = logger;
this.alreadyResolvedOutputTypes = new Map();
this.alreadyResolvedInterfaceTypes = new Map();
}
GraphqlOutputFieldResolver.prototype.resolve = function (input) {
try {
var type = this.resolveOutputType(input.type);
return input.isList ? new graphql_1.GraphQLList(type) : type;
}
catch (err) {
var errStacked = new Error("could not resolve output type for " + util_1.inspect(input, false, 4));
errStacked.stack += '\nCaused by: ' + err.stack;
throw errStacked;
}
};
GraphqlOutputFieldResolver.prototype.resolveOutputType = function (soapType) {
if (this.alreadyResolvedOutputTypes.has(soapType)) {
return this.alreadyResolvedOutputTypes.get(soapType);
}
if (typeof soapType === 'string') {
var customType = this.options.customResolver.outputType(soapType);
if (!!customType) {
this.alreadyResolvedOutputTypes.set(soapType, customType);
return customType;
}
}
else {
var objectType = this.createObjectType(soapType);
if (!!objectType) {
this.alreadyResolvedOutputTypes.set(soapType, objectType);
return objectType;
}
}
this.logger.warn(function () { return "could not resolve output type '" + soapType + "'; using GraphQLString instead"; });
this.alreadyResolvedOutputTypes.set(soapType, scalars_1.GraphQLString);
return scalars_1.GraphQLString;
};
GraphqlOutputFieldResolver.prototype.createObjectType = function (soapType) {
return new graphql_1.GraphQLObjectType(this.createObjectTypeConfig(soapType));
};
GraphqlOutputFieldResolver.prototype.createObjectTypeConfig = function (soapType) {
var _this = this;
var fields = function () {
var fieldMap = {};
_this.appendObjectTypeFields(fieldMap, soapType);
return fieldMap;
};
var interfaces = function () {
var interfaces = [];
_this.appendInterfaces(interfaces, soapType);
return interfaces;
};
return {
name: this.options.outputNameResolver(soapType),
fields: fields,
interfaces: interfaces,
};
};
GraphqlOutputFieldResolver.prototype.appendObjectTypeFields = function (fieldMap, soapType) {
var _this = this;
soapType.fields.forEach(function (soapField) {
fieldMap[soapField.name] = {
type: _this.resolve(soapField),
};
});
if (!!soapType.base) {
this.appendObjectTypeFields(fieldMap, soapType.base);
}
};
GraphqlOutputFieldResolver.prototype.appendInterfaces = function (interfaces, soapType) {
if (!!soapType.base) {
interfaces.push(this.resolveInterfaceType(soapType.base));
this.appendInterfaces(interfaces, soapType.base);
}
};
GraphqlOutputFieldResolver.prototype.resolveInterfaceType = function (soapType) {
if (this.alreadyResolvedInterfaceTypes.has(soapType)) {
return this.alreadyResolvedInterfaceTypes.get(soapType);
}
var interfaceType = this.createInterfaceType(soapType);
this.alreadyResolvedInterfaceTypes.set(soapType, interfaceType);
return interfaceType;
};
GraphqlOutputFieldResolver.prototype.createInterfaceType = function (soapType) {
return new graphql_1.GraphQLInterfaceType(this.createInterfaceTypeConfig(soapType));
};
GraphqlOutputFieldResolver.prototype.createInterfaceTypeConfig = function (soapType) {
var _this = this;
var fields = function () {
var fieldMap = {};
_this.appendInterfaceTypeFields(fieldMap, soapType);
return fieldMap;
};
return {
name: this.options.interfaceNameResolver(soapType),
fields: fields,
// should never be called, since the schema will not contain ambigous return types
resolveType: function (value, context, info) { throw Error('no interface resolving available'); },
};
};
GraphqlOutputFieldResolver.prototype.appendInterfaceTypeFields = function (fieldMap, soapType) {
var _this = this;
soapType.fields.forEach(function (soapField) {
fieldMap[soapField.name] = {
type: _this.resolve(soapField),
};
});
if (!!soapType.base) {
this.appendObjectTypeFields(fieldMap, soapType.base);
}
};
return GraphqlOutputFieldResolver;
}());
var GraphqlInputFieldResolver = /** @class */ (function () {
function GraphqlInputFieldResolver(options, logger) {
this.options = options;
this.logger = logger;
this.alreadyResolved = new Map();
}
GraphqlInputFieldResolver.prototype.resolve = function (input) {
try {
var type = this.resolveInputType(input.type);
return input.isList ? new graphql_1.GraphQLList(type) : type;
}
catch (err) {
var errStacked = new Error("could not resolve output type for " + util_1.inspect(input, false, 4));
errStacked.stack += '\nCaused by: ' + err.stack;
throw errStacked;
}
};
GraphqlInputFieldResolver.prototype.resolveInputType = function (soapType) {
if (this.alreadyResolved.has(soapType)) {
return this.alreadyResolved.get(soapType);
}
if (typeof soapType === 'string') {
var customType = this.options.customResolver.inputType(soapType);
if (!!customType) {
this.alreadyResolved.set(soapType, customType);
return customType;
}
}
else {
var objectType = this.createObjectType(soapType);
if (!!objectType) {
this.alreadyResolved.set(soapType, objectType);
return objectType;
}
}
this.logger.warn(function () { return "could not resolve input type '" + soapType + "'; using GraphQLString"; });
this.alreadyResolved.set(soapType, scalars_1.GraphQLString);
return scalars_1.GraphQLString;
};
GraphqlInputFieldResolver.prototype.createObjectType = function (soapType) {
return new graphql_1.GraphQLInputObjectType(this.createObjectTypeConfig(soapType));
};
GraphqlInputFieldResolver.prototype.createObjectTypeConfig = function (soapType) {
var _this = this;
var fields = function () {
var fieldMap = {};
_this.appendObjectTypeFields(fieldMap, soapType);
return fieldMap;
};
return {
name: this.options.inputNameResolver(soapType),
fields: fields,
};
};
GraphqlInputFieldResolver.prototype.appendObjectTypeFields = function (fieldMap, soapType) {
var _this = this;
soapType.fields.forEach(function (soapField) {
fieldMap[soapField.name] = {
type: _this.resolve(soapField),
};
});
if (!!soapType.base) {
this.appendObjectTypeFields(fieldMap, soapType.base);
}
};
return GraphqlInputFieldResolver;
}());
//# sourceMappingURL=schema-resolver.js.map