Handling Nested Requests
This example demonstrates how Express-Cargo can populate nested Requests, allowing you to map complex, structured request data into a single, well-organized object.
1. Define Your Requests
In this scenario, we'll define two classes: UserInfoRequest and OrderRequest. The UserInfoRequest class pulls user details from the request body and an authentication token from the headers.
UserInfoRequest – Maps user details from the request body and extracts the authorization token from headers.
// user.request.ts
import { body, header, optional, prefix, transform } from 'express-cargo'
export class UserInfoRequest {
@body('name')
name!: string
@body('email')
@prefix('user-')
email!: string
@body('age')
@optional()
age?: number
// Extract the token from the Authorization header.
@header('authorization')
@transform((value: string) => {
if (value.startsWith('Bearer ')) {
return value.substring(7);
}
return ''
})
authorization!: string
}
OrderRequest – Represents an order request, including a nested UserInfoRequest.
// order.request.ts
import { body, min, max } from 'express-cargo'
import { UserInfoRequest } from './user.Request'
export class OrderRequest {
@body('productId')
productId!: string
@body('quantity')
@min(1)
@max(10)
quantity!: number
@body('user')
user!: UserInfoRequest
}
In UserInfoRequest, we use the @header decorator on the authorization property to get the value from the Authorization header. Then, the @transform decorator extracts just the token value, stripping the "Bearer " prefix.
2. Use in an Express Route
Simply apply the bindingCargo middleware to your route with the top-level Request, OrderRequest. The middleware will handle all the binding logic for you.
router.post('/orders', bindingCargo(OrderRequest), (req, res) => {
const order = getCargo<OrderRequest>(req)
if (order) {
console.log(`Processing order for product: ${order.productId}`)
console.log(`User name: ${order.user.name}`)
console.log(`Auth token: ${order.user.authorization}`)
// You can now use the auth token for validation or other logic.
res.json({ message: 'Order received', order })
}
})
3. Example Request
This route will successfully process a request that has both a body and an Authorization header.
-
Request Body:
{
"productId": "SKU-456",
"quantity": 5,
"user": {
"name": "Jane Doe",
"email": "user-jane@example.com"
}
} -
Request Headers:
Authorization: Bearer my-auth-token-12345
When processed, getCargo(req) will return a single OrderRequest object that contains all the data, with the authorization property correctly populated from the header. This demonstrates how Express-Cargo elegantly unifies multiple data sources into one clean object.
4. Example Result
Final bound OrderRequest object:
{
"productId": "SKU-456",
"quantity": 5,
"user": {
"name": "Jane Doe",
"email": "user-jane@example.com",
"authorization": "my-auth-token-12345"
}
}