Skip to main content

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 renders: { id: 1234, name: 'My place' }
// PlaceSerializer renders: { id: 1234, name: 'My place', style: 'cabin', sleeps: 5 }

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

openapi

When serializing a Dream model with DreamSerializer, the OpenAPI shape of database column attributes is determined automatically (except for json and jsonb columns). You can still add an OpenAPI description if you want:

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

With ObjectSerializer, you always need to provide the openapi option, since there's no schema to pull from. Same goes for virtual attributes on Dream models — even with DreamSerializer, virtual attributes need an explicit openapi shape:

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

For json/jsonb columns, you'll need to spell out the full OpenAPI shape:

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

default

The default option provides a fallback when the attribute is null or undefined. Default values go through the same transformations as regular data (decimals get rounded, dates get converted to ISO format, etc.):

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

as

Use the as option to rename the attribute in the output:

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

// renders: { id: 1234, accommodates: 5 }

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 renders: { id: 1234, rating: 4.7 }

delegatedAttribute

The delegatedAttribute method reaches into a nested object or association and pulls an attribute into the serialized output. Associations used by delegatedAttribute are automatically loaded by preloadFor:

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

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

delegatedAttribute.default

All options from attribute are supported on delegatedAttribute. The default kicks in whether the association itself is null or the attribute on the association is null:

.delegatedAttribute('currentLocalizedText', 'title', {
openapi: 'string',
default: 'Untitled',
})

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

customAttribute

The customAttribute method is for arbitrary data transformation. It's especially handy for leveraging passthrough data. 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 documentation for how to set passthrough data on automatically rendered serializers.

customAttribute.flatten

When flatten: true is included, the attributes of the returned object get flattened into the parent:

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' }