@@ -353,6 +353,363 @@ testCase('route with unknown unions', ROUTE_WITH_UNKNOWN_UNIONS, {
353
353
} ,
354
354
} ) ;
355
355
356
+ const ROUTE_WITH_PATH_PARAMS_IN_UNION_NOT_FIRST = `
357
+ import * as t from 'io-ts';
358
+ import * as h from '@api-ts/io-ts-http';
359
+
360
+ export const route = h.httpRoute({
361
+ path: '/internal/api/policy/v1/{applicationName}/touchpoints/{touchpoint}/rules/evaluation',
362
+ method: 'POST',
363
+ request: t.union([
364
+ h.httpRequest({
365
+ body: { emptyRequest: t.boolean }
366
+ }),
367
+ h.httpRequest({
368
+ params: {
369
+ applicationName: t.string,
370
+ touchpoint: t.string,
371
+ },
372
+ body: { requestWithParams: t.string }
373
+ }),
374
+ ]),
375
+ response: {
376
+ 200: t.string,
377
+ },
378
+ });
379
+ ` ;
380
+
381
+ testCase (
382
+ 'route with path params in union second schema (regression test)' ,
383
+ ROUTE_WITH_PATH_PARAMS_IN_UNION_NOT_FIRST ,
384
+ {
385
+ info : {
386
+ title : 'Test' ,
387
+ version : '1.0.0' ,
388
+ } ,
389
+ openapi : '3.0.3' ,
390
+ paths : {
391
+ '/internal/api/policy/v1/{applicationName}/touchpoints/{touchpoint}/rules/evaluation' :
392
+ {
393
+ post : {
394
+ parameters : [
395
+ {
396
+ in : 'path' ,
397
+ name : 'applicationName' ,
398
+ required : true ,
399
+ schema : { type : 'string' } ,
400
+ } ,
401
+ {
402
+ in : 'path' ,
403
+ name : 'touchpoint' ,
404
+ required : true ,
405
+ schema : { type : 'string' } ,
406
+ } ,
407
+ ] ,
408
+ requestBody : {
409
+ content : {
410
+ 'application/json' : {
411
+ schema : {
412
+ oneOf : [
413
+ {
414
+ properties : {
415
+ emptyRequest : { type : 'boolean' } ,
416
+ } ,
417
+ required : [ 'emptyRequest' ] ,
418
+ type : 'object' ,
419
+ } ,
420
+ {
421
+ properties : {
422
+ requestWithParams : { type : 'string' } ,
423
+ } ,
424
+ required : [ 'requestWithParams' ] ,
425
+ type : 'object' ,
426
+ } ,
427
+ ] ,
428
+ } ,
429
+ } ,
430
+ } ,
431
+ } ,
432
+ responses : {
433
+ '200' : {
434
+ description : 'OK' ,
435
+ content : {
436
+ 'application/json' : {
437
+ schema : {
438
+ type : 'string' ,
439
+ } ,
440
+ } ,
441
+ } ,
442
+ } ,
443
+ } ,
444
+ } ,
445
+ } ,
446
+ } ,
447
+ components : {
448
+ schemas : { } ,
449
+ } ,
450
+ } ,
451
+ ) ;
452
+
453
+ const ROUTE_WITH_PATH_PARAMS_ONLY_IN_THIRD_SCHEMA = `
454
+ import * as t from 'io-ts';
455
+ import * as h from '@api-ts/io-ts-http';
456
+
457
+ export const route = h.httpRoute({
458
+ path: '/api/{userId}/posts/{postId}',
459
+ method: 'GET',
460
+ request: t.union([
461
+ // First: empty request
462
+ h.httpRequest({}),
463
+ // Second: only query params
464
+ h.httpRequest({
465
+ query: { filter: t.string }
466
+ }),
467
+ // Third: has the path params
468
+ h.httpRequest({
469
+ params: {
470
+ userId: t.string,
471
+ postId: t.string,
472
+ },
473
+ query: { details: t.boolean }
474
+ }),
475
+ ]),
476
+ response: {
477
+ 200: t.string,
478
+ },
479
+ });
480
+ ` ;
481
+
482
+ testCase (
483
+ 'route with path params only in third schema' ,
484
+ ROUTE_WITH_PATH_PARAMS_ONLY_IN_THIRD_SCHEMA ,
485
+ {
486
+ info : {
487
+ title : 'Test' ,
488
+ version : '1.0.0' ,
489
+ } ,
490
+ openapi : '3.0.3' ,
491
+ paths : {
492
+ '/api/{userId}/posts/{postId}' : {
493
+ get : {
494
+ parameters : [
495
+ {
496
+ in : 'query' ,
497
+ name : 'union' ,
498
+ required : true ,
499
+ explode : true ,
500
+ style : 'form' ,
501
+ schema : {
502
+ oneOf : [
503
+ {
504
+ properties : { filter : { type : 'string' } } ,
505
+ required : [ 'filter' ] ,
506
+ type : 'object' ,
507
+ } ,
508
+ {
509
+ properties : { details : { type : 'boolean' } } ,
510
+ required : [ 'details' ] ,
511
+ type : 'object' ,
512
+ } ,
513
+ ] ,
514
+ } ,
515
+ } ,
516
+ { in : 'path' , name : 'userId' , required : true , schema : { type : 'string' } } ,
517
+ { in : 'path' , name : 'postId' , required : true , schema : { type : 'string' } } ,
518
+ ] ,
519
+ responses : {
520
+ '200' : {
521
+ description : 'OK' ,
522
+ content : {
523
+ 'application/json' : {
524
+ schema : {
525
+ type : 'string' ,
526
+ } ,
527
+ } ,
528
+ } ,
529
+ } ,
530
+ } ,
531
+ } ,
532
+ } ,
533
+ } ,
534
+ components : {
535
+ schemas : { } ,
536
+ } ,
537
+ } ,
538
+ ) ;
539
+
540
+ const ROUTE_WITH_FULLY_DEFINED_PARAMS = `
541
+ import * as t from 'io-ts';
542
+ import * as h from '@api-ts/io-ts-http';
543
+
544
+ const AddressBookConnectionSides = t.union([t.literal('send'), t.literal('receive')]);
545
+
546
+ /**
547
+ * Create policy evaluation definition
548
+ * @operationId v1.post.policy.evaluation.definition
549
+ * @tag Policy Builder
550
+ * @private
551
+ */
552
+ export const route = h.httpRoute({
553
+ path: '/internal/api/policy/v1/{applicationName}/touchpoints/{touchpoint}/rules/evaluations',
554
+ method: 'POST',
555
+ request: t.union([
556
+ h.httpRequest({
557
+ params: {
558
+ applicationName: t.string,
559
+ touchpoint: t.string,
560
+ },
561
+ body: t.type({
562
+ approvalRequestId: t.string,
563
+ counterPartyId: t.string,
564
+ description: h.optional(t.string),
565
+ enterpriseId: t.string,
566
+ grossAmount: h.optional(t.number),
567
+ idempotencyKey: t.string,
568
+ isFirstTimeCounterParty: t.boolean,
569
+ isMutualConnection: t.boolean,
570
+ netAmount: h.optional(t.number),
571
+ settlementId: t.string,
572
+ userId: t.string,
573
+ walletId: t.string,
574
+ })
575
+ }),
576
+ h.httpRequest({
577
+ params: {
578
+ applicationName: t.string,
579
+ touchpoint: t.string,
580
+ },
581
+ body: t.type({
582
+ connectionId: t.string,
583
+ description: h.optional(t.string),
584
+ enterpriseId: t.string,
585
+ idempotencyKey: t.string,
586
+ side: AddressBookConnectionSides,
587
+ walletId: t.string,
588
+ })
589
+ }),
590
+ ]),
591
+ response: {
592
+ 200: t.string,
593
+ },
594
+ });
595
+ ` ;
596
+
597
+ testCase (
598
+ 'union request with consistently defined path parameters' ,
599
+ ROUTE_WITH_FULLY_DEFINED_PARAMS ,
600
+ {
601
+ info : {
602
+ title : 'Test' ,
603
+ version : '1.0.0' ,
604
+ } ,
605
+ openapi : '3.0.3' ,
606
+ paths : {
607
+ '/internal/api/policy/v1/{applicationName}/touchpoints/{touchpoint}/rules/evaluations' :
608
+ {
609
+ post : {
610
+ summary : 'Create policy evaluation definition' ,
611
+ operationId : 'v1.post.policy.evaluation.definition' ,
612
+ tags : [ 'Policy Builder' ] ,
613
+ 'x-internal' : true ,
614
+ parameters : [
615
+ {
616
+ in : 'path' ,
617
+ name : 'applicationName' ,
618
+ required : true ,
619
+ schema : { type : 'string' } ,
620
+ } ,
621
+ {
622
+ in : 'path' ,
623
+ name : 'touchpoint' ,
624
+ required : true ,
625
+ schema : { type : 'string' } ,
626
+ } ,
627
+ ] ,
628
+ requestBody : {
629
+ content : {
630
+ 'application/json' : {
631
+ schema : {
632
+ oneOf : [
633
+ {
634
+ type : 'object' ,
635
+ properties : {
636
+ approvalRequestId : { type : 'string' } ,
637
+ counterPartyId : { type : 'string' } ,
638
+ description : { type : 'string' } ,
639
+ enterpriseId : { type : 'string' } ,
640
+ grossAmount : { type : 'number' } ,
641
+ idempotencyKey : { type : 'string' } ,
642
+ isFirstTimeCounterParty : { type : 'boolean' } ,
643
+ isMutualConnection : { type : 'boolean' } ,
644
+ netAmount : { type : 'number' } ,
645
+ settlementId : { type : 'string' } ,
646
+ userId : { type : 'string' } ,
647
+ walletId : { type : 'string' } ,
648
+ } ,
649
+ required : [
650
+ 'approvalRequestId' ,
651
+ 'counterPartyId' ,
652
+ 'enterpriseId' ,
653
+ 'idempotencyKey' ,
654
+ 'isFirstTimeCounterParty' ,
655
+ 'isMutualConnection' ,
656
+ 'settlementId' ,
657
+ 'userId' ,
658
+ 'walletId' ,
659
+ ] ,
660
+ } ,
661
+ {
662
+ type : 'object' ,
663
+ properties : {
664
+ connectionId : { type : 'string' } ,
665
+ description : { type : 'string' } ,
666
+ enterpriseId : { type : 'string' } ,
667
+ idempotencyKey : { type : 'string' } ,
668
+ side : {
669
+ $ref : '#/components/schemas/AddressBookConnectionSides' ,
670
+ } ,
671
+ walletId : { type : 'string' } ,
672
+ } ,
673
+ required : [
674
+ 'connectionId' ,
675
+ 'enterpriseId' ,
676
+ 'idempotencyKey' ,
677
+ 'side' ,
678
+ 'walletId' ,
679
+ ] ,
680
+ } ,
681
+ ] ,
682
+ } ,
683
+ } ,
684
+ } ,
685
+ } ,
686
+ responses : {
687
+ '200' : {
688
+ description : 'OK' ,
689
+ content : {
690
+ 'application/json' : {
691
+ schema : {
692
+ type : 'string' ,
693
+ } ,
694
+ } ,
695
+ } ,
696
+ } ,
697
+ } ,
698
+ } ,
699
+ } ,
700
+ } ,
701
+ components : {
702
+ schemas : {
703
+ AddressBookConnectionSides : {
704
+ enum : [ 'send' , 'receive' ] ,
705
+ title : 'AddressBookConnectionSides' ,
706
+ type : 'string' ,
707
+ } ,
708
+ } ,
709
+ } ,
710
+ } ,
711
+ ) ;
712
+
356
713
const ROUTE_WITH_DUPLICATE_HEADERS = `
357
714
import * as t from 'io-ts';
358
715
import * as h from '@api-ts/io-ts-http';
0 commit comments