github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/pkg/graphql/webhook_validation_test.go (about) 1 package graphql_test 2 3 import ( 4 "testing" 5 6 "github.com/kyma-incubator/compass/components/director/pkg/str" 7 8 "github.com/kyma-incubator/compass/components/director/pkg/correlation" 9 10 "github.com/kyma-incubator/compass/components/director/pkg/graphql" 11 "github.com/kyma-incubator/compass/components/director/pkg/inputvalidation/inputvalidationtest" 12 "github.com/stretchr/testify/require" 13 ) 14 15 func TestWebhookInput_Validate_Type(t *testing.T) { 16 testCases := []struct { 17 Name string 18 Value graphql.WebhookType 19 ExpectedValid bool 20 }{ 21 { 22 Name: "ExpectedValid", 23 Value: graphql.WebhookTypeConfigurationChanged, 24 ExpectedValid: true, 25 }, 26 { 27 Name: "Invalid - Empty", 28 Value: inputvalidationtest.EmptyString, 29 ExpectedValid: false, 30 }, 31 { 32 Name: "Invalid - Not enum", 33 Value: "invalid", 34 ExpectedValid: false, 35 }, 36 } 37 38 for _, testCase := range testCases { 39 t.Run(testCase.Name, func(t *testing.T) { 40 //GIVEN 41 sut := fixValidWebhookInput(inputvalidationtest.ValidURL) 42 sut.Type = testCase.Value 43 // WHEN 44 err := sut.Validate() 45 // THEN 46 if testCase.ExpectedValid { 47 require.NoError(t, err) 48 } else { 49 require.Error(t, err) 50 } 51 }) 52 } 53 } 54 55 func TestWebhookInput_Validate_URL(t *testing.T) { 56 testCases := []struct { 57 Name string 58 Value string 59 ExpectedValid bool 60 }{ 61 { 62 Name: "ExpectedValid", 63 Value: inputvalidationtest.ValidURL, 64 ExpectedValid: true, 65 }, 66 { 67 Name: "Invalid - Empty string", 68 Value: inputvalidationtest.EmptyString, 69 ExpectedValid: false, 70 }, 71 { 72 Name: "Invalid - Invalid URL", 73 Value: inputvalidationtest.InvalidURL, 74 ExpectedValid: false, 75 }, 76 { 77 Name: "Invalid - Too long", 78 Value: inputvalidationtest.URL257Long, 79 ExpectedValid: false, 80 }, 81 } 82 83 for _, testCase := range testCases { 84 t.Run(testCase.Name, func(t *testing.T) { 85 //GIVEN 86 sut := fixValidWebhookInput(inputvalidationtest.ValidURL) 87 sut.URL = &testCase.Value 88 // WHEN 89 err := sut.Validate() 90 // THEN 91 if testCase.ExpectedValid { 92 require.NoError(t, err) 93 } else { 94 require.Error(t, err) 95 } 96 }) 97 } 98 } 99 100 func TestWebhookInput_Validate_Auth(t *testing.T) { 101 auth := fixValidAuthInput() 102 testCases := []struct { 103 Name string 104 Value *graphql.AuthInput 105 ExpectedValid bool 106 }{ 107 { 108 Name: "ExpectedValid", 109 Value: &auth, 110 ExpectedValid: true, 111 }, 112 { 113 Name: "ExpectedValid - nil", 114 Value: nil, 115 ExpectedValid: true, 116 }, 117 { 118 Name: "Invalid - Nested validation error", 119 Value: &graphql.AuthInput{Credential: &graphql.CredentialDataInput{}}, 120 ExpectedValid: false, 121 }, 122 } 123 124 for _, testCase := range testCases { 125 t.Run(testCase.Name, func(t *testing.T) { 126 //GIVEN 127 sut := fixValidWebhookInput(inputvalidationtest.ValidURL) 128 sut.Auth = testCase.Value 129 // WHEN 130 err := sut.Validate() 131 // THEN 132 if testCase.ExpectedValid { 133 require.NoError(t, err) 134 } else { 135 require.Error(t, err) 136 } 137 }) 138 } 139 } 140 141 func TestWebhookInput_Validate_CorrelationIDKey(t *testing.T) { 142 testCases := []struct { 143 Name string 144 Value *string 145 ExpectedValid bool 146 }{ 147 { 148 Name: "ExpectedValid", 149 Value: stringPtr(correlation.RequestIDHeaderKey), 150 ExpectedValid: true, 151 }, 152 { 153 Name: "Empty", 154 Value: stringPtr(inputvalidationtest.EmptyString), 155 ExpectedValid: true, 156 }, 157 { 158 Name: "Nil", 159 Value: nil, 160 ExpectedValid: true, 161 }, 162 } 163 164 for _, testCase := range testCases { 165 t.Run(testCase.Name, func(t *testing.T) { 166 //GIVEN 167 sut := fixValidWebhookInput(inputvalidationtest.ValidURL) 168 sut.CorrelationIDKey = testCase.Value 169 // WHEN 170 err := sut.Validate() 171 // THEN 172 if testCase.ExpectedValid { 173 require.NoError(t, err) 174 } else { 175 require.Error(t, err) 176 } 177 }) 178 } 179 } 180 181 func TestWebhookInput_Validate_Mode(t *testing.T) { 182 testCases := []struct { 183 Name string 184 Value *graphql.WebhookMode 185 Type *graphql.WebhookType 186 ExpectedValid bool 187 }{ 188 { 189 Name: "ExpectedValidMode", 190 Value: webhookModePtr(graphql.WebhookModeSync), 191 ExpectedValid: true, 192 }, 193 { 194 Name: "ExpectedValidSyncModeAndConfigurationChangedType", 195 Value: webhookModePtr(graphql.WebhookModeSync), 196 Type: webhookTypePtr(graphql.WebhookTypeConfigurationChanged), 197 ExpectedValid: true, 198 }, 199 { 200 Name: "ExpectedValidAsyncCallbackModeAndConfigurationChangedType", 201 Value: webhookModePtr(graphql.WebhookModeAsyncCallback), 202 Type: webhookTypePtr(graphql.WebhookTypeConfigurationChanged), 203 ExpectedValid: true, 204 }, 205 { 206 Name: "ExpectedValidAsyncCallbackModeAndAppTntMappingType", 207 Value: webhookModePtr(graphql.WebhookModeAsyncCallback), 208 Type: webhookTypePtr(graphql.WebhookTypeApplicationTenantMapping), 209 ExpectedValid: true, 210 }, 211 { 212 Name: "ExpectedValidSyncModeAndFormationLifecycleType", 213 Value: webhookModePtr(graphql.WebhookModeSync), 214 Type: webhookTypePtr(graphql.WebhookTypeFormationLifecycle), 215 ExpectedValid: true, 216 }, 217 { 218 Name: "ExpectedInvalidAsyncModeAndConfigurationChangedType", 219 Value: webhookModePtr(graphql.WebhookModeAsync), 220 Type: webhookTypePtr(graphql.WebhookTypeConfigurationChanged), 221 ExpectedValid: false, 222 }, 223 { 224 Name: "ExpectedInvalidAsyncModeAndAppTntMappingType", 225 Value: webhookModePtr(graphql.WebhookModeAsync), 226 Type: webhookTypePtr(graphql.WebhookTypeApplicationTenantMapping), 227 ExpectedValid: false, 228 }, 229 { 230 Name: "ExpectedInvalidAsyncCallbackModeAndRegisterAppType", 231 Value: webhookModePtr(graphql.WebhookModeAsyncCallback), 232 Type: webhookTypePtr(graphql.WebhookTypeRegisterApplication), 233 ExpectedValid: false, 234 }, 235 { 236 Name: "ExpectedValidAsyncCallbackModeAndFormationLifecycleType", 237 Value: webhookModePtr(graphql.WebhookModeAsyncCallback), 238 Type: webhookTypePtr(graphql.WebhookTypeFormationLifecycle), 239 ExpectedValid: true, 240 }, 241 { 242 Name: "Empty", 243 Value: webhookModePtr(inputvalidationtest.EmptyString), 244 ExpectedValid: true, 245 }, 246 { 247 Name: "Nil", 248 Value: nil, 249 ExpectedValid: true, 250 }, 251 { 252 Name: "Invalid - Not enum", 253 Value: webhookModePtr("invalid"), 254 ExpectedValid: false, 255 }, 256 } 257 258 for _, testCase := range testCases { 259 t.Run(testCase.Name, func(t *testing.T) { 260 //GIVEN 261 sut := fixValidWebhookInput(inputvalidationtest.ValidURL) 262 sut.Mode = testCase.Value 263 if testCase.Type != nil { 264 sut.Type = *testCase.Type 265 } 266 // WHEN 267 err := sut.Validate() 268 // THEN 269 if testCase.ExpectedValid { 270 require.NoError(t, err) 271 } else { 272 require.Error(t, err) 273 } 274 }) 275 } 276 } 277 278 func TestWebhookInput_Validate_RetryInterval(t *testing.T) { 279 testCases := []struct { 280 Name string 281 Value *int 282 ExpectedValid bool 283 }{ 284 { 285 Name: "ExpectedValid", 286 Value: intPtr(120), 287 ExpectedValid: true, 288 }, 289 { 290 Name: "Empty", 291 Value: intPtr(0), 292 ExpectedValid: true, 293 }, 294 { 295 Name: "Nil", 296 Value: nil, 297 ExpectedValid: true, 298 }, 299 { 300 Name: "Invalid - negative number", 301 Value: intPtr(-1), 302 ExpectedValid: false, 303 }, 304 } 305 306 for _, testCase := range testCases { 307 t.Run(testCase.Name, func(t *testing.T) { 308 //GIVEN 309 sut := fixValidWebhookInput(inputvalidationtest.ValidURL) 310 sut.RetryInterval = testCase.Value 311 // WHEN 312 err := sut.Validate() 313 // THEN 314 if testCase.ExpectedValid { 315 require.NoError(t, err) 316 } else { 317 require.Error(t, err) 318 } 319 }) 320 } 321 } 322 323 func TestWebhookInput_Validate_Timeout(t *testing.T) { 324 testCases := []struct { 325 Name string 326 Value *int 327 ExpectedValid bool 328 }{ 329 { 330 Name: "ExpectedValid", 331 Value: intPtr(120), 332 ExpectedValid: true, 333 }, 334 { 335 Name: "Empty", 336 Value: intPtr(0), 337 ExpectedValid: true, 338 }, 339 { 340 Name: "Nil", 341 Value: nil, 342 ExpectedValid: true, 343 }, 344 { 345 Name: "Invalid - negative number", 346 Value: intPtr(-1), 347 ExpectedValid: false, 348 }, 349 } 350 351 for _, testCase := range testCases { 352 t.Run(testCase.Name, func(t *testing.T) { 353 //GIVEN 354 sut := fixValidWebhookInput(inputvalidationtest.ValidURL) 355 sut.Timeout = testCase.Value 356 // WHEN 357 err := sut.Validate() 358 // THEN 359 if testCase.ExpectedValid { 360 require.NoError(t, err) 361 } else { 362 require.Error(t, err) 363 } 364 }) 365 } 366 } 367 368 func TestWebhookInput_Validate_URLTemplate(t *testing.T) { 369 testCases := []struct { 370 Name string 371 Value *string 372 ExpectedValid bool 373 }{ 374 { 375 Name: "ExpectedValid", 376 Value: stringPtr(`{ 377 "method": "POST", 378 "path": "https://my-int-system/api/v1/{{.Application.ID}}/pairing" 379 }`), 380 ExpectedValid: true, 381 }, 382 { 383 Name: "InvalidURL", 384 Value: stringPtr(`{ 385 "method": "POST", 386 "path": "abc" 387 }`), 388 ExpectedValid: false, 389 }, 390 { 391 Name: "MissingPath", 392 Value: stringPtr(`{ 393 "method": "POST" 394 }`), 395 ExpectedValid: false, 396 }, 397 { 398 Name: "MissingMethod", 399 Value: stringPtr(`{ 400 "path": "https://my-int-system/api/v1/{{.Application.ID}}/pairing" 401 }`), 402 ExpectedValid: false, 403 }, 404 { 405 Name: "MethodNotAllowed", 406 Value: stringPtr(`{ 407 "method": "HEAD", 408 "path": "https://my-int-system/api/v1/{{.Application.ID}}/pairing" 409 }`), 410 ExpectedValid: false, 411 }, 412 { 413 Name: "Empty", 414 Value: stringPtr(""), 415 ExpectedValid: false, // it should not be valid due to the fact that we also discard the legacy URL from the webhook in the test below 416 }, 417 { 418 Name: "Nil", 419 Value: nil, 420 ExpectedValid: false, // it should not be valid due to the fact that we also discard the legacy URL from the webhook in the test below 421 }, 422 { 423 Name: "Invalid - contains unexpected property", 424 Value: stringPtr("https://my-int-system/api/v1/{{.Application.Group}}/pairing"), 425 ExpectedValid: false, 426 }, 427 } 428 429 for _, testCase := range testCases { 430 t.Run(testCase.Name, func(t *testing.T) { 431 //GIVEN 432 sut := fixValidWebhookInput(inputvalidationtest.ValidURL) 433 sut.URL = nil 434 sut.URLTemplate = testCase.Value 435 // WHEN 436 err := sut.Validate() 437 // THEN 438 if testCase.ExpectedValid { 439 require.NoError(t, err) 440 } else { 441 require.Error(t, err) 442 } 443 }) 444 } 445 } 446 447 func TestWebhookInput_Validate_InputTemplate(t *testing.T) { 448 testCases := []struct { 449 Name string 450 Value *string 451 ExpectedValid bool 452 }{ 453 { 454 Name: "ExpectedValid", 455 Value: stringPtr(`{ 456 "app_id": "{{.Application.ID}}", 457 "app_name": "{{.Application.Name}}" 458 }`), 459 ExpectedValid: true, 460 }, 461 { 462 Name: "Empty", 463 Value: stringPtr(""), 464 ExpectedValid: false, 465 }, 466 { 467 Name: "Nil", 468 Value: nil, 469 ExpectedValid: true, 470 }, 471 { 472 Name: "Invalid - contains unexpected property", 473 Value: stringPtr(`{ 474 "app_id": "{{.Application.ID}}", 475 "app_name": "{{.Application.Group}}" 476 }`), 477 ExpectedValid: false, 478 }, 479 } 480 481 for _, testCase := range testCases { 482 t.Run(testCase.Name, func(t *testing.T) { 483 //GIVEN 484 sut := fixValidWebhookInput(inputvalidationtest.ValidURL) 485 sut.InputTemplate = testCase.Value 486 // WHEN 487 err := sut.Validate() 488 // THEN 489 if testCase.ExpectedValid { 490 require.NoError(t, err) 491 } else { 492 require.Error(t, err) 493 } 494 }) 495 } 496 } 497 498 func TestWebhookInput_Validate_HeaderTemplate(t *testing.T) { 499 testCases := []struct { 500 Name string 501 Value *string 502 ExpectedValid bool 503 }{ 504 { 505 Name: "ExpectedValid", 506 Value: stringPtr(`{"Content-Type":["application/json"],"client_user":["{{.Headers.User_id}}"]}`), 507 ExpectedValid: true, 508 }, 509 { 510 Name: "Empty", 511 Value: stringPtr(""), 512 ExpectedValid: false, 513 }, 514 { 515 Name: "Nil", 516 Value: nil, 517 ExpectedValid: true, 518 }, 519 { 520 Name: "Invalid - contains unexpected property", 521 Value: stringPtr(`{"Content-Type":["application/json"],"client_user":["{{.Body.Group}}"]}`), 522 ExpectedValid: false, 523 }, 524 } 525 526 for _, testCase := range testCases { 527 t.Run(testCase.Name, func(t *testing.T) { 528 //GIVEN 529 sut := fixValidWebhookInput(inputvalidationtest.ValidURL) 530 sut.HeaderTemplate = testCase.Value 531 // WHEN 532 err := sut.Validate() 533 // THEN 534 if testCase.ExpectedValid { 535 require.NoError(t, err) 536 } else { 537 require.Error(t, err) 538 } 539 }) 540 } 541 } 542 543 func TestWebhookInput_Validate_OutputTemplate(t *testing.T) { 544 testCases := []struct { 545 Name string 546 Value *string 547 ExpectedValid bool 548 }{ 549 { 550 Name: "ExpectedValid", 551 Value: stringPtr(`{ 552 "location": "{{.Headers.Location}}", 553 "success_status_code": 202, 554 "error": "{{.Body.error}}" 555 }`), 556 ExpectedValid: true, 557 }, 558 { 559 Name: "ExpectedValid - missing location when SYNC mode", 560 Value: stringPtr(`{ 561 "success_status_code": 202, 562 "error": "{{.Body.error}}" 563 }`), 564 ExpectedValid: true, 565 }, 566 { 567 Name: "Invalid - missing success status code", 568 Value: stringPtr(`{ 569 "location": "{{.Headers.Location}}", 570 "error": "{{.Body.error}}" 571 }`), 572 ExpectedValid: false, 573 }, 574 { 575 Name: "Invalid - missing error", 576 Value: stringPtr(`{ 577 "location": "{{.Headers.Location}}", 578 "success_status_code": 202 579 }`), 580 ExpectedValid: false, 581 }, 582 { 583 Name: "Empty", 584 Value: stringPtr(""), 585 ExpectedValid: false, 586 }, 587 { 588 Name: "Nil", 589 Value: nil, 590 ExpectedValid: false, 591 }, 592 } 593 594 for _, testCase := range testCases { 595 t.Run(testCase.Name, func(t *testing.T) { 596 //GIVEN 597 sut := fixValidWebhookInput(inputvalidationtest.ValidURL) 598 sut.InputTemplate = nil 599 sut.OutputTemplate = testCase.Value 600 // WHEN 601 err := sut.Validate() 602 // THEN 603 if testCase.ExpectedValid { 604 require.NoError(t, err) 605 } else { 606 require.Error(t, err) 607 } 608 }) 609 } 610 } 611 612 func TestWebhookInput_Validate_StatusTemplate(t *testing.T) { 613 testCases := []struct { 614 Name string 615 Value *string 616 ExpectedValid bool 617 }{ 618 { 619 Name: "ExpectedValid", 620 Value: stringPtr(`{ 621 "status": "{{.Body.status}}", 622 "success_status_code": 200, 623 "success_status_identifier": "SUCCESS", 624 "in_progress_status_identifier": "IN_PROGRESS", 625 "failed_status_identifier": "FAILED", 626 "error": "{{.Body.error}}" 627 }`), 628 ExpectedValid: true, 629 }, 630 { 631 Name: "Invalid - missing error", 632 Value: stringPtr(`{ 633 "status": "{{.Body.status}}", 634 "success_status_code": 200, 635 "success_status_identifier": "SUCCESS", 636 "in_progress_status_identifier": "IN_PROGRESS", 637 "failed_status_identifier": "FAILED" 638 }`), 639 ExpectedValid: false, 640 }, 641 { 642 Name: "Invalid - missing status", 643 Value: stringPtr(`{ 644 "success_status_code": 200, 645 "success_status_identifier": "SUCCESS", 646 "in_progress_status_identifier": "IN_PROGRESS", 647 "failed_status_identifier": "FAILED", 648 "error": "{{.Body.error}}" 649 }`), 650 ExpectedValid: false, 651 }, 652 { 653 Name: "Invalid - missing success status code", 654 Value: stringPtr(`{ 655 "status": "{{.Body.status}}", 656 "success_status_identifier": "SUCCESS", 657 "in_progress_status_identifier": "IN_PROGRESS", 658 "failed_status_identifier": "FAILED", 659 "error": "{{.Body.error}}" 660 }`), 661 ExpectedValid: false, 662 }, 663 { 664 Name: "Invalid - missing success status identifier", 665 Value: stringPtr(`{ 666 "status": "{{.Body.status}}", 667 "success_status_code": 200, 668 "in_progress_status_identifier": "IN_PROGRESS", 669 "failed_status_identifier": "FAILED", 670 "error": "{{.Body.error}}" 671 }`), 672 ExpectedValid: false, 673 }, 674 { 675 Name: "Invalid - missing in progress status identifier", 676 Value: stringPtr(`{ 677 "status": "{{.Body.status}}", 678 "success_status_code": 200, 679 "success_status_identifier": "SUCCESS", 680 "failed_status_identifier": "FAILED", 681 "error": "{{.Body.error}}" 682 }`), 683 ExpectedValid: false, 684 }, 685 { 686 Name: "Invalid - missing failed status identifier", 687 Value: stringPtr(`{ 688 "status": "{{.Body.status}}", 689 "success_status_code": 200, 690 "success_status_identifier": "SUCCESS", 691 "in_progress_status_identifier": "IN_PROGRESS", 692 "error": "{{.Body.error}}" 693 }`), 694 ExpectedValid: false, 695 }, 696 { 697 Name: "Empty", 698 Value: stringPtr(""), 699 ExpectedValid: false, 700 }, 701 { 702 Name: "Nil", 703 Value: nil, 704 ExpectedValid: false, 705 }, 706 } 707 708 for _, testCase := range testCases { 709 t.Run(testCase.Name, func(t *testing.T) { 710 //GIVEN 711 sut := fixValidWebhookInput(inputvalidationtest.ValidURL) 712 sut.Mode = webhookModePtr(graphql.WebhookModeAsync) 713 sut.StatusTemplate = testCase.Value 714 // WHEN 715 err := sut.Validate() 716 // THEN 717 if testCase.ExpectedValid { 718 require.NoError(t, err) 719 } else { 720 require.Error(t, err) 721 } 722 }) 723 } 724 } 725 726 func TestWebhookInput_Validate_BothURLAndURLTemplate(t *testing.T) { 727 sut := fixValidWebhookInput(inputvalidationtest.ValidURL) 728 sut.URL = stringPtr("https://my-int-system/api/v1/123/pairing") 729 sut.URLTemplate = stringPtr("https://my-int-system/api/v1/{{.Application.ID}}/pairing") 730 // WHEN 731 err := sut.Validate() 732 // THEN 733 require.Error(t, err) 734 } 735 736 func TestWebhookInput_Validate_AsyncWebhook_MissingLocationInOutputTemplate_ShouldReturnError(t *testing.T) { 737 sut := fixValidWebhookInput(inputvalidationtest.ValidURL) 738 sut.Mode = webhookModePtr(graphql.WebhookModeAsync) 739 sut.OutputTemplate = stringPtr(`{ 740 "success_status_code": 202, 741 "error": "{{.Body.error}}" 742 }`) 743 // WHEN 744 err := sut.Validate() 745 // THEN 746 require.Error(t, err) 747 } 748 749 func TestWebhookInput_Validate_MissingOutputTemplateForCertainTypes(t *testing.T) { 750 webhookMode := graphql.WebhookModeSync 751 testCases := []struct { 752 Name string 753 Input graphql.WebhookInput 754 ExpectedValid bool 755 }{ 756 { 757 Name: "Success when missing for type: OPEN_RESOURCE_DISCOVERY", 758 ExpectedValid: true, 759 Input: graphql.WebhookInput{ 760 Type: graphql.WebhookTypeOpenResourceDiscovery, 761 Mode: &webhookMode, 762 URL: str.Ptr(inputvalidationtest.ValidURL), 763 }, 764 }, 765 { 766 Name: "Success when missing for type: CONFIGURATION_CHANGED", 767 ExpectedValid: true, 768 Input: graphql.WebhookInput{ 769 Type: graphql.WebhookTypeConfigurationChanged, 770 Mode: &webhookMode, 771 URL: str.Ptr(inputvalidationtest.ValidURL), 772 }, 773 }, 774 { 775 Name: "Fails when missing for type: UNREGISTER_APPLICATION", 776 ExpectedValid: false, 777 Input: graphql.WebhookInput{ 778 Type: graphql.WebhookTypeUnregisterApplication, 779 Mode: &webhookMode, 780 URL: str.Ptr(inputvalidationtest.ValidURL), 781 }, 782 }, 783 { 784 Name: "Fails when missing for type: REGISTER_APPLICATION", 785 ExpectedValid: false, 786 Input: graphql.WebhookInput{ 787 Type: graphql.WebhookTypeRegisterApplication, 788 Mode: &webhookMode, 789 URL: str.Ptr(inputvalidationtest.ValidURL), 790 }, 791 }, 792 } 793 794 for _, testCase := range testCases { 795 t.Run(testCase.Name, func(t *testing.T) { 796 err := testCase.Input.Validate() 797 if testCase.ExpectedValid { 798 require.NoError(t, err) 799 } else { 800 require.Error(t, err) 801 } 802 }) 803 } 804 } 805 806 func fixValidWebhookInput(url string) graphql.WebhookInput { 807 template := `{}` 808 outputTemplate := `{ 809 "location": "{{.Headers.Location}}", 810 "success_status_code": 202, 811 "error": "{{.Body.error}}" 812 }` 813 webhookMode := graphql.WebhookModeSync 814 webhookInput := graphql.WebhookInput{ 815 Type: graphql.WebhookTypeUnregisterApplication, 816 Mode: &webhookMode, 817 InputTemplate: &template, 818 HeaderTemplate: &template, 819 OutputTemplate: &outputTemplate, 820 } 821 822 if url != "" { 823 webhookInput.URL = &url 824 } else { 825 webhookInput.URLTemplate = stringPtr(`{ 826 "method": "POST", 827 "path": "https://my-int-system/api/v1/{{.Application.ID}}/pairing" 828 }`) 829 } 830 831 return webhookInput 832 } 833 834 func stringPtr(s string) *string { 835 return &s 836 } 837 838 func intPtr(n int) *int { 839 return &n 840 } 841 842 func webhookModePtr(mode graphql.WebhookMode) *graphql.WebhookMode { 843 return &mode 844 } 845 846 func webhookTypePtr(whType graphql.WebhookType) *graphql.WebhookType { 847 return &whType 848 }