UNPKG

@omnigraph/raml

Version:

This package generates `GraphQLSchema` instance from **RAML API Document** (`.raml`) file located at a URL or FileSystem by resolving the JSON Schema dependencies. It uses `@omnigraph/json-schema` by generating the necessary configuration.

229 lines (228 loc) • 10.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getJSONSchemaOptionsFromRAMLOptions = getJSONSchemaOptionsFromRAMLOptions; const tslib_1 = require("tslib"); const json_machete_1 = require("json-machete"); const to_json_schema_1 = tslib_1.__importDefault(require("to-json-schema")); const raml_1_parser_1 = require("@ardatan/raml-1-parser"); const cross_helpers_1 = require("@graphql-mesh/cross-helpers"); const string_interpolation_1 = require("@graphql-mesh/string-interpolation"); const utils_1 = require("@graphql-mesh/utils"); const utils_2 = require("@graphql-tools/utils"); const fetch_1 = require("@whatwg-node/fetch"); const utils_js_1 = require("./utils.js"); function resolveTraitsByIs(base) { const allTraits = []; for (const traitRef of base.is()) { const traitNode = traitRef.trait(); if (traitNode) { allTraits.push(traitNode); allTraits.push(...resolveTraitsByIs(traitNode)); } } return allTraits; } /** * Generates the options for JSON Schema Loader * from RAML Loader options by extracting the JSON Schema references * from RAML API Document */ async function getJSONSchemaOptionsFromRAMLOptions({ source, cwd: ramlFileCwd = cross_helpers_1.process.cwd(), operations: extraOperations, endpoint: forcedBaseUrl, fetch = fetch_1.fetch, schemaHeaders = {}, selectQueryOrMutationField = [], }) { const fieldTypeMap = {}; for (const { fieldName, type } of selectQueryOrMutationField) { fieldTypeMap[fieldName] = type; } const operations = extraOperations || []; const ramlAbsolutePath = (0, json_machete_1.getAbsolutePath)(source, ramlFileCwd); const schemaHeadersFactory = (0, string_interpolation_1.getInterpolatedHeadersFactory)(schemaHeaders); const ramlAPI = (await (0, raml_1_parser_1.loadApi)(ramlAbsolutePath, [], { httpResolver: { getResourceAsync: async (url) => { const fetchResponse = await fetch(url, { headers: schemaHeadersFactory({ env: cross_helpers_1.process.env }), }); const content = await fetchResponse.text(); if (fetchResponse.status !== 200) { return { errorMessage: content, }; } return { content, }; }, getResource: () => { throw new Error(`Sync fetching not available for URLs`); }, }, })); let endpoint = forcedBaseUrl; if (!endpoint) { endpoint = ramlAPI.baseUri().value(); for (const endpointParamNode of ramlAPI.baseUriParameters()) { const paramName = endpointParamNode.name(); endpoint = endpoint.split(`{${paramName}}`).join(`{context.${paramName}}`); } } const pathTypeMap = new Map(); const typePathMap = new Map(); for (const typeNode of ramlAPI.types()) { const typeNodeJson = typeNode.toJSON(); for (const typeName in typeNodeJson) { const { schemaPath } = typeNodeJson[typeName]; if (schemaPath) { pathTypeMap.set(schemaPath, typeName); typePathMap.set(typeName, schemaPath); } } } const cwd = (0, json_machete_1.getCwd)(ramlAbsolutePath); const apiQueryParameters = []; const apiBodyNodes = []; const apiResponses = []; for (const traitNode of ramlAPI.traits()) { apiQueryParameters.push(...traitNode.queryParameters()); apiBodyNodes.push(...traitNode.body()); apiResponses.push(...traitNode.responses()); const nestedTraits = resolveTraitsByIs(traitNode); for (const nestedTrait of nestedTraits) { apiQueryParameters.push(...nestedTrait.queryParameters()); apiBodyNodes.push(...nestedTrait.body()); apiResponses.push(...nestedTrait.responses()); } } for (const resourceNode of ramlAPI.allResources()) { const resourceQueryParameters = [...apiQueryParameters]; const resourceBodyNodes = [...apiBodyNodes]; const resourceResponses = [...apiResponses]; const resourceTraits = resolveTraitsByIs(resourceNode); for (const traitNode of resourceTraits) { apiQueryParameters.push(...traitNode.queryParameters()); apiBodyNodes.push(...traitNode.body()); apiResponses.push(...traitNode.responses()); } for (const methodNode of resourceNode.methods()) { const queryParameters = [...resourceQueryParameters]; const bodyNodes = [...resourceBodyNodes]; const responses = [...resourceResponses]; const traits = resolveTraitsByIs(methodNode); for (const traitNode of traits) { queryParameters.push(...traitNode.queryParameters()); bodyNodes.push(...traitNode.body()); responses.push(...traitNode.responses()); } queryParameters.push(...methodNode.queryParameters()); bodyNodes.push(...methodNode.body()); responses.push(...methodNode.responses()); let requestSchema; let requestTypeName; const responseByStatusCode = {}; const method = methodNode.method().toUpperCase(); let fieldName = methodNode.displayName()?.replace('GET_', ''); const description = methodNode.description()?.value() || resourceNode.description()?.value(); const originalFullRelativeUrl = resourceNode.completeRelativeUri(); let fullRelativeUrl = originalFullRelativeUrl; const argTypeMap = {}; const queryParamArgMap = {}; for (const uriParameterNode of resourceNode.uriParameters()) { const paramName = uriParameterNode.name(); const argName = (0, utils_1.sanitizeNameForGraphQL)(paramName); fullRelativeUrl = fullRelativeUrl.replace(`{${paramName}}`, `{args.${argName}}`); const uriParameterNodeJson = uriParameterNode.toJSON(); if (uriParameterNodeJson.displayName) { uriParameterNodeJson.title = uriParameterNodeJson.displayName; } argTypeMap[argName] = uriParameterNodeJson; } for (const queryParameterNode of queryParameters) { const parameterName = queryParameterNode.name(); const argName = (0, utils_1.sanitizeNameForGraphQL)(parameterName); const queryParameterNodeJson = queryParameterNode.toJSON(); if (queryParameterNodeJson.displayName) { queryParameterNodeJson.title = queryParameterNodeJson.displayName; } queryParamArgMap[parameterName] = argName; argTypeMap[argName] = queryParameterNodeJson; } for (const bodyNode of bodyNodes) { if (bodyNode.name().includes('application/json')) { const bodyJson = bodyNode.toJSON(); if (bodyJson.schemaPath) { const schemaPath = bodyJson.schemaPath; requestSchema = schemaPath; requestTypeName = pathTypeMap.get(schemaPath); } else if (bodyJson.type) { const typeName = (0, utils_2.asArray)(bodyJson.type)[0]; requestTypeName = typeName; const schemaPath = typePathMap.get(typeName); requestSchema = schemaPath; } } } for (const responseNode of responses) { const statusCode = responseNode.code().value(); const responseNodeDescription = responseNode.description()?.value(); for (const bodyNode of responseNode.body()) { if (bodyNode.name().includes('application/json')) { const bodyJson = bodyNode.toJSON(); if (bodyJson.schemaPath) { const schemaPath = bodyJson.schemaPath; const typeName = pathTypeMap.get(schemaPath); if (schemaPath) { responseByStatusCode[statusCode] = { responseSchema: schemaPath, responseTypeName: typeName, }; } } else if (bodyJson.type) { const typeName = (0, utils_2.asArray)(bodyJson.type)[0]; const schemaPath = typePathMap.get(typeName); if (schemaPath) { responseByStatusCode[statusCode] = { responseSchema: schemaPath, responseTypeName: typeName, }; } } if (!responseByStatusCode[statusCode] && bodyJson.example) { const responseSchema = (0, to_json_schema_1.default)(bodyJson.example, { required: false, }); responseSchema.description = responseNodeDescription; responseByStatusCode[statusCode] = { responseSchema, }; } } } } fieldName = fieldName || (0, utils_js_1.getFieldNameFromPath)(originalFullRelativeUrl, method, responseByStatusCode['200']?.responseTypeName); if (fieldName) { const graphQLFieldName = (0, utils_1.sanitizeNameForGraphQL)(fieldName); const operationType = (fieldTypeMap[graphQLFieldName] ?? method === 'GET') ? 'query' : 'mutation'; operations.push({ type: operationType, field: graphQLFieldName, description, path: fullRelativeUrl, method, requestSchema, requestTypeName, responseByStatusCode, queryParamArgMap, argTypeMap, }); } } } return { operations, endpoint, cwd, fetch, }; }