sofa-api 0.15.5 → 0.16.1

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
@@ -73,12 +73,12 @@ function resolveVariable({ value, type, schema, }) {
73
73
  }
74
74
  }
75
75
 
76
- var _a;
76
+ var _a, _b;
77
77
  const levels = ['error', 'warn', 'info', 'debug'];
78
78
  const toLevel = (string) => levels.includes(string) ? string : null;
79
- const currentLevel = process.env.SOFA_DEBUG
79
+ const currentLevel = ((_a = globalThis.process) === null || _a === void 0 ? void 0 : _a.env.SOFA_DEBUG)
80
80
  ? 'debug'
81
- : (_a = toLevel(process.env.SOFA_LOGGER_LEVEL)) !== null && _a !== void 0 ? _a : 'info';
81
+ : (_b = toLevel(process.env.SOFA_LOGGER_LEVEL)) !== null && _b !== void 0 ? _b : 'info';
82
82
  const log = (level, color, args) => {
83
83
  if (levels.indexOf(level) <= levels.indexOf(currentLevel)) {
84
84
  console.log(`${color(level)}:`, ...args);
@@ -275,6 +275,34 @@ class SubscriptionManager {
275
275
  }
276
276
  }
277
277
 
278
+ const defaultErrorHandler = (errors) => {
279
+ var _a;
280
+ let status;
281
+ const headers = {
282
+ 'Content-Type': 'application/json; charset=utf-8',
283
+ };
284
+ for (const error of errors) {
285
+ if (typeof error === 'object' &&
286
+ error != null &&
287
+ ((_a = error.extensions) === null || _a === void 0 ? void 0 : _a.http)) {
288
+ if (error.extensions.http.status &&
289
+ (!status || error.extensions.http.status > status)) {
290
+ status = error.extensions.http.status;
291
+ }
292
+ if (error.extensions.http.headers) {
293
+ Object.assign(headers, error.extensions.http.headers);
294
+ }
295
+ delete error.extensions.http;
296
+ }
297
+ }
298
+ if (!status) {
299
+ status = 500;
300
+ }
301
+ return new router.Response(JSON.stringify({ errors }), {
302
+ status,
303
+ headers,
304
+ });
305
+ };
278
306
  function createRouter(sofa) {
279
307
  logger.debug('[Sofa] Creating router');
280
308
  const router$1 = router.createRouter({
@@ -451,82 +479,79 @@ function createMutationRoute({ sofa, router, fieldName, }) {
451
479
  function useHandler(config) {
452
480
  const { sofa, operation, fieldName } = config;
453
481
  const info = config.info;
482
+ const errorHandler = sofa.errorHandler || defaultErrorHandler;
454
483
  return (request, serverContext) => tslib.__awaiter(this, void 0, void 0, function* () {
455
- var _a;
456
- let body = {};
457
- if (request.body != null) {
458
- const strBody = yield request.text();
459
- if (strBody) {
460
- body = JSON.parse(strBody);
484
+ var _a, _b;
485
+ try {
486
+ let body = {};
487
+ if (request.body != null) {
488
+ const strBody = yield request.text();
489
+ if (strBody) {
490
+ try {
491
+ body = JSON.parse(strBody);
492
+ }
493
+ catch (error) {
494
+ throw utils.createGraphQLError('POST body sent invalid JSON.', {
495
+ extensions: {
496
+ http: {
497
+ status: 400,
498
+ }
499
+ }
500
+ });
501
+ }
502
+ }
461
503
  }
462
- }
463
- const variableValues = info.variables.reduce((variables, variable) => {
464
- const name = variable.variable.name.value;
465
- const value = parseVariable({
466
- value: pickParam({
467
- url: request.url,
468
- body,
469
- params: request.params || {},
470
- name,
471
- }),
472
- variable,
473
- schema: sofa.schema,
474
- });
475
- if (typeof value === 'undefined') {
476
- return variables;
504
+ let variableValues = {};
505
+ try {
506
+ variableValues = info.variables.reduce((variables, variable) => {
507
+ const name = variable.variable.name.value;
508
+ const value = parseVariable({
509
+ value: pickParam({
510
+ url: request.url,
511
+ body,
512
+ params: request.params || {},
513
+ name,
514
+ }),
515
+ variable,
516
+ schema: sofa.schema,
517
+ });
518
+ if (typeof value === 'undefined') {
519
+ return variables;
520
+ }
521
+ return Object.assign(Object.assign({}, variables), { [name]: value });
522
+ }, {});
477
523
  }
478
- return Object.assign(Object.assign({}, variables), { [name]: value });
479
- }, {});
480
- const sofaServerContext = Object.assign(Object.assign({}, serverContext), { request });
481
- const contextValue = yield sofa.contextFactory(sofaServerContext);
482
- const result = yield sofa.execute({
483
- schema: sofa.schema,
484
- document: operation,
485
- contextValue,
486
- variableValues,
487
- operationName: info.operation.name && info.operation.name.value,
488
- });
489
- if (result.errors) {
490
- const defaultErrorHandler = (errors) => {
491
- var _a;
492
- let status;
493
- const headers = {
494
- 'Content-Type': 'application/json; charset=utf-8',
495
- };
496
- for (const error of errors) {
497
- if (typeof error === 'object' && error != null && ((_a = error.extensions) === null || _a === void 0 ? void 0 : _a.http)) {
498
- if (error.extensions.http.status &&
499
- (!status || error.extensions.http.status > status)) {
500
- status = error.extensions.http.status;
501
- }
502
- if (error.extensions.http.headers) {
503
- Object.assign(headers, error.extensions.http.headers);
524
+ catch (error) {
525
+ throw utils.createGraphQLError(error.message || ((_a = error.toString) === null || _a === void 0 ? void 0 : _a.call(error)) || error, {
526
+ extensions: {
527
+ http: {
528
+ status: 400,
504
529
  }
505
530
  }
506
- }
507
- if (!status) {
508
- status = 500;
509
- }
510
- if (errors.length === 1) {
511
- return new router.Response(JSON.stringify(errors[0]), {
512
- status,
513
- headers,
514
- });
515
- }
516
- return new router.Response(JSON.stringify({ errors }), {
517
- status,
518
- headers,
519
531
  });
520
- };
521
- const errorHandler = sofa.errorHandler || defaultErrorHandler;
522
- return errorHandler(result.errors);
532
+ }
533
+ const sofaServerContext = Object.assign(Object.assign({}, serverContext), { request });
534
+ const contextValue = yield sofa.contextFactory(sofaServerContext);
535
+ const result = yield sofa.execute({
536
+ schema: sofa.schema,
537
+ document: operation,
538
+ contextValue,
539
+ variableValues,
540
+ operationName: info.operation.name && info.operation.name.value,
541
+ });
542
+ if (result.errors) {
543
+ return errorHandler(result.errors);
544
+ }
545
+ return new router.Response(JSON.stringify((_b = result.data) === null || _b === void 0 ? void 0 : _b[fieldName]), {
546
+ status: config.route.responseStatus,
547
+ headers: {
548
+ 'Content-Type': 'application/json',
549
+ },
550
+ });
551
+ }
552
+ catch (error) {
553
+ return errorHandler([error]);
523
554
  }
524
- return new router.Response(JSON.stringify((_a = result.data) === null || _a === void 0 ? void 0 : _a[fieldName]), {
525
- status: config.route.responseStatus,
526
- headers: {
527
- 'Content-Type': 'application/json',
528
- },
529
- });
530
555
  });
531
556
  }
532
557
  function getPath(fieldName, hasId = false) {
@@ -653,6 +678,16 @@ function mapToPrimitive(type) {
653
678
  }
654
679
  function mapToRef(type) {
655
680
  return `#/components/schemas/${type}`;
681
+ }
682
+ function normalizePathParamForOpenAPI(path) {
683
+ const pathParts = path.split('/');
684
+ const normalizedPathParts = pathParts.map((part) => {
685
+ if (part.startsWith(':')) {
686
+ return `{${part.slice(1)}}`;
687
+ }
688
+ return part;
689
+ });
690
+ return normalizedPathParts.join('/');
656
691
  }
657
692
 
658
693
  function buildSchemaObjectFromType(type, opts) {
@@ -887,7 +922,7 @@ function OpenAPI({ schema, info, servers, components, security, tags, customScal
887
922
  addRoute(info, config) {
888
923
  const basePath = (config === null || config === void 0 ? void 0 : config.basePath) || '';
889
924
  const path = basePath +
890
- info.path.replace(/\:[a-z0-9]+\w/i, (param) => `{${param.replace(':', '')}}`);
925
+ normalizePathParamForOpenAPI(info.path);
891
926
  if (!swagger.paths[path]) {
892
927
  swagger.paths[path] = {};
893
928
  }
package/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { __awaiter, __asyncValues } from 'tslib';
2
2
  import { getOperationAST, Kind, isScalarType, isEqualType, GraphQLBoolean, isInputObjectType, isObjectType, isNonNullType, execute, subscribe, getNamedType, isListType, isEnumType, parse, printType, isIntrospectionType } from 'graphql';
3
- import { buildOperationNodeForField } from '@graphql-tools/utils';
3
+ import { buildOperationNodeForField, createGraphQLError } from '@graphql-tools/utils';
4
4
  import { paramCase } from 'param-case';
5
5
  import { crypto, fetch } from '@whatwg-node/fetch';
6
6
  import colors from 'ansi-colors';
@@ -67,12 +67,12 @@ function resolveVariable({ value, type, schema, }) {
67
67
  }
68
68
  }
69
69
 
70
- var _a;
70
+ var _a, _b;
71
71
  const levels = ['error', 'warn', 'info', 'debug'];
72
72
  const toLevel = (string) => levels.includes(string) ? string : null;
73
- const currentLevel = process.env.SOFA_DEBUG
73
+ const currentLevel = ((_a = globalThis.process) === null || _a === void 0 ? void 0 : _a.env.SOFA_DEBUG)
74
74
  ? 'debug'
75
- : (_a = toLevel(process.env.SOFA_LOGGER_LEVEL)) !== null && _a !== void 0 ? _a : 'info';
75
+ : (_b = toLevel(process.env.SOFA_LOGGER_LEVEL)) !== null && _b !== void 0 ? _b : 'info';
76
76
  const log = (level, color, args) => {
77
77
  if (levels.indexOf(level) <= levels.indexOf(currentLevel)) {
78
78
  console.log(`${color(level)}:`, ...args);
@@ -269,6 +269,34 @@ class SubscriptionManager {
269
269
  }
270
270
  }
271
271
 
272
+ const defaultErrorHandler = (errors) => {
273
+ var _a;
274
+ let status;
275
+ const headers = {
276
+ 'Content-Type': 'application/json; charset=utf-8',
277
+ };
278
+ for (const error of errors) {
279
+ if (typeof error === 'object' &&
280
+ error != null &&
281
+ ((_a = error.extensions) === null || _a === void 0 ? void 0 : _a.http)) {
282
+ if (error.extensions.http.status &&
283
+ (!status || error.extensions.http.status > status)) {
284
+ status = error.extensions.http.status;
285
+ }
286
+ if (error.extensions.http.headers) {
287
+ Object.assign(headers, error.extensions.http.headers);
288
+ }
289
+ delete error.extensions.http;
290
+ }
291
+ }
292
+ if (!status) {
293
+ status = 500;
294
+ }
295
+ return new Response(JSON.stringify({ errors }), {
296
+ status,
297
+ headers,
298
+ });
299
+ };
272
300
  function createRouter(sofa) {
273
301
  logger.debug('[Sofa] Creating router');
274
302
  const router = createRouter$1({
@@ -445,82 +473,79 @@ function createMutationRoute({ sofa, router, fieldName, }) {
445
473
  function useHandler(config) {
446
474
  const { sofa, operation, fieldName } = config;
447
475
  const info = config.info;
476
+ const errorHandler = sofa.errorHandler || defaultErrorHandler;
448
477
  return (request, serverContext) => __awaiter(this, void 0, void 0, function* () {
449
- var _a;
450
- let body = {};
451
- if (request.body != null) {
452
- const strBody = yield request.text();
453
- if (strBody) {
454
- body = JSON.parse(strBody);
478
+ var _a, _b;
479
+ try {
480
+ let body = {};
481
+ if (request.body != null) {
482
+ const strBody = yield request.text();
483
+ if (strBody) {
484
+ try {
485
+ body = JSON.parse(strBody);
486
+ }
487
+ catch (error) {
488
+ throw createGraphQLError('POST body sent invalid JSON.', {
489
+ extensions: {
490
+ http: {
491
+ status: 400,
492
+ }
493
+ }
494
+ });
495
+ }
496
+ }
455
497
  }
456
- }
457
- const variableValues = info.variables.reduce((variables, variable) => {
458
- const name = variable.variable.name.value;
459
- const value = parseVariable({
460
- value: pickParam({
461
- url: request.url,
462
- body,
463
- params: request.params || {},
464
- name,
465
- }),
466
- variable,
467
- schema: sofa.schema,
468
- });
469
- if (typeof value === 'undefined') {
470
- return variables;
498
+ let variableValues = {};
499
+ try {
500
+ variableValues = info.variables.reduce((variables, variable) => {
501
+ const name = variable.variable.name.value;
502
+ const value = parseVariable({
503
+ value: pickParam({
504
+ url: request.url,
505
+ body,
506
+ params: request.params || {},
507
+ name,
508
+ }),
509
+ variable,
510
+ schema: sofa.schema,
511
+ });
512
+ if (typeof value === 'undefined') {
513
+ return variables;
514
+ }
515
+ return Object.assign(Object.assign({}, variables), { [name]: value });
516
+ }, {});
471
517
  }
472
- return Object.assign(Object.assign({}, variables), { [name]: value });
473
- }, {});
474
- const sofaServerContext = Object.assign(Object.assign({}, serverContext), { request });
475
- const contextValue = yield sofa.contextFactory(sofaServerContext);
476
- const result = yield sofa.execute({
477
- schema: sofa.schema,
478
- document: operation,
479
- contextValue,
480
- variableValues,
481
- operationName: info.operation.name && info.operation.name.value,
482
- });
483
- if (result.errors) {
484
- const defaultErrorHandler = (errors) => {
485
- var _a;
486
- let status;
487
- const headers = {
488
- 'Content-Type': 'application/json; charset=utf-8',
489
- };
490
- for (const error of errors) {
491
- if (typeof error === 'object' && error != null && ((_a = error.extensions) === null || _a === void 0 ? void 0 : _a.http)) {
492
- if (error.extensions.http.status &&
493
- (!status || error.extensions.http.status > status)) {
494
- status = error.extensions.http.status;
495
- }
496
- if (error.extensions.http.headers) {
497
- Object.assign(headers, error.extensions.http.headers);
518
+ catch (error) {
519
+ throw createGraphQLError(error.message || ((_a = error.toString) === null || _a === void 0 ? void 0 : _a.call(error)) || error, {
520
+ extensions: {
521
+ http: {
522
+ status: 400,
498
523
  }
499
524
  }
500
- }
501
- if (!status) {
502
- status = 500;
503
- }
504
- if (errors.length === 1) {
505
- return new Response(JSON.stringify(errors[0]), {
506
- status,
507
- headers,
508
- });
509
- }
510
- return new Response(JSON.stringify({ errors }), {
511
- status,
512
- headers,
513
525
  });
514
- };
515
- const errorHandler = sofa.errorHandler || defaultErrorHandler;
516
- return errorHandler(result.errors);
526
+ }
527
+ const sofaServerContext = Object.assign(Object.assign({}, serverContext), { request });
528
+ const contextValue = yield sofa.contextFactory(sofaServerContext);
529
+ const result = yield sofa.execute({
530
+ schema: sofa.schema,
531
+ document: operation,
532
+ contextValue,
533
+ variableValues,
534
+ operationName: info.operation.name && info.operation.name.value,
535
+ });
536
+ if (result.errors) {
537
+ return errorHandler(result.errors);
538
+ }
539
+ return new Response(JSON.stringify((_b = result.data) === null || _b === void 0 ? void 0 : _b[fieldName]), {
540
+ status: config.route.responseStatus,
541
+ headers: {
542
+ 'Content-Type': 'application/json',
543
+ },
544
+ });
545
+ }
546
+ catch (error) {
547
+ return errorHandler([error]);
517
548
  }
518
- return new Response(JSON.stringify((_a = result.data) === null || _a === void 0 ? void 0 : _a[fieldName]), {
519
- status: config.route.responseStatus,
520
- headers: {
521
- 'Content-Type': 'application/json',
522
- },
523
- });
524
549
  });
525
550
  }
526
551
  function getPath(fieldName, hasId = false) {
@@ -647,6 +672,16 @@ function mapToPrimitive(type) {
647
672
  }
648
673
  function mapToRef(type) {
649
674
  return `#/components/schemas/${type}`;
675
+ }
676
+ function normalizePathParamForOpenAPI(path) {
677
+ const pathParts = path.split('/');
678
+ const normalizedPathParts = pathParts.map((part) => {
679
+ if (part.startsWith(':')) {
680
+ return `{${part.slice(1)}}`;
681
+ }
682
+ return part;
683
+ });
684
+ return normalizedPathParts.join('/');
650
685
  }
651
686
 
652
687
  function buildSchemaObjectFromType(type, opts) {
@@ -881,7 +916,7 @@ function OpenAPI({ schema, info, servers, components, security, tags, customScal
881
916
  addRoute(info, config) {
882
917
  const basePath = (config === null || config === void 0 ? void 0 : config.basePath) || '';
883
918
  const path = basePath +
884
- info.path.replace(/\:[a-z0-9]+\w/i, (param) => `{${param.replace(':', '')}}`);
919
+ normalizePathParamForOpenAPI(info.path);
885
920
  if (!swagger.paths[path]) {
886
921
  swagger.paths[path] = {};
887
922
  }
@@ -1,2 +1,3 @@
1
1
  export declare function mapToPrimitive(type: string): any;
2
2
  export declare function mapToRef(type: string): string;
3
+ export declare function normalizePathParamForOpenAPI(path: string): string;
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "sofa-api",
3
- "version": "0.15.5",
3
+ "version": "0.16.1",
4
4
  "description": "Create REST APIs with GraphQL",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
7
- "graphql": "^0.13.2 || ^14.0.0 || ^15.0.0 || ^16.0.0"
7
+ "graphql": "^15.0.0 || ^16.0.0"
8
8
  },
9
9
  "dependencies": {
10
10
  "@graphql-tools/utils": "9.1.4",
@@ -14,7 +14,7 @@
14
14
  "openapi-types": "12.1.0",
15
15
  "param-case": "3.0.4",
16
16
  "title-case": "3.0.3",
17
- "tslib": "2.4.1"
17
+ "tslib": "2.5.0"
18
18
  },
19
19
  "repository": {
20
20
  "type": "git",