Conversions
trim, trimStart, trimEnd, toLowerCase and toUpperCase, default values or default functions, and conversionFun to compute a value, like a slug from a name.
API Maker
The framework for AI era
Database APIs
Describe a table once. Every write through the schema APIs is converted and checked for you.
The schema of a table is a TypeScript object: the type of each field, how to clean it, its default, its rules and its relations. API Maker detects a first version from your data. From then on, the schema APIs trim, convert, validate, encrypt and number your data before it reaches the database.
Step through it, slow it down, or open the full canvas.
Your table, described in TypeScript. API Maker detects a first schema from your table. You add the types, conversions, rules and relations, and every write through the schema APIs follows them.
API Maker detects a first schema from your table. You add the types, conversions, rules and relations, and every write through the schema APIs follows them.
Keys that are not in the schema are refused. Values get their type, "25" becomes 25, and strings are trimmed or cased.
conversionFun(value, all) gets the value and the whole object, and its return is stored: "Wireless Mouse" becomes the slug wireless-mouse.
Fields are encrypted or hashed with your secret, ids are generated, numbers incremented, defaults set. Then the rules pass and the row is saved.
validatorFun(value, all) refuses a value by returning false or throwing: the message you throw goes to the caller, next to the errors of the other rules.
The field marked isConcurrencyControlField is a version. An update sends the version it read: when the row changed meanwhile, API Maker refuses it instead of overwriting the other change.
trim, trimStart, trimEnd, toLowerCase and toUpperCase, default values or default functions, and conversionFun to compute a value, like a slug from a name.
required, min, max, minLength, maxLength, email and enum, plus validatorFun for rules that need the whole object.
instance, database, collection or table, and column on a field point to another table, even in another database. Deep populate, find and join and master save follow them.
isAutoIncrementByAM counts from your start value with your step. isAutoGenerateByAM creates a UUID, ObjectID, ULID or short UUID.
encryption stores a field encrypted with the key of your secret (AES, RC4 or TripleDES); decrypt it with g.sys.system.decrypt when you need it. hashing stores a one-way HMAC SHA-256 hash.
Mark a version field with isConcurrencyControlField: an update carrying an old version fails instead of overwriting someone else's change.
A web app, a mobile app and a partner integration all save products. The rules live in the schema, so each of them gets the same checks, the same defaults and the same error messages, and none of them can store a product without a category.
import { EType, ISchemaType, ISchemaProperty } from 'types';const schema: ISchemaType = { _id: <ISchemaProperty>{ __type: EType.objectId, isPrimaryKey: true, isAutoGenerateByAM: { valueGeneratorType: 'ObjectID' } }, product_no: <ISchemaProperty>{ __type: EType.number, isAutoIncrementByAM: { start: 1000, step: 1 } }, name: <ISchemaProperty>{ __type: EType.string, validations: { required: true, minLength: 2, maxLength: 120 }, conversions: { trim: true } }, status: <ISchemaProperty>{ __type: EType.string, validations: { enum: ['DRAFT', 'ACTIVE', 'ARCHIVED'] }, conversions: { toUpperCase: true, defaults: { defaultValue: 'DRAFT' } } }, category: <ISchemaProperty>{ __type: EType.objectId, validations: { required: true }, database: 'shop', collection: 'categories', column: '_id' }, slug: <ISchemaProperty>{ __type: EType.string }, supplier_tax_id: <ISchemaProperty>{ __type: EType.string, conversions: { encryption: true } }, version: <ISchemaProperty>{ __type: EType.number, isConcurrencyControlField: true, conversions: { conversionFun: () => new Date().getTime() } },};module.exports = { schema };{ "success": false, "statusCode": 400, "errors": [ { "type": "required", "field": "category", "code": 400, "message": "Please provide valid 'category' field with type 'objectId'." }, { "type": "enumValidation", "field": "status", "code": 400, "message": "Property 'status' should have any value from [DRAFT, ACTIVE, ARCHIVED]." } ]}Messages come from the language pack of the caller, in the language it asks for.
Yes. The system API is-valid-data-for-table (g.sys.system.isValidDataForTable) runs the same conversions and validations and returns the errors.
The schema APIs refuse it with a schemaKeyNotFound error, "Property not found in schema for key …", instead of storing it.
Yes. instance, database, collection or table, and column on a field point to another table. Deep populate, find and join and master save follow them, even into another database.
Not by default: calls from custom code skip it. Pass skipConcurrencyControl: false to use it there too.