@graphql-mesh/openapi 1.0.0-alpha-3fc47d119.0 → 1.0.0-alpha-20220804093904-8e2e41f7f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -10,6 +10,7 @@ const Swagger2OpenAPI = require('swagger2openapi');
10
10
  const JsonPointer = _interopDefault(require('json-pointer'));
11
11
  const pluralize = _interopDefault(require('pluralize'));
12
12
  const JSONPath = require('jsonpath-plus');
13
+ const qs = _interopDefault(require('qs'));
13
14
  const formurlencoded = _interopDefault(require('form-urlencoded'));
14
15
  const urlJoin = _interopDefault(require('url-join'));
15
16
  const fetch = require('@whatwg-node/fetch');
@@ -171,6 +172,7 @@ var HTTP_METHODS;
171
172
  HTTP_METHODS["head"] = "head";
172
173
  })(HTTP_METHODS || (HTTP_METHODS = {}));
173
174
  const SUCCESS_STATUS_RX = /2[0-9]{2}|2XX/;
175
+ const CONTENT_TYPE_JSON_RX = /^application\/(.*)json$/;
174
176
  /**
175
177
  * Given an HTTP method, convert it to the HTTP_METHODS enum
176
178
  */
@@ -492,7 +494,7 @@ function getRequestBodyObject(operation, oas) {
492
494
  const content = requestBodyObject.content;
493
495
  const contentTypes = Object.keys(content);
494
496
  const jsonContentType = (_a = contentTypes
495
- .find(contentType => contentType.toString().includes('application/json'))) === null || _a === void 0 ? void 0 : _a.toString();
497
+ .find(contentType => CONTENT_TYPE_JSON_RX.test(contentType.toString()))) === null || _a === void 0 ? void 0 : _a.toString();
496
498
  const formDataContentType = (_b = contentTypes
497
499
  .find(contentType => contentType.toString().includes('application/x-www-form-urlencoded'))) === null || _b === void 0 ? void 0 : _b.toString();
498
500
  // Prioritize content-type JSON
@@ -547,7 +549,7 @@ function getRequestSchemaAndNames(path, operation, oas) {
547
549
  * Instead, treat the request body as a black box and send it as a string
548
550
  * with the proper content-type header
549
551
  */
550
- if (!payloadContentType.includes('application/json') &&
552
+ if (!CONTENT_TYPE_JSON_RX.test(payloadContentType.toString()) &&
551
553
  !payloadContentType.includes('application/x-www-form-urlencoded') &&
552
554
  !payloadContentType.includes('*/*')) {
553
555
  const saneContentTypeName = uncapitalize(payloadContentType.split('/').reduce((name, term) => {
@@ -594,7 +596,7 @@ function getResponseObject(operation, statusCode, oas) {
594
596
  if (responseObject.content && typeof responseObject.content !== 'undefined') {
595
597
  const content = responseObject.content;
596
598
  const contentTypes = Object.keys(content);
597
- const isJsonContent = contentTypes.some(contentType => contentType.toString().includes('application/json'));
599
+ const isJsonContent = contentTypes.some(contentType => CONTENT_TYPE_JSON_RX.test(contentType.toString()));
598
600
  // Prioritize content-type JSON
599
601
  if (isJsonContent) {
600
602
  return {
@@ -631,9 +633,22 @@ function getResponseSchemaAndNames(path, method, operation, oas, data, options)
631
633
  const availableSimilarContentType = contentTypes.find(contentType => contentType.toString().includes(responseContentType));
632
634
  let responseSchema = responseObject.content[availableSimilarContentType || contentTypes[0]].schema;
633
635
  let fromRef;
634
- if ('$ref' in responseSchema) {
635
- fromRef = responseSchema.$ref.split('/').pop();
636
- responseSchema = resolveRef(responseSchema.$ref, oas);
636
+ if (responseSchema) {
637
+ if ('$ref' in responseSchema) {
638
+ fromRef = responseSchema.$ref.split('/').pop();
639
+ responseSchema = resolveRef(responseSchema.$ref, oas);
640
+ }
641
+ }
642
+ else if (options.allowUndefinedSchemaRefTags) {
643
+ options.logger.info(`${path}:${method.toUpperCase()}:${statusCode}`);
644
+ fromRef = 'Unknown';
645
+ responseSchema = {
646
+ description: `Placeholder for missing ${path}:${method.toUpperCase()}:${statusCode} schema ref`,
647
+ type: options.defaultUndefinedSchemaType || 'object',
648
+ };
649
+ }
650
+ else {
651
+ throw new Error(`${path}:${method.toUpperCase()}:${statusCode} has an undefined schema ref`);
637
652
  }
638
653
  const responseSchemaNames = {
639
654
  fromRef,
@@ -644,7 +659,7 @@ function getResponseSchemaAndNames(path, method, operation, oas, data, options)
644
659
  * Edge case: if response body content-type is not application/json, do not
645
660
  * parse.
646
661
  */
647
- if (!responseContentType.includes('application/json') && !responseContentType.includes('*/*')) {
662
+ if (!CONTENT_TYPE_JSON_RX.test(responseContentType.toString()) && !responseContentType.includes('*/*')) {
648
663
  let description = 'Placeholder to access non-application/json response bodies';
649
664
  if ('description' in responseSchema && typeof responseSchema.description === 'string') {
650
665
  description += `\n\nOriginal top level description: '${responseSchema.description}'`;
@@ -1298,17 +1313,8 @@ function getResolver(getResolverParams, logger) {
1298
1313
  headers,
1299
1314
  };
1300
1315
  }
1301
- for (const paramName in query) {
1302
- const val = query[paramName];
1303
- if (Array.isArray(val)) {
1304
- for (let index = 0; index < val.length; index++) {
1305
- urlObject.searchParams.append(paramName, val[index]);
1306
- }
1307
- }
1308
- else if (val !== undefined) {
1309
- urlObject.searchParams.set(paramName, val);
1310
- }
1311
- }
1316
+ const allQueryParams = {};
1317
+ Object.assign(allQueryParams, query);
1312
1318
  /**
1313
1319
  * Determine possible payload
1314
1320
  *
@@ -1350,21 +1356,11 @@ function getResolver(getResolverParams, logger) {
1350
1356
  }
1351
1357
  // Query string:
1352
1358
  if (typeof data.options.qs === 'object') {
1353
- for (const query in data.options.qs) {
1354
- const val = data.options.qs[query];
1355
- if (val) {
1356
- urlObject.searchParams.set(query, val);
1357
- }
1358
- }
1359
+ Object.assign(allQueryParams, data.options.qs);
1359
1360
  }
1360
1361
  }
1361
1362
  if (typeof customQs === 'object') {
1362
- for (const query in customQs) {
1363
- const val = customQs[query];
1364
- if (val) {
1365
- urlObject.searchParams.set(query, val);
1366
- }
1367
- }
1363
+ Object.assign(allQueryParams, customQs);
1368
1364
  }
1369
1365
  // Get authentication headers and query parameters
1370
1366
  if (root && typeof root === 'object' && typeof root._openAPIToGraphQL === 'object') {
@@ -1376,12 +1372,7 @@ function getResolver(getResolverParams, logger) {
1376
1372
  options.headers[headerName] = headerValue;
1377
1373
  }
1378
1374
  }
1379
- for (const query in authQs) {
1380
- const val = authQs[query];
1381
- if (val) {
1382
- urlObject.searchParams.set(query, val);
1383
- }
1384
- }
1375
+ Object.assign(allQueryParams, authQs);
1385
1376
  // Add authentication cookie if created
1386
1377
  if (authCookie !== null) {
1387
1378
  const cookieHeaderName = 'cookie';
@@ -1391,12 +1382,7 @@ function getResolver(getResolverParams, logger) {
1391
1382
  // Extract OAuth token from context (if available)
1392
1383
  if (data.options.sendOAuthTokenInQuery) {
1393
1384
  const oauthQueryObj = createOAuthQS(data, ctx, logger);
1394
- for (const query in oauthQueryObj) {
1395
- const val = oauthQueryObj[query];
1396
- if (val) {
1397
- urlObject.searchParams.set(query, val);
1398
- }
1399
- }
1385
+ Object.assign(allQueryParams, oauthQueryObj);
1400
1386
  }
1401
1387
  else {
1402
1388
  const oauthHeader = createOAuthHeader(data, ctx, logger);
@@ -1407,6 +1393,7 @@ function getResolver(getResolverParams, logger) {
1407
1393
  }
1408
1394
  }
1409
1395
  }
1396
+ urlObject.search = qs.stringify(allQueryParams);
1410
1397
  const urlWithoutQuery = urlObject.href.replace(urlObject.search, '');
1411
1398
  resolveData.url = urlWithoutQuery;
1412
1399
  resolveData.usedRequestOptions = Object.assign({}, options);
@@ -3961,7 +3948,7 @@ function getArgs({ requestPayloadDef, parameters, operation, data, includeHttpDe
3961
3948
  }
3962
3949
  else if (typeof parameter.content === 'object') {
3963
3950
  const contentTypes = Object.keys(parameter.content);
3964
- const jsonContentType = contentTypes.find(contentType => contentType.toString().includes('application/json') || contentType.toString().includes('*/*'));
3951
+ const jsonContentType = contentTypes.find(contentType => CONTENT_TYPE_JSON_RX.test(contentType.toString()) || contentType.toString().includes('*/*'));
3965
3952
  if (jsonContentType &&
3966
3953
  typeof parameter.content[jsonContentType] === 'object' &&
3967
3954
  typeof parameter.content[jsonContentType].schema === 'object') {
@@ -5004,6 +4991,8 @@ class OpenAPIHandler {
5004
4991
  }
5005
4992
  return originalFactory(() => resolverParams, this.logger)(root, args, context, info);
5006
4993
  },
4994
+ allowUndefinedSchemaRefTags: this.config.allowUndefinedSchemaRefTags,
4995
+ defaultUndefinedSchemaType: this.config.defaultUndefinedSchemaType,
5007
4996
  });
5008
4997
  const { args, contextVariables } = stringInterpolation.parseInterpolationStrings(Object.values(operationHeaders || {}));
5009
4998
  const rootFields = [
package/index.mjs CHANGED
@@ -6,6 +6,7 @@ import { convertObj } from 'swagger2openapi';
6
6
  import JsonPointer from 'json-pointer';
7
7
  import pluralize from 'pluralize';
8
8
  import { JSONPath } from 'jsonpath-plus';
9
+ import qs from 'qs';
9
10
  import formurlencoded from 'form-urlencoded';
10
11
  import urlJoin from 'url-join';
11
12
  import { Headers } from '@whatwg-node/fetch';
@@ -167,6 +168,7 @@ var HTTP_METHODS;
167
168
  HTTP_METHODS["head"] = "head";
168
169
  })(HTTP_METHODS || (HTTP_METHODS = {}));
169
170
  const SUCCESS_STATUS_RX = /2[0-9]{2}|2XX/;
171
+ const CONTENT_TYPE_JSON_RX = /^application\/(.*)json$/;
170
172
  /**
171
173
  * Given an HTTP method, convert it to the HTTP_METHODS enum
172
174
  */
@@ -488,7 +490,7 @@ function getRequestBodyObject(operation, oas) {
488
490
  const content = requestBodyObject.content;
489
491
  const contentTypes = Object.keys(content);
490
492
  const jsonContentType = (_a = contentTypes
491
- .find(contentType => contentType.toString().includes('application/json'))) === null || _a === void 0 ? void 0 : _a.toString();
493
+ .find(contentType => CONTENT_TYPE_JSON_RX.test(contentType.toString()))) === null || _a === void 0 ? void 0 : _a.toString();
492
494
  const formDataContentType = (_b = contentTypes
493
495
  .find(contentType => contentType.toString().includes('application/x-www-form-urlencoded'))) === null || _b === void 0 ? void 0 : _b.toString();
494
496
  // Prioritize content-type JSON
@@ -543,7 +545,7 @@ function getRequestSchemaAndNames(path, operation, oas) {
543
545
  * Instead, treat the request body as a black box and send it as a string
544
546
  * with the proper content-type header
545
547
  */
546
- if (!payloadContentType.includes('application/json') &&
548
+ if (!CONTENT_TYPE_JSON_RX.test(payloadContentType.toString()) &&
547
549
  !payloadContentType.includes('application/x-www-form-urlencoded') &&
548
550
  !payloadContentType.includes('*/*')) {
549
551
  const saneContentTypeName = uncapitalize(payloadContentType.split('/').reduce((name, term) => {
@@ -590,7 +592,7 @@ function getResponseObject(operation, statusCode, oas) {
590
592
  if (responseObject.content && typeof responseObject.content !== 'undefined') {
591
593
  const content = responseObject.content;
592
594
  const contentTypes = Object.keys(content);
593
- const isJsonContent = contentTypes.some(contentType => contentType.toString().includes('application/json'));
595
+ const isJsonContent = contentTypes.some(contentType => CONTENT_TYPE_JSON_RX.test(contentType.toString()));
594
596
  // Prioritize content-type JSON
595
597
  if (isJsonContent) {
596
598
  return {
@@ -627,9 +629,22 @@ function getResponseSchemaAndNames(path, method, operation, oas, data, options)
627
629
  const availableSimilarContentType = contentTypes.find(contentType => contentType.toString().includes(responseContentType));
628
630
  let responseSchema = responseObject.content[availableSimilarContentType || contentTypes[0]].schema;
629
631
  let fromRef;
630
- if ('$ref' in responseSchema) {
631
- fromRef = responseSchema.$ref.split('/').pop();
632
- responseSchema = resolveRef(responseSchema.$ref, oas);
632
+ if (responseSchema) {
633
+ if ('$ref' in responseSchema) {
634
+ fromRef = responseSchema.$ref.split('/').pop();
635
+ responseSchema = resolveRef(responseSchema.$ref, oas);
636
+ }
637
+ }
638
+ else if (options.allowUndefinedSchemaRefTags) {
639
+ options.logger.info(`${path}:${method.toUpperCase()}:${statusCode}`);
640
+ fromRef = 'Unknown';
641
+ responseSchema = {
642
+ description: `Placeholder for missing ${path}:${method.toUpperCase()}:${statusCode} schema ref`,
643
+ type: options.defaultUndefinedSchemaType || 'object',
644
+ };
645
+ }
646
+ else {
647
+ throw new Error(`${path}:${method.toUpperCase()}:${statusCode} has an undefined schema ref`);
633
648
  }
634
649
  const responseSchemaNames = {
635
650
  fromRef,
@@ -640,7 +655,7 @@ function getResponseSchemaAndNames(path, method, operation, oas, data, options)
640
655
  * Edge case: if response body content-type is not application/json, do not
641
656
  * parse.
642
657
  */
643
- if (!responseContentType.includes('application/json') && !responseContentType.includes('*/*')) {
658
+ if (!CONTENT_TYPE_JSON_RX.test(responseContentType.toString()) && !responseContentType.includes('*/*')) {
644
659
  let description = 'Placeholder to access non-application/json response bodies';
645
660
  if ('description' in responseSchema && typeof responseSchema.description === 'string') {
646
661
  description += `\n\nOriginal top level description: '${responseSchema.description}'`;
@@ -1294,17 +1309,8 @@ function getResolver(getResolverParams, logger) {
1294
1309
  headers,
1295
1310
  };
1296
1311
  }
1297
- for (const paramName in query) {
1298
- const val = query[paramName];
1299
- if (Array.isArray(val)) {
1300
- for (let index = 0; index < val.length; index++) {
1301
- urlObject.searchParams.append(paramName, val[index]);
1302
- }
1303
- }
1304
- else if (val !== undefined) {
1305
- urlObject.searchParams.set(paramName, val);
1306
- }
1307
- }
1312
+ const allQueryParams = {};
1313
+ Object.assign(allQueryParams, query);
1308
1314
  /**
1309
1315
  * Determine possible payload
1310
1316
  *
@@ -1346,21 +1352,11 @@ function getResolver(getResolverParams, logger) {
1346
1352
  }
1347
1353
  // Query string:
1348
1354
  if (typeof data.options.qs === 'object') {
1349
- for (const query in data.options.qs) {
1350
- const val = data.options.qs[query];
1351
- if (val) {
1352
- urlObject.searchParams.set(query, val);
1353
- }
1354
- }
1355
+ Object.assign(allQueryParams, data.options.qs);
1355
1356
  }
1356
1357
  }
1357
1358
  if (typeof customQs === 'object') {
1358
- for (const query in customQs) {
1359
- const val = customQs[query];
1360
- if (val) {
1361
- urlObject.searchParams.set(query, val);
1362
- }
1363
- }
1359
+ Object.assign(allQueryParams, customQs);
1364
1360
  }
1365
1361
  // Get authentication headers and query parameters
1366
1362
  if (root && typeof root === 'object' && typeof root._openAPIToGraphQL === 'object') {
@@ -1372,12 +1368,7 @@ function getResolver(getResolverParams, logger) {
1372
1368
  options.headers[headerName] = headerValue;
1373
1369
  }
1374
1370
  }
1375
- for (const query in authQs) {
1376
- const val = authQs[query];
1377
- if (val) {
1378
- urlObject.searchParams.set(query, val);
1379
- }
1380
- }
1371
+ Object.assign(allQueryParams, authQs);
1381
1372
  // Add authentication cookie if created
1382
1373
  if (authCookie !== null) {
1383
1374
  const cookieHeaderName = 'cookie';
@@ -1387,12 +1378,7 @@ function getResolver(getResolverParams, logger) {
1387
1378
  // Extract OAuth token from context (if available)
1388
1379
  if (data.options.sendOAuthTokenInQuery) {
1389
1380
  const oauthQueryObj = createOAuthQS(data, ctx, logger);
1390
- for (const query in oauthQueryObj) {
1391
- const val = oauthQueryObj[query];
1392
- if (val) {
1393
- urlObject.searchParams.set(query, val);
1394
- }
1395
- }
1381
+ Object.assign(allQueryParams, oauthQueryObj);
1396
1382
  }
1397
1383
  else {
1398
1384
  const oauthHeader = createOAuthHeader(data, ctx, logger);
@@ -1403,6 +1389,7 @@ function getResolver(getResolverParams, logger) {
1403
1389
  }
1404
1390
  }
1405
1391
  }
1392
+ urlObject.search = qs.stringify(allQueryParams);
1406
1393
  const urlWithoutQuery = urlObject.href.replace(urlObject.search, '');
1407
1394
  resolveData.url = urlWithoutQuery;
1408
1395
  resolveData.usedRequestOptions = Object.assign({}, options);
@@ -3957,7 +3944,7 @@ function getArgs({ requestPayloadDef, parameters, operation, data, includeHttpDe
3957
3944
  }
3958
3945
  else if (typeof parameter.content === 'object') {
3959
3946
  const contentTypes = Object.keys(parameter.content);
3960
- const jsonContentType = contentTypes.find(contentType => contentType.toString().includes('application/json') || contentType.toString().includes('*/*'));
3947
+ const jsonContentType = contentTypes.find(contentType => CONTENT_TYPE_JSON_RX.test(contentType.toString()) || contentType.toString().includes('*/*'));
3961
3948
  if (jsonContentType &&
3962
3949
  typeof parameter.content[jsonContentType] === 'object' &&
3963
3950
  typeof parameter.content[jsonContentType].schema === 'object') {
@@ -5000,6 +4987,8 @@ class OpenAPIHandler {
5000
4987
  }
5001
4988
  return originalFactory(() => resolverParams, this.logger)(root, args, context, info);
5002
4989
  },
4990
+ allowUndefinedSchemaRefTags: this.config.allowUndefinedSchemaRefTags,
4991
+ defaultUndefinedSchemaType: this.config.defaultUndefinedSchemaType,
5003
4992
  });
5004
4993
  const { args, contextVariables } = parseInterpolationStrings(Object.values(operationHeaders || {}));
5005
4994
  const rootFields = [
@@ -39,6 +39,7 @@ export declare enum HTTP_METHODS {
39
39
  'head' = "head"
40
40
  }
41
41
  export declare const SUCCESS_STATUS_RX: RegExp;
42
+ export declare const CONTENT_TYPE_JSON_RX: RegExp;
42
43
  /**
43
44
  * Given an HTTP method, convert it to the HTTP_METHODS enum
44
45
  */
@@ -240,4 +240,12 @@ export declare type InternalOptions<TSource, TContext, TArgs> = {
240
240
  includeHttpDetails?: boolean;
241
241
  pubsub: MeshPubSub;
242
242
  logger: Logger;
243
+ /**
244
+ * Allow processing to continue if the swagger schema is missing a schema $ref.
245
+ */
246
+ allowUndefinedSchemaRefTags?: boolean;
247
+ /**
248
+ * Object type to use for missing swagger schemas refs default is object.
249
+ */
250
+ defaultUndefinedSchemaType?: 'string' | 'number' | 'object' | 'array' | 'boolean' | 'integer';
243
251
  };
package/package.json CHANGED
@@ -1,26 +1,27 @@
1
1
  {
2
2
  "name": "@graphql-mesh/openapi",
3
- "version": "1.0.0-alpha-3fc47d119.0",
3
+ "version": "1.0.0-alpha-20220804093904-8e2e41f7f",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
- "@graphql-mesh/types": "0.79.0-alpha-3fc47d119.0",
7
- "@graphql-mesh/utils": "1.0.0-alpha-3fc47d119.0",
6
+ "@graphql-mesh/types": "0.79.0-alpha-20220804093904-8e2e41f7f",
7
+ "@graphql-mesh/utils": "1.0.0-alpha-20220804093904-8e2e41f7f",
8
8
  "graphql": "*"
9
9
  },
10
10
  "dependencies": {
11
11
  "@graphql-mesh/cross-helpers": "0.2.0",
12
- "@graphql-mesh/store": "1.0.0-alpha-3fc47d119.0",
12
+ "@graphql-mesh/store": "1.0.0-alpha-20220804093904-8e2e41f7f",
13
13
  "@graphql-mesh/string-interpolation": "0.3.0",
14
- "@graphql-tools/utils": "8.8.0",
15
- "@whatwg-node/fetch": "^0.0.2",
14
+ "@graphql-tools/utils": "8.9.0",
15
+ "@whatwg-node/fetch": "^0.2.7",
16
16
  "deep-equal": "2.0.5",
17
- "form-urlencoded": "6.0.7",
17
+ "form-urlencoded": "6.1.0",
18
18
  "graphql-scalars": "1.17.0",
19
19
  "json-pointer": "0.6.2",
20
20
  "jsonpath-plus": "7.0.0",
21
21
  "openapi-diff": "0.23.5",
22
22
  "openapi-types": "12.0.0",
23
23
  "pluralize": "8.0.0",
24
+ "qs": "6.11.0",
24
25
  "swagger2openapi": "7.0.8",
25
26
  "tslib": "^2.4.0",
26
27
  "url-join": "4.0.1"