@microsoft/m365-spec-parser 0.2.4 → 0.2.5-alpha.4da5c3b2d.0

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.
@@ -62,11 +62,8 @@ var ErrorType;
62
62
  ErrorType["PostBodyContainMultipleMediaTypes"] = "post-body-contain-multiple-media-types";
63
63
  ErrorType["ResponseContainMultipleMediaTypes"] = "response-contain-multiple-media-types";
64
64
  ErrorType["ResponseJsonIsEmpty"] = "response-json-is-empty";
65
- ErrorType["PostBodySchemaIsNotJson"] = "post-body-schema-is-not-json";
66
65
  ErrorType["PostBodyContainsRequiredUnsupportedSchema"] = "post-body-contains-required-unsupported-schema";
67
66
  ErrorType["ParamsContainRequiredUnsupportedSchema"] = "params-contain-required-unsupported-schema";
68
- ErrorType["ParamsContainsNestedObject"] = "params-contains-nested-object";
69
- ErrorType["RequestBodyContainsNestedObject"] = "request-body-contains-nested-object";
70
67
  ErrorType["ExceededRequiredParamsLimit"] = "exceeded-required-params-limit";
71
68
  ErrorType["NoParameter"] = "no-parameter";
72
69
  ErrorType["NoAPIInfo"] = "no-api-info";
@@ -86,6 +83,7 @@ var WarningType;
86
83
  WarningType["ConvertSwaggerToOpenAPI"] = "convert-swagger-to-openapi";
87
84
  WarningType["FuncDescriptionTooLong"] = "function-description-too-long";
88
85
  WarningType["OperationIdContainsSpecialCharacters"] = "operationid-contains-special-characters";
86
+ WarningType["UnsupportedAuthType"] = "unsupported-auth-type";
89
87
  WarningType["GenerateJsonDataFailed"] = "generate-json-data-failed";
90
88
  WarningType["Unknown"] = "unknown";
91
89
  })(WarningType || (WarningType = {}));
@@ -133,6 +131,7 @@ ConstantString.SwaggerNotSupported = "Swagger 2.0 is not supported. Please conve
133
131
  ConstantString.SpecVersionNotSupported = "Unsupported OpenAPI version %s. Please use version 3.0.x.";
134
132
  ConstantString.MultipleAuthNotSupported = "Multiple authentication methods are unsupported. Ensure all selected APIs use identical authentication.";
135
133
  ConstantString.OperationIdContainsSpecialCharacters = "Operation id '%s' in OpenAPI description document contained special characters and was renamed to '%s'.";
134
+ ConstantString.AuthTypeIsNotSupported = "Unsupported authorization type in API '%s'. No authorization will be used.";
136
135
  ConstantString.UnsupportedSchema = "Unsupported schema in %s %s: %s";
137
136
  ConstantString.FuncDescriptionTooLong = "The description of the function '%s' is too long. The current length is %s characters, while the maximum allowed length is %s characters.";
138
137
  ConstantString.GenerateJsonDataFailed = "Failed to generate JSON data for api: %s due to %s.";
@@ -142,17 +141,12 @@ ConstantString.WrappedCardResponseLayout = "list";
142
141
  ConstantString.GetMethod = "get";
143
142
  ConstantString.PostMethod = "post";
144
143
  ConstantString.AdaptiveCardVersion = "1.5";
145
- ConstantString.AdaptiveCardSchema = "http://adaptivecards.io/schemas/adaptive-card.json";
144
+ ConstantString.AdaptiveCardSchema = "https://adaptivecards.io/schemas/adaptive-card.json";
146
145
  ConstantString.AdaptiveCardType = "AdaptiveCard";
147
146
  ConstantString.TextBlockType = "TextBlock";
148
147
  ConstantString.ImageType = "Image";
149
148
  ConstantString.ContainerType = "Container";
150
- ConstantString.RegistrationIdPostfix = {
151
- apiKey: "REGISTRATION_ID",
152
- oauth2: "CONFIGURATION_ID",
153
- http: "REGISTRATION_ID",
154
- openIdConnect: "REGISTRATION_ID",
155
- };
149
+ ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
156
150
  ConstantString.ResponseCodeFor20X = [
157
151
  "200",
158
152
  "201",
@@ -164,6 +158,7 @@ ConstantString.ResponseCodeFor20X = [
164
158
  "207",
165
159
  "208",
166
160
  "226",
161
+ "2XX",
167
162
  "default",
168
163
  ];
169
164
  ConstantString.AllOperationMethods = [
@@ -221,17 +216,6 @@ ConstantString.PluginManifestSchema = "https://developer.microsoft.com/json-sche
221
216
 
222
217
  // Copyright (c) Microsoft Corporation.
223
218
  class Utils {
224
- static hasNestedObjectInSchema(schema) {
225
- if (this.isObjectSchema(schema)) {
226
- for (const property in schema.properties) {
227
- const nestedSchema = schema.properties[property];
228
- if (this.isObjectSchema(nestedSchema)) {
229
- return true;
230
- }
231
- }
232
- }
233
- return false;
234
- }
235
219
  static isObjectSchema(schema) {
236
220
  return schema.type === "object" || (!schema.type && !!schema.properties);
237
221
  }
@@ -244,11 +228,32 @@ class Utils {
244
228
  static isAPIKeyAuth(authScheme) {
245
229
  return authScheme.type === "apiKey";
246
230
  }
231
+ static isAPIKeyAuthButNotInCookie(authScheme) {
232
+ return authScheme.type === "apiKey" && authScheme.in !== "cookie";
233
+ }
247
234
  static isOAuthWithAuthCodeFlow(authScheme) {
248
235
  return !!(authScheme.type === "oauth2" &&
249
236
  authScheme.flows &&
250
237
  authScheme.flows.authorizationCode);
251
238
  }
239
+ static isNotSupportedAuth(authSchemeArray) {
240
+ if (authSchemeArray.length === 0) {
241
+ return false;
242
+ }
243
+ if (authSchemeArray.length > 0 && authSchemeArray.every((auths) => auths.length > 1)) {
244
+ return true;
245
+ }
246
+ for (const auths of authSchemeArray) {
247
+ if (auths.length === 1) {
248
+ if (Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme) ||
249
+ Utils.isBearerTokenAuth(auths[0].authScheme) ||
250
+ Utils.isAPIKeyAuthButNotInCookie(auths[0].authScheme)) {
251
+ return false;
252
+ }
253
+ }
254
+ }
255
+ return true;
256
+ }
252
257
  static getAuthArray(securities, spec) {
253
258
  var _a;
254
259
  const result = [];
@@ -273,6 +278,20 @@ class Utils {
273
278
  result.sort((a, b) => a[0].name.localeCompare(b[0].name));
274
279
  return result;
275
280
  }
281
+ static getAuthMap(spec) {
282
+ const authMap = {};
283
+ for (const url in spec.paths) {
284
+ for (const method in spec.paths[url]) {
285
+ const operation = spec.paths[url][method];
286
+ const authArray = Utils.getAuthArray(operation.security, spec);
287
+ if (authArray && authArray.length > 0) {
288
+ const currentAuth = authArray[0][0];
289
+ authMap[operation.operationId] = currentAuth;
290
+ }
291
+ }
292
+ }
293
+ return authMap;
294
+ }
276
295
  static getAuthInfo(spec) {
277
296
  let authInfo = undefined;
278
297
  for (const url in spec.paths) {
@@ -301,27 +320,33 @@ class Utils {
301
320
  let multipleMediaType = false;
302
321
  for (const code of ConstantString.ResponseCodeFor20X) {
303
322
  const responseObject = (_a = operationObject === null || operationObject === void 0 ? void 0 : operationObject.responses) === null || _a === void 0 ? void 0 : _a[code];
304
- if (responseObject === null || responseObject === void 0 ? void 0 : responseObject.content) {
305
- for (const contentType of Object.keys(responseObject.content)) {
306
- // json media type can also be "application/json; charset=utf-8"
307
- if (contentType.indexOf("application/json") >= 0) {
308
- multipleMediaType = false;
309
- json = responseObject.content[contentType];
310
- if (Utils.containMultipleMediaTypes(responseObject)) {
311
- multipleMediaType = true;
312
- if (!allowMultipleMediaType) {
313
- json = {};
314
- }
315
- }
316
- else {
317
- return { json, multipleMediaType };
318
- }
319
- }
320
- }
323
+ if (!responseObject) {
324
+ continue;
325
+ }
326
+ multipleMediaType = Utils.containMultipleMediaTypes(responseObject);
327
+ if (!allowMultipleMediaType && multipleMediaType) {
328
+ json = {};
329
+ continue;
330
+ }
331
+ const mediaObj = Utils.getJsonContentType(responseObject);
332
+ if (Object.keys(mediaObj).length > 0) {
333
+ json = mediaObj;
334
+ return { json, multipleMediaType };
321
335
  }
322
336
  }
323
337
  return { json, multipleMediaType };
324
338
  }
339
+ static getJsonContentType(responseObject) {
340
+ if (responseObject.content) {
341
+ for (const contentType of Object.keys(responseObject.content)) {
342
+ // json media type can also be "application/json; charset=utf-8"
343
+ if (contentType.indexOf("application/json") >= 0) {
344
+ return responseObject.content[contentType];
345
+ }
346
+ }
347
+ }
348
+ return {};
349
+ }
325
350
  static convertPathToCamelCase(path) {
326
351
  const pathSegments = path.split(/[./{]/);
327
352
  const camelCaseSegments = pathSegments.map((segment) => {
@@ -357,7 +382,7 @@ class Utils {
357
382
  }
358
383
  return newStr;
359
384
  }
360
- static checkServerUrl(servers) {
385
+ static checkServerUrl(servers, allowHttp = false) {
361
386
  const errors = [];
362
387
  let serverUrl;
363
388
  try {
@@ -380,8 +405,7 @@ class Utils {
380
405
  data: servers,
381
406
  });
382
407
  }
383
- else if (protocol !== "https:") {
384
- // Http server url is not supported
408
+ else if (protocol !== "https:" && !(protocol === "http:" && allowHttp)) {
385
409
  const protocolString = protocol.slice(0, -1);
386
410
  errors.push({
387
411
  type: ErrorType.UrlProtocolNotSupported,
@@ -397,10 +421,11 @@ class Utils {
397
421
  let hasTopLevelServers = false;
398
422
  let hasPathLevelServers = false;
399
423
  let hasOperationLevelServers = false;
424
+ const allowHttp = options.projectType === ProjectType.Copilot;
400
425
  if (spec.servers && spec.servers.length >= 1) {
401
426
  hasTopLevelServers = true;
402
427
  // for multiple server, we only use the first url
403
- const serverErrors = Utils.checkServerUrl(spec.servers);
428
+ const serverErrors = Utils.checkServerUrl(spec.servers, allowHttp);
404
429
  errors.push(...serverErrors);
405
430
  }
406
431
  const paths = spec.paths;
@@ -408,7 +433,7 @@ class Utils {
408
433
  const methods = paths[path];
409
434
  if ((methods === null || methods === void 0 ? void 0 : methods.servers) && methods.servers.length >= 1) {
410
435
  hasPathLevelServers = true;
411
- const serverErrors = Utils.checkServerUrl(methods.servers);
436
+ const serverErrors = Utils.checkServerUrl(methods.servers, allowHttp);
412
437
  errors.push(...serverErrors);
413
438
  }
414
439
  for (const method in methods) {
@@ -416,7 +441,7 @@ class Utils {
416
441
  if (((_a = options.allowMethods) === null || _a === void 0 ? void 0 : _a.includes(method)) && operationObject) {
417
442
  if ((operationObject === null || operationObject === void 0 ? void 0 : operationObject.servers) && operationObject.servers.length >= 1) {
418
443
  hasOperationLevelServers = true;
419
- const serverErrors = Utils.checkServerUrl(operationObject.servers);
444
+ const serverErrors = Utils.checkServerUrl(operationObject.servers, allowHttp);
420
445
  errors.push(...serverErrors);
421
446
  }
422
447
  }
@@ -705,22 +730,6 @@ class Validator {
705
730
  }
706
731
  return result;
707
732
  }
708
- validateResponse(method, path) {
709
- const result = { isValid: true, reason: [] };
710
- const operationObject = this.spec.paths[path][method];
711
- const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
712
- if (this.options.projectType === ProjectType.SME) {
713
- // only support response body only contains “application/json” content type
714
- if (multipleMediaType) {
715
- result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
716
- }
717
- else if (Object.keys(json).length === 0) {
718
- // response body should not be empty
719
- result.reason.push(ErrorType.ResponseJsonIsEmpty);
720
- }
721
- }
722
- return result;
723
- }
724
733
  validateServer(method, path) {
725
734
  const result = { isValid: true, reason: [] };
726
735
  const serverObj = Utils.getServerObject(this.spec, method, path);
@@ -729,8 +738,8 @@ class Validator {
729
738
  result.reason.push(ErrorType.NoServerInformation);
730
739
  }
731
740
  else {
732
- // server url should be absolute url with https protocol
733
- const serverValidateResult = Utils.checkServerUrl([serverObj]);
741
+ const allowHttp = this.projectType === ProjectType.Copilot;
742
+ const serverValidateResult = Utils.checkServerUrl([serverObj], allowHttp);
734
743
  result.reason.push(...serverValidateResult.map((item) => item.type));
735
744
  }
736
745
  return result;
@@ -753,6 +762,9 @@ class Validator {
753
762
  reason: [ErrorType.MultipleAuthNotSupported],
754
763
  };
755
764
  }
765
+ if (this.projectType === ProjectType.Copilot) {
766
+ return { isValid: true, reason: [] };
767
+ }
756
768
  for (const auths of authSchemeArray) {
757
769
  if (auths.length === 1) {
758
770
  if ((this.options.allowAPIKeyAuth && Utils.isAPIKeyAuth(auths[0].authScheme)) ||
@@ -765,114 +777,6 @@ class Validator {
765
777
  }
766
778
  return { isValid: false, reason: [ErrorType.AuthTypeIsNotSupported] };
767
779
  }
768
- checkPostBodySchema(schema, isRequired = false) {
769
- var _a;
770
- const paramResult = {
771
- requiredNum: 0,
772
- optionalNum: 0,
773
- isValid: true,
774
- reason: [],
775
- };
776
- if (Object.keys(schema).length === 0) {
777
- return paramResult;
778
- }
779
- const isRequiredWithoutDefault = isRequired && schema.default === undefined;
780
- const isCopilot = this.projectType === ProjectType.Copilot;
781
- if (isCopilot && Utils.hasNestedObjectInSchema(schema)) {
782
- paramResult.isValid = false;
783
- paramResult.reason = [ErrorType.RequestBodyContainsNestedObject];
784
- return paramResult;
785
- }
786
- if (schema.type === "string" ||
787
- schema.type === "integer" ||
788
- schema.type === "boolean" ||
789
- schema.type === "number") {
790
- if (isRequiredWithoutDefault) {
791
- paramResult.requiredNum = paramResult.requiredNum + 1;
792
- }
793
- else {
794
- paramResult.optionalNum = paramResult.optionalNum + 1;
795
- }
796
- }
797
- else if (Utils.isObjectSchema(schema)) {
798
- const { properties } = schema;
799
- for (const property in properties) {
800
- let isRequired = false;
801
- if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
802
- isRequired = true;
803
- }
804
- const result = this.checkPostBodySchema(properties[property], isRequired);
805
- paramResult.requiredNum += result.requiredNum;
806
- paramResult.optionalNum += result.optionalNum;
807
- paramResult.isValid = paramResult.isValid && result.isValid;
808
- paramResult.reason.push(...result.reason);
809
- }
810
- }
811
- else {
812
- if (isRequiredWithoutDefault && !isCopilot) {
813
- paramResult.isValid = false;
814
- paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
815
- }
816
- }
817
- return paramResult;
818
- }
819
- checkParamSchema(paramObject) {
820
- const paramResult = {
821
- requiredNum: 0,
822
- optionalNum: 0,
823
- isValid: true,
824
- reason: [],
825
- };
826
- if (!paramObject) {
827
- return paramResult;
828
- }
829
- const isCopilot = this.projectType === ProjectType.Copilot;
830
- for (let i = 0; i < paramObject.length; i++) {
831
- const param = paramObject[i];
832
- const schema = param.schema;
833
- if (isCopilot && Utils.hasNestedObjectInSchema(schema)) {
834
- paramResult.isValid = false;
835
- paramResult.reason.push(ErrorType.ParamsContainsNestedObject);
836
- continue;
837
- }
838
- const isRequiredWithoutDefault = param.required && schema.default === undefined;
839
- if (isCopilot) {
840
- if (isRequiredWithoutDefault) {
841
- paramResult.requiredNum = paramResult.requiredNum + 1;
842
- }
843
- else {
844
- paramResult.optionalNum = paramResult.optionalNum + 1;
845
- }
846
- continue;
847
- }
848
- if (param.in === "header" || param.in === "cookie") {
849
- if (isRequiredWithoutDefault) {
850
- paramResult.isValid = false;
851
- paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
852
- }
853
- continue;
854
- }
855
- if (schema.type !== "boolean" &&
856
- schema.type !== "string" &&
857
- schema.type !== "number" &&
858
- schema.type !== "integer") {
859
- if (isRequiredWithoutDefault) {
860
- paramResult.isValid = false;
861
- paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
862
- }
863
- continue;
864
- }
865
- if (param.in === "query" || param.in === "path") {
866
- if (isRequiredWithoutDefault) {
867
- paramResult.requiredNum = paramResult.requiredNum + 1;
868
- }
869
- else {
870
- paramResult.optionalNum = paramResult.optionalNum + 1;
871
- }
872
- }
873
- }
874
- return paramResult;
875
- }
876
780
  }
877
781
 
878
782
  // Copyright (c) Microsoft Corporation.
@@ -882,7 +786,6 @@ class CopilotValidator extends Validator {
882
786
  this.projectType = ProjectType.Copilot;
883
787
  this.options = options;
884
788
  this.spec = spec;
885
- this.checkCircularReference();
886
789
  }
887
790
  validateSpec() {
888
791
  const result = { errors: [], warnings: [] };
@@ -908,10 +811,6 @@ class CopilotValidator extends Validator {
908
811
  if (!methodAndPathResult.isValid) {
909
812
  return methodAndPathResult;
910
813
  }
911
- const circularReferenceResult = this.validateCircularReference(method, path);
912
- if (!circularReferenceResult.isValid) {
913
- return circularReferenceResult;
914
- }
915
814
  const operationObject = this.spec.paths[path][method];
916
815
  // validate auth
917
816
  const authCheckResult = this.validateAuth(method, path);
@@ -923,24 +822,6 @@ class CopilotValidator extends Validator {
923
822
  // validate server
924
823
  const validateServerResult = this.validateServer(method, path);
925
824
  result.reason.push(...validateServerResult.reason);
926
- // validate response
927
- const validateResponseResult = this.validateResponse(method, path);
928
- result.reason.push(...validateResponseResult.reason);
929
- // validate requestBody
930
- const requestBody = operationObject.requestBody;
931
- const requestJsonBody = requestBody === null || requestBody === void 0 ? void 0 : requestBody.content["application/json"];
932
- if (requestJsonBody) {
933
- const requestBodySchema = requestJsonBody.schema;
934
- if (!Utils.isObjectSchema(requestBodySchema)) {
935
- result.reason.push(ErrorType.PostBodySchemaIsNotJson);
936
- }
937
- const requestBodyParamResult = this.checkPostBodySchema(requestBodySchema, requestBody.required);
938
- result.reason.push(...requestBodyParamResult.reason);
939
- }
940
- // validate parameters
941
- const paramObject = operationObject.parameters;
942
- const paramResult = this.checkParamSchema(paramObject);
943
- result.reason.push(...paramResult.reason);
944
825
  if (result.reason.length > 0) {
945
826
  result.isValid = false;
946
827
  }
@@ -1032,6 +913,108 @@ class SMEValidator extends Validator {
1032
913
  }
1033
914
  return result;
1034
915
  }
916
+ validateResponse(method, path) {
917
+ const result = { isValid: true, reason: [] };
918
+ const operationObject = this.spec.paths[path][method];
919
+ const { json, multipleMediaType } = Utils.getResponseJson(operationObject);
920
+ // only support response body only contains “application/json” content type
921
+ if (multipleMediaType) {
922
+ result.reason.push(ErrorType.ResponseContainMultipleMediaTypes);
923
+ }
924
+ else if (Object.keys(json).length === 0) {
925
+ // response body should not be empty
926
+ result.reason.push(ErrorType.ResponseJsonIsEmpty);
927
+ }
928
+ return result;
929
+ }
930
+ checkPostBodySchema(schema, isRequired = false) {
931
+ var _a;
932
+ const paramResult = {
933
+ requiredNum: 0,
934
+ optionalNum: 0,
935
+ isValid: true,
936
+ reason: [],
937
+ };
938
+ if (Object.keys(schema).length === 0) {
939
+ return paramResult;
940
+ }
941
+ const isRequiredWithoutDefault = isRequired && schema.default === undefined;
942
+ const isCopilot = this.projectType === ProjectType.Copilot;
943
+ if (schema.type === "string" ||
944
+ schema.type === "integer" ||
945
+ schema.type === "boolean" ||
946
+ schema.type === "number") {
947
+ if (isRequiredWithoutDefault) {
948
+ paramResult.requiredNum = paramResult.requiredNum + 1;
949
+ }
950
+ else {
951
+ paramResult.optionalNum = paramResult.optionalNum + 1;
952
+ }
953
+ }
954
+ else if (Utils.isObjectSchema(schema)) {
955
+ const { properties } = schema;
956
+ for (const property in properties) {
957
+ let isRequired = false;
958
+ if (schema.required && ((_a = schema.required) === null || _a === void 0 ? void 0 : _a.indexOf(property)) >= 0) {
959
+ isRequired = true;
960
+ }
961
+ const result = this.checkPostBodySchema(properties[property], isRequired);
962
+ paramResult.requiredNum += result.requiredNum;
963
+ paramResult.optionalNum += result.optionalNum;
964
+ paramResult.isValid = paramResult.isValid && result.isValid;
965
+ paramResult.reason.push(...result.reason);
966
+ }
967
+ }
968
+ else {
969
+ if (isRequiredWithoutDefault && !isCopilot) {
970
+ paramResult.isValid = false;
971
+ paramResult.reason.push(ErrorType.PostBodyContainsRequiredUnsupportedSchema);
972
+ }
973
+ }
974
+ return paramResult;
975
+ }
976
+ checkParamSchema(paramObject) {
977
+ const paramResult = {
978
+ requiredNum: 0,
979
+ optionalNum: 0,
980
+ isValid: true,
981
+ reason: [],
982
+ };
983
+ if (!paramObject) {
984
+ return paramResult;
985
+ }
986
+ for (let i = 0; i < paramObject.length; i++) {
987
+ const param = paramObject[i];
988
+ const schema = param.schema;
989
+ const isRequiredWithoutDefault = param.required && schema.default === undefined;
990
+ if (param.in === "header" || param.in === "cookie") {
991
+ if (isRequiredWithoutDefault) {
992
+ paramResult.isValid = false;
993
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
994
+ }
995
+ continue;
996
+ }
997
+ if (schema.type !== "boolean" &&
998
+ schema.type !== "string" &&
999
+ schema.type !== "number" &&
1000
+ schema.type !== "integer") {
1001
+ if (isRequiredWithoutDefault) {
1002
+ paramResult.isValid = false;
1003
+ paramResult.reason.push(ErrorType.ParamsContainRequiredUnsupportedSchema);
1004
+ }
1005
+ continue;
1006
+ }
1007
+ if (param.in === "query" || param.in === "path") {
1008
+ if (isRequiredWithoutDefault) {
1009
+ paramResult.requiredNum = paramResult.requiredNum + 1;
1010
+ }
1011
+ else {
1012
+ paramResult.optionalNum = paramResult.optionalNum + 1;
1013
+ }
1014
+ }
1015
+ }
1016
+ return paramResult;
1017
+ }
1035
1018
  validateParamCount(postBodyResult, paramResult) {
1036
1019
  const result = { isValid: true, reason: [] };
1037
1020
  const totalRequiredParams = postBodyResult.requiredNum + paramResult.requiredNum;