Serialization
- Introduction
- Serializing to Arrays
- Hiding Attributes
- Exposing Attributes (visible)
- Temporarily Modifying Visibility
- Appending Computed Values
- Date Serialization
Introduction
When building an API, you need to control which attributes are exposed, how dates are formatted, and whether computed properties appear in the output. Orion handles all of this through decorators and per-instance override methods.
For advanced transformation logic, use API Resources instead of raw serialization.
Serializing to Arrays
const user = await User.with('roles').firstOrFail();
// All attributes + all loaded relations, recursively
const data = user.toArray();
// { id: 1, name: 'Alice', email: 'a@example.com', roles: [{ id: 1, name: 'admin' }] }
// Attributes only — no relations
const attrs = user.attributesToArray();
// { id: 1, name: 'Alice', email: 'a@example.com' }Collections serialize with toArray() too:
const users = await User.with('roles').get();
users.toArray(); // array of plain objects, relations includedOrion implements
toJSON()on both models and collections, so you can pass them directly tores.json(),JSON.stringify(), or any HTTP framework — serialization happens automatically, no explicit.toArray()call needed.
Hiding Attributes
Use @hidden to exclude sensitive columns from serialization:
import { Model, table, hidden } from '@wrsouza/orion';
@table('users')
@hidden(['password', 'remember_token', 'two_factor_secret'])
class User extends Model {}
user.toArray();
// { id: 1, name: 'Alice', email: 'a@example.com' }
// password, remember_token, two_factor_secret are omittedYou can also hide relationships by adding the relation name to @hidden.
Exposing Attributes (visible)
@visible is the inverse of @hidden — only listed columns appear in serialization. All other columns are hidden:
@table('users')
@visible(['id', 'name', 'email'])
class User extends Model {}
user.toArray();
// { id: 1, name: 'Alice', email: 'a@example.com' }
// All other columns — password, settings, etc. — are excluded
@visibleand@hiddenare mutually exclusive. Prefer@visiblewhen you want an explicit allowlist, and@hiddenwhen you just want to exclude a few sensitive columns.
Temporarily Modifying Visibility
All these methods return this so they can be chained directly into toArray():
const data = user.makeVisible('phone').toArray();
// Exposes 'phone' even if it's in @hidden
const data = user.makeHidden('email').toArray();
// Hides 'email' for this call only
// Replace the entire visible/hidden list for this instance
const data = user.setVisible(['id', 'name']).toArray();
const data = user.setHidden(['password', 'ssn']).toArray();
// Add to the current list without replacing
const data = user.mergeVisible(['phone']).toArray();
const data = user.mergeHidden(['internal_notes']).toArray();These work on ModelCollection too and delegate to each model in the collection:
const users = await User.get();
users.makeVisible(['phone']).toArray();
users.makeHidden(['email']).toArray();
users.setVisible(['id', 'name']).toArray();
users.mergeHidden(['secret']).toArray();Appending Computed Values
Computed accessors are excluded from serialization by default. Use @appends to include them permanently:
import { Model, table, appends, accessor, map, cast, Cast } from '@wrsouza/orion';
@table('users')
@appends(['full_name', 'is_veteran'])
class User extends Model {
declare id: number;
@map('first_name')
declare firstName: string;
@map('last_name')
declare lastName: string;
@map('created_at')
@cast(Cast.Date)
declare createdAt: Date;
@accessor
get fullName(): string {
return `${this.firstName} ${this.lastName}`;
}
@accessor
get isVeteran(): boolean {
const years = (Date.now() - this.createdAt.getTime()) / (365.25 * 86400e3);
return years >= 5;
}
}
user.toArray();
// { id: 1, firstName: 'Alice', lastName: 'Smith', ..., full_name: 'Alice Smith', is_veteran: false }Accessor methods use camelCase (
fullName) but the appended key uses snake_case (full_name). Orion converts automatically.
Appended attributes respect @visible and @hidden:
@hidden(['full_name']) // hide the appended attribute
@appends(['full_name'])
class User extends Model {}
user.toArray(); // full_name is NOT included
user.makeVisible('full_name').toArray(); // now includedRuntime Appends
// Add an accessor to the output for this call
user.append('full_name').toArray();
user.append(['full_name', 'avatar_url']).toArray();
// Replace the entire appends list
user.setAppends(['full_name']).toArray();
// Remove all appended attributes
user.withoutAppends().toArray();
// Merge with existing list
user.mergeAppends(['new_attr']).toArray();Date Serialization
Orion serializes Date objects to ISO 8601 strings by default. Override per model by implementing serializeDate():
@table('posts')
class Post extends Model {
serializeDate(date: Date): string {
return date.toISOString().slice(0, 10); // 'YYYY-MM-DD'
}
}Control the format per individual column using cast declarations:
@casts({
born_at: 'date:Y-m-d',
meeting_at: 'datetime:Y-m-d H:00',
})
class User extends Model {}