Skip to main content

Serializing Attributes

attribute

The attribute method includes a property from your source object in the serialized output.

export const PlaceSummarySerializer = (place: Place) =>
DreamSerializer(Place, place).attribute('id').attribute('name')

export const PlaceSerializer = (place: Place) =>
PlaceSummarySerializer(place).attribute('style').attribute('sleeps')

// PlaceSummarySerializer serializes to:
// { id: 1234, name: 'My place' }
// and PlaceSerializer serializes to:
// { id: 1234, name: 'My place', style: 'cabin', sleeps: 5 }
info

CalendarDate and DateTime attributes (even arrays of CalendarDate and DateTime values) are automatically converted to their ISO values as part of serialization.

attribute.openapi

When serializing a Dream model with DreamSerializer, the OpenAPI shape of attributes corresponding to database columns is determined automatically (except for json and jsonb columns). However, you may still want to include an OpenAPI description:

.attribute('name', { openapi: { description: 'The name of the Place' } })`
info

ObjectSerializer serializer attributes always requires the openapi option.

For a virtual attribute on a Dream model, openapi is required even for DreamSerializer:

export const PlaceSerializer = (place: Place) =>
DreamSerializer(Place, place)
.attribute('id')
.attribute('myVirtualAttribute', { openapi: ['string', 'null'] })

This example leverages OpenAPI shorthand, but the full OpenAPI shape is available for representing complex shapes, as one must do for attributes that correspond to json/jsonb columns:

export const PlaceSerializer = (place: Place) =>
DreamSerializer(Place, place)
.attribute('id')
.attribute('myJsonAttribute', {
openapi: {
type: 'object',
properties: {
label: 'string',
value: 'decimal',
},
},
})

attribute.default

The default option provides a fallback value when the attribute is null or undefined. The default value undergoes the same transformations as regular data (e.g., decimals are rounded, dates are converted to ISO format):

export const PlaceSerializer = (place: Place) =>
DreamSerializer(Place, place)
.attribute('id')
.attribute('name', { default: 'unnamed' })
.attribute('sleeps', { default: 0 })

attribute.as

Use the as option to change the name of the attribute in the output:

export const PlaceSerializer = (place: Place) =>
DreamSerializer(Place, place).attribute('id').attribute('sleeps', { as: 'accomodates' })

// PlaceSerializer serializes to:
// { id: 1234, accomodates: 5 }

attribute.precision

Decimal values can be automatically rounded with the precision option:

export const PlaceSerializer = (place: Place) =>
DreamSerializer(Place, place).attribute('id').attribute('rating', { precision: 1 })

// A place with rating 4.66666 would serialize to:
// { id: 1234, rating: 4.7 }

delegatedAttribute

The delegatedAttribute method renders an attribute from a nested object into the serialized output. delegatedAttribute attributes are automatically inspected as part of preloadFor (so when delegating to an association, that association will be automatically preloaded):

export const PlaceSummaryForGuestsSerializer = (place: Place) =>
DreamSerializer(Place, place)
.attribute('id')
.delegatedAttribute('currentLocalizedText', 'title', { openapi: 'string' })

// A place with currentLocalizedText with { title: 'Hello world' } will render:
// { id: 1234, title: 'Hello world' }

delegatedAttribute.default

All options from the attribute method are supported on delegatedAttribute. On a delegated attribute, the default will be applied whether the association is null or the attribute on the association is null:

export const PlaceSummaryForGuestsSerializer = (place: Place) =>
DreamSerializer(Place, place).attribute('id').delegatedAttribute('currentLocalizedText', 'title', {
openapi: 'string',
default: 'Untitled',
})

// A place without a currentLocalizedText or a currentLocalizedText with { title: null } will render:
// { id: 1234, title: 'Untitled' }

The default option provides a fallback value when either the target object is null/undefined OR when the delegated attribute itself is null/undefined.

customAttribute

The customAttribute method is used for arbitrary data transformation. It is especially useful for rendering or leveraging passthrough data into the serialized output. customAttribute always requires the openapi option:

export const PlaceForGuestsSerializer = (place: Place, passthrough: { locale: LocalesEnum }) =>
PlaceSummaryForGuestsSerializer(place).customAttribute(
'style',
() => i18n(passthrough.locale, `places.style.${place.style}`),
{
openapi: 'string',
}
)

See the passthrough setting documentation for details on how to set passthrough data on automatically rendered serializers.

customAttribute.flatten

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

const UserSerializer = (user: User) =>
DreamSerializer(User, user)
.attribute('id')
.customAttribute('profileInfo', () => ({ age: 30, city: 'Metropolis' }), {
flatten: true,
openapi: {
age: { type: 'integer' },
city: { type: 'string' },
},
})

// renders { id: 1, age: 30, city: 'Metropolis' }