$expand
$expand follows navigation properties (TypeORM relations) and includes related entities inline in the response.
Basic usage
Given a Product entity with a Category relation:
@Entity()
export class Product {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@ManyToOne(() => Category, (c) => c.products, { nullable: true })
category: Category | null
}Expand the Category navigation property:
curl 'http://localhost:3000/odata/Products?$expand=category'Response:
{
"@odata.context": "http://localhost:3000/odata/$metadata#Products(category())",
"value": [
{
"id": 1,
"name": "Widget",
"category": {
"id": 10,
"name": "Hardware"
}
}
]
}Nested $expand
$expand supports nesting to follow navigation properties multiple levels deep:
# Expand orders, and within each order expand its items
curl 'http://localhost:3000/odata/Customers?$expand=orders($expand=items)'Depth limit
The default maxExpandDepth is 2. Requests exceeding this return HTTP 400. Override per-entity or globally — see Security.
$expand with $select
Combine $expand with $select to limit which fields come back for the expanded entity:
# Only return name from the expanded category
curl 'http://localhost:3000/odata/Products?$expand=category($select=name)'Response:
{
"@odata.context": "...",
"value": [
{
"id": 1,
"name": "Widget",
"category": { "name": "Hardware" }
}
]
}$expand with $top and $skip
For collection navigation properties (one-to-many, many-to-many), paginate the expanded collection:
# Expand first 5 orders for each customer
curl 'http://localhost:3000/odata/Customers?$expand=orders($top=5;$skip=0)'Implementation detail
In v1, $expand pagination is applied in-memory after the JOIN query runs. Results are bounded by the parent maxTop and maxExpandDepth limits, making this safe without unbounded queries.
$expand with $filter
Filter the expanded collection:
# Only expand in-stock products for each category
curl 'http://localhost:3000/odata/Categories?$expand=products($filter=inStock eq true)'Multiple navigations
Expand multiple navigation properties at once:
curl 'http://localhost:3000/odata/Orders?$expand=customer,items'Response:
{
"@odata.context": "...",
"value": [
{
"id": 1,
"customer": { "id": 5, "name": "Acme Corp" },
"items": [{ "id": 10, "productId": 1, "quantity": 3 }]
}
]
}maxExpandDepth
Configure the maximum nesting depth globally or per entity:
// Global: 3 levels of nesting
ODataModule.forRoot({
serviceRoot: '/odata',
maxExpandDepth: 3,
})// Per-entity: Orders can expand 1 level only
this.edmRegistry.setEntitySecurityOptions('Orders', {
maxExpandDepth: 1,
})When exceeded, the response is:
{
"error": {
"code": "ExpandDepthExceeded",
"message": "$expand depth 3 exceeds maximum allowed depth 2"
}
}