json-entity
v0.4.3
Published
Entity class for controlling and formatting data objects
Downloads
18
Maintainers
Readme
json-entity
The goal of this package is to provide an easy, reusable, and secure way to control and format data for output (e.g. from a REST API). Using an Entity, you can specify the fields you'd like to be included in the output representation of your data, as well as additional options for tweaking the structure. In this manner, this package takes a whitelist-only approach, forcing clear definitions of properties that will be exposed. This package is heavily inspired by Grape::Entity.
Example
const User = new Entity({
// Use `true` to always expose a field
id: true,
firstName: true,
lastName: true,
// Use a function to return a custom value (return `undefined` to hide in JSON)
fullName(user, options) {
return `${user.firstName} ${user.lastName}`;
},
// Use an object to specify additional options
location: {
// Expose field using an alternate name
as: 'hometown',
// Expose field only if function returns "truthy"
if: (user, options) => options.output === 'full' },
// See additional options below
},
});
User.represent({
id: 1,
firstName: 'Josh',
lastName: 'Swan',
location: 'San Francisco, CA',
}, { output: 'full' });
/*
{
id: 1,
firstName: "Josh",
lastName: "Swan",
fullName: "Josh Swan",
hometown: "San Francisco, CA"
}
*/
Methods
Entity.isEntity
Static helper method to determine whether a supplied object is an Entity.
Entity.isEntity(new Entity({})); // true
Entity.isEntity({}); // false
extend
Create a new Entity using the current Entity as a base. The new Entity inherits all exposed properties from the base in addition to any new properties specified on the object passed to extend
.
const User = new Entity({
id: true,
firstName: true,
});
const UserFull = User.extend({
lastName: true,
location: true,
});
User.represent({ id: 1, firstName: 'Josh', lastName: 'Swan', location: 'San Francisco, CA' });
// { id: 1, firstName: "Josh" }
UserFull.represent({ id: 1, firstName: 'Josh', lastName: 'Swan', location: 'San Francisco, CA' });
// { id: 1, firstName: "Josh", lastName: "Swan", location: "San Francisco, CA" }
represent
Use the exposed properties defined on the Entity to create a new object from the supplied data. Only whitelisted/exposed properties will be included in the resulting object, and any options specified will be used to modify the output.
const User = new Entity({
id: true,
firstName: true,
});
const user = { id: 1, firstName: 'Josh', lastName: 'Swan' };
const representation = User.represent(user);
// { id: 1, firstName: "Josh" }
console.log(user === representation); // false
// Supply an options object that will be passed to `filter` and `if` functions. You can also set
// `safe` to `false` in your options object to enable strict mode and throw an error on any missing
// property, regardless of `require` option (see below).
const representation = User.represent(user, { options });
const throws = User.represent({}, { safe: false });
Options
The following options can be specified using the { [property]: {options} } syntax shown in the example above. Multiple options can be specified and will work together, though some combinations may be logically incompatible.
as String
Expose a property using an alternate name.
const Example = new Entity({
fullName: { as: 'name' },
});
Example.represent({ fullName: 'Josh Swan' });
// { name: "Josh Swan" }
default Any
Provide a default value in case the property is not defined.
const Example = new Entity({
admin: { default: false },
});
Example.represent({});
// { admin: false }
filter Function
Filter an array value based on a function. The function is invoked with three arguments: item
(the current item of the array), data
(the full data object supplied to represent
), and options
(the options object supplied to represent
). Note: An error will be thrown if filter
is applied to a non-array value.
const Example = new Entity({
roles: { filter: (role, user, options) => role !== 'admin' },
});
Example.represent({ roles: ['admin', 'user'] });
// { roles: ['user'] }
if Function
Conditionally expose a field based on function return value ("truthy" = expose). The function is invoked with the same arguments as represent
(i.e. data, [options={}]
).
const Example = new Entity({
country: { if: (obj, opts) => obj.country !== 'US' },
});
Example.represent({ country: 'CA' });
// { country: "CA" }
Example.represent({ country: 'US' });
// { }
merge Boolean
Merge properties into parent directly (or concatenate if array). NOTE: When merging arrays from multiple properties using as
, the merge
option must be specified on all properties that will be merged or those without will overwrite any existing values during the merge process (see example below).
const Example = new Entity({
id: true,
address: { merge: true },
});
Example.represent({ id: 1, address: { city: 'San Francisco', region: 'CA', country: 'US' } });
// { id: 1, city: "San Francisco", region: "CA", country: "US" }
const Example2 = new Entity({
id: true,
roles: { merge: true },
scopes: { as: 'roles', merge: true }, // Merge into `roles` - must also specify `merge` on `roles`
});
Example2.represent({ id: 1, roles: ['admin'], scopes: ['user'] });
// { id: 1, roles: ['admin', 'user'] }
require Boolean
Throw an error if this property is absent from data supplied to represent
.
const Example = new Entity({
id: { require: true },
});
Example.represent({});
// Error: data missing required property id!
using Entity
Apply an Entity to the value of the property (for nesting Entities).
const User = new Entity({
id: true,
firstName: true,
});
const Example = new Entity({
user: { using: User },
});
Example.represent({ user: { id: 1, firstName: 'Josh', lastName: 'Swan', location: 'San Francisco, CA' } });
// { user: { id: 1, firstName: "Josh" } }
value Any
Always use the specified value for this property, regardless of property value in supplied data.
const Example = new Entity({
id: true,
type: { value: 'User' },
});
Example.represent({ id: 1, type: 'AdminUser' });
// { id: 1, type: "User" }