@@ -205,6 +205,7 @@ Whatever you decide is best for your use case, **Lambda API** is there to suppor
205
205
- [ TypeScript Support] ( #typescript-support )
206
206
- [ Contributions] ( #contributions )
207
207
- [ Are you using Lambda API?] ( #are-you-using-lambda-api )
208
+ - [ Handling Multiple Request Sources] ( #handling-multiple-request-sources )
208
209
209
210
## Installation
210
211
@@ -1564,3 +1565,158 @@ Contributions, ideas and bug reports are welcome and greatly appreciated. Please
1564
1565
## Are you using Lambda API?
1565
1566
1566
1567
If you're using Lambda API and finding it useful, hit me up on [ Twitter] ( https://twitter.com/jeremy_daly ) or email me at contact[ at] jeremydaly.com. I'd love to hear your stories, ideas, and even your complaints!
1568
+
1569
+ ## Type-Safe Middleware and Extensions
1570
+
1571
+ Lambda API provides full TypeScript support with type-safe middleware and request/response extensions. Here are the recommended patterns:
1572
+
1573
+ ### Extending Request and Response Types
1574
+
1575
+ ``` typescript
1576
+ declare module ' lambda-api' {
1577
+ interface Request {
1578
+ user? : {
1579
+ id: string ;
1580
+ roles: string [];
1581
+ email: string ;
1582
+ };
1583
+ }
1584
+ }
1585
+
1586
+ function hasUser(req : Request ): req is Request & { user: { id: string ; roles: string []; email: string ; } } {
1587
+ return ' user' in req && req .user !== undefined ;
1588
+ }
1589
+
1590
+ const authMiddleware: Middleware = (req , res , next ) => {
1591
+ req .user = {
1592
+ id: ' 123' ,
1593
+ roles: [' admin' ],
1594
+ email: ' user@example.com'
1595
+ };
1596
+ next ();
1597
+ };
1598
+
1599
+ api .get (' /protected' , (req , res ) => {
1600
+ if (hasUser (req )) {
1601
+ const { id, roles, email } = req .user ;
1602
+ res .json ({ message: ` Hello ${email } ` });
1603
+ }
1604
+ });
1605
+ ```
1606
+
1607
+ ### Response Extensions
1608
+
1609
+ ``` typescript
1610
+ declare module ' lambda-api' {
1611
+ interface Response {
1612
+ sendWithTimestamp? : (data : any ) => void ;
1613
+ }
1614
+ }
1615
+
1616
+ const responseEnhancer: Middleware = (req , res , next ) => {
1617
+ res .sendWithTimestamp = (data : any ) => {
1618
+ res .json ({
1619
+ ... data ,
1620
+ timestamp: Date .now ()
1621
+ });
1622
+ };
1623
+ next ();
1624
+ };
1625
+
1626
+ api .get (' /users' , (req , res ) => {
1627
+ res .sendWithTimestamp ({ name: ' John' });
1628
+ });
1629
+ ```
1630
+
1631
+ ### Using Built-in Auth Property
1632
+
1633
+ ``` typescript
1634
+ interface AuthInfo {
1635
+ userId: string ;
1636
+ roles: string [];
1637
+ type: ' Bearer' | ' Basic' | ' OAuth' | ' Digest' | ' none' ;
1638
+ value: string | null ;
1639
+ }
1640
+
1641
+ function hasAuth(req : Request ): req is Request & { auth: AuthInfo } {
1642
+ return ' auth' in req && req .auth ?.type !== undefined ;
1643
+ }
1644
+
1645
+ const authMiddleware: Middleware = (req , res , next ) => {
1646
+ req .auth = {
1647
+ userId: ' 123' ,
1648
+ roles: [' user' ],
1649
+ type: ' Bearer' ,
1650
+ value: ' token123'
1651
+ };
1652
+ next ();
1653
+ };
1654
+ ```
1655
+
1656
+ ### Type Safety Examples
1657
+
1658
+ ``` typescript
1659
+ function hasUser(req : Request ): req is Request & { user: UserType } {
1660
+ return ' user' in req && req .user !== undefined ;
1661
+ }
1662
+
1663
+ interface QueryParams {
1664
+ limit? : string ;
1665
+ offset? : string ;
1666
+ }
1667
+
1668
+ api .get <UserResponse , APIGatewayContext , QueryParams >(
1669
+ ' /users' ,
1670
+ (req , res ) => {
1671
+ const { limit, offset } = req .query ;
1672
+ res .json ({ /* ... */ });
1673
+ }
1674
+ );
1675
+
1676
+ interface CreateUserBody {
1677
+ name: string ;
1678
+ email: string ;
1679
+ }
1680
+
1681
+ api .post <UserResponse , APIGatewayContext , never , never , CreateUserBody >(
1682
+ ' /users' ,
1683
+ (req , res ) => {
1684
+ const { name, email } = req .body ;
1685
+ res .json ({ /* ... */ });
1686
+ }
1687
+ );
1688
+
1689
+ const withUser = <T >(handler : HandlerFunction <T >): HandlerFunction <T > => {
1690
+ return (req , res ) => {
1691
+ if (! hasUser (req )) {
1692
+ return res .status (401 ).json ({ error: ' Unauthorized' });
1693
+ }
1694
+ return handler (req , res );
1695
+ };
1696
+ };
1697
+
1698
+ api .get (' /protected' , withUser (handler ));
1699
+ ```
1700
+
1701
+ ## Handling Multiple Request Sources
1702
+
1703
+ ``` typescript
1704
+ import { isApiGatewayContext , isApiGatewayV2Context , isAlbContext } from ' lambda-api' ;
1705
+
1706
+ api .get <Response , APIGatewayRequestContext >(' /api-gateway' , (req , res ) => {
1707
+ console .log (req .requestContext .identity );
1708
+ });
1709
+
1710
+ api .get <Response , ALBRequestContext >(' /alb' , (req , res ) => {
1711
+ console .log (req .requestContext .elb );
1712
+ });
1713
+
1714
+ api .get (' /any' , (req , res ) => {
1715
+ if (isApiGatewayContext (req .requestContext )) {
1716
+ console .log (req .requestContext .identity );
1717
+ } else if (isAlbContext (req .requestContext )) {
1718
+ console .log (req .requestContext .elb );
1719
+ }
1720
+ });
1721
+ ```
1722
+
0 commit comments