Skip to main content

Serializing Associations

Rendering Associated Objects

Use .rendersOne() and .rendersMany() to include associated models in serialized output.

// From BearBnB: Place with rooms
export const PlaceForGuestsSerializer = (place: Place) =>
DreamSerializer(Place, place)
.attribute('id')
.delegatedAttribute('currentLocalizedText', 'title', { openapi: 'string' })
.rendersMany('rooms', { serializerKey: 'forGuests' })

// Room with place
export const RoomWithPlaceSerializer = (room: Room) =>
DreamSerializer(Room, room).attribute('id').attribute('name').rendersOne('place')

serializerKey option

Specify which serializer to use for the associated model (defaults to 'default'):

export const PlaceDetailSerializer = (place: Place) =>
DreamSerializer(Place, place)
.attribute('id')
.attribute('name')
.rendersMany('rooms', { serializerKey: 'forGuests' })
.rendersMany('bookings') // renders using the default serializer

as option

Rename the association in the output:

export const PlaceSerializer = (place: Place) =>
DreamSerializer(Place, place).attribute('id').rendersMany('rooms', { as: 'accommodations' })

// Output: { id: 1234, accommodations: [...] }

flatten option (for rendersOne only)

When flatten: true is included, the attributes of the serialized, associated object are flattened into the serialized results.

export const PlaceSerializer = (place: Place) =>
DreamSerializer(Place, place).attribute('id').rendersOne('currentLocalizedText', {
flatten: true,
serializerKey: 'forPlaces',
})

// Output: { id: 1234, title: 'My localized title', markdown: 'My localized markdown' }
info

When the goal is to incorporate a property or two from the associated model, a delegatedAttribute may be a simpler approach than creating a new named serializer.

Loading Associations

Associations must be loaded before serialization. Use preloadFor to automatically load everything needed for a serializer:

// Loads all associations needed for PlaceForGuestsSerializer
const places = await Place.preloadFor('forGuests').all()

// Better than manually specifying:
// const places = await Place.preload('rooms', 'currentLocalizedText').all()