NativeModels






Native Models provides a way to map objects in a clean and typed way. The main goal is to ensure runtime type checking and consistent models for APIs.
Getting Started
const { createModel } = require('nativemodels');
const { array, boolean, computed, date, int, object, string } = require('nativemodels/datatypes');
const photoSchema = {
ext: string(),
url: string().required(),
};
const contactSchema = {
email: string(),
phone: string(),
url: string(),
};
const userSchema = {
accountID: int().nullable(),
contact: object(contactSchema),
created: date(),
firstName: string().required(),
fullName: computed((record) => `${record.firstName} ${record.lastName}`),
isAdmin: boolean().nullable(),
lastName: string().required(),
photos: array(object(photoSchema)),
typeID: int().default(2),
};
const userModel = createModel(userSchema);
const johnSmith = userModel({
contact: {
email: 'j.smith@example.com',
},
firstName: 'John',
lastName: 'Smith',
photos: [
{
ext: '.jpg',
url: 'https://example.com/img.jpg',
},
],
});
const userRecords = [
{
firstName: 'John',
lastName: 'Smith',
},
{
firstName: 'Jane',
lastName: 'Doe',
},
];
const users = userRecords.map(userModel);
const janeDoe = userModel({
...johnSmith,
firstName: 'Jane',
lastName: 'Doe',
});
Datatype API
Datatype methods that can be chained when defining schema.
datatypes.default(defaultValue)
Sets a default value if no value is set
datatypes.nullable()
Allows the value set to be null (useful for database models)
datatypes.required()
Forces the value to be required. Is ignored if default value is set
Datatypes
- array
- boolean
- computed
- date
- float
- int
- object
- string
Extending Datatypes
datatypes.validate(value, name)
If value is valid, returns true, else throws error. Name is key on object;
datatypes.parse(value)
Parses the value being set. Used to extend base datatype
Customtypes
Custom types are types that are useful to have and common enough for use to include them in our library. They currently include
- email
- enumberable
- guid
- phone
- url
Examples
const { email, enumberable, guid, phone, url } = require('nativemodels/customtypes');
const model = createModel({
email: email(),
enumberable: enumberable(['FOO', 'BAR']),
guid: guid(),
phone: phone(),
url: url(),
});
Async / Promise Computed Functions
Sometimes computed values aren't syncronous. To help you deal with that, we have provided the resolver method which will allow you to resolve all computed functions that are promises or async functions.
NOTE: You must return an async function, Promise or syncronous result. Generators will not work with this
WARNING: This is an N+1 unoptimized resolver meaning that for each nested array / object will require an extra iteration.
const { createModel, resolver } = require('nativemodels');
const { boolean, computed } = require('nativemodels/datatypes');
const schema = {
async: computed(
(record) =>
new Promise((succeed, reject) => (record.succeed ? succeed(1) : reject(new Error('Failed to resolve')))),
),
succeed: boolean().default(false),
};
const model = createModel(schema);
const data = model({ succeed: true });
const resolvedData = await resolver(data);
Schema Parsing of resolved data
You can provide a second option to resolver() that will allow you to recieve back an object that has had the schema applied to it.
const { createModel, resolver } = require('nativemodels');
const { boolean, computed, int } = require('nativemodels/datatypes');
const schema = {
async: computed(
(record) =>
new Promise((succeed, reject) => (record.succeed ? succeed(1) : reject(new Error('Failed to resolve')))),
),
succeed: boolean().default(false),
};
const resolvedSchema = {
async: int(),
succeed: boolean(),
};
const model = createModel(schema);
const data = model({ succeed: true });
const resolvedData = await resolver(data, resolvedSchema);