Skip to content

Commit 03f3c29

Browse files
committed
.
1 parent 464c982 commit 03f3c29

File tree

5 files changed

+374
-342
lines changed

5 files changed

+374
-342
lines changed

README.md

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ Whatever you decide is best for your use case, **Lambda API** is there to suppor
205205
- [TypeScript Support](#typescript-support)
206206
- [Contributions](#contributions)
207207
- [Are you using Lambda API?](#are-you-using-lambda-api)
208+
- [Handling Multiple Request Sources](#handling-multiple-request-sources)
208209

209210
## Installation
210211

@@ -1564,3 +1565,158 @@ Contributions, ideas and bug reports are welcome and greatly appreciated. Please
15641565
## Are you using Lambda API?
15651566

15661567
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

Comments
 (0)