Guide

Models & fields

One class produces the schema, the indexes, the database validators, the permissions and the OpenAPI definition.

@ParseClass

Registers the Parse subclass and everything derived from it. Applied to a class extending BaseModel.

import {
  ParseClass, BaseModel, ParseField, BeforeSave, validateOrThrow,
} from 'parse-server-kit';

@ParseClass('Product', {
  description: 'A product in the catalogue',
  clp: { find: { requiresAuthentication: true } },
  compoundIndexes: [{ fields: ['status', 'createdAt'] }],
})
export default class Product extends BaseModel {
  constructor() { super('Product'); }
}
OptionWhat it does
clpClass-level permissions, applied to the Parse schema
protectedFieldsFields hidden from given roles
ACLA default ACL template for new objects
descriptionShown in the generated OpenAPI document
compoundIndexesMulti-field indexes, created at boot

A Parse.Role subclass is detected and deliberately not passed to registerSubclass, which Parse rejects.

@ParseField

Defines a getter and setter on the prototype that read and write Parse's attribute store. That means product.name is the supported API, not product.get('name').

@ParseField({ type: 'String', required: true, maxLength: 200 })
declare name: string;

@ParseField({ type: 'String', unique: true })
declare sku: string;

// A Pointer must name its target, or fromParams() skips it.
@ParseField({ type: 'Pointer', targetClass: 'Category' })
declare category: any;
Write declare, not ! The declaration exists only to give TypeScript the type — the storage belongs to Parse. Written as name!: string, TypeScript emits a real class field that shadows the accessor whenever useDefineForClassFields is on (its default from target: ES2022). @ParseClass repairs that automatically, so neither form breaks, but declare states what is actually true.

Options

OptionApplies toEffect
typeallString, Number, Boolean, Date, Object, Array, GeoPoint, File, Bytes, Polygon, Pointer, Relation
requiredallEnforced by validateOrThrow and by the database validator
targetClassPointer, RelationMandatory — omitting it throws at import
uniqueallUnique index, created at boot
indexalltrue, 1 or -1
min / maxNumberRange, enforced in code and in MongoDB
minLength / maxLengthStringLength bounds
enumStringAllowed values
patternStringRegular expression
geoGeoPoint2dsphere index
ttlSecondsDateTTL index — rows expire N seconds after this date

Options are validated when the file is imported, not when a request arrives. A Pointer without targetClass, min on a String, an invalid regex, geo combined with index — all throw at boot, where you will see them.

BaseModel

// A reference by id, with no fetch.
const ref = Category.pointer('abc123');

// Build a typed instance from request params, reading @ParseField
// metadata to convert pointers, arrays of pointers, dates and geopoints.
const product = Product.fromParams(req.params);

Use fromParams in create and update rather than a series of set() calls. It converts a Pointer given null or {} to an explicit clear, and converts an Array to pointers only when the field declares a targetClass.

Query results need a cast Parse.Query returns Parse.Object, not your class, so typed property access is unavailable until you cast: const p = row as Product. This is a limitation of Parse's own typings, not something this library changes.

Validation

@BeforeSave()
static async onBeforeSave(req: Parse.Cloud.BeforeSaveRequest<Product>) {
  validateOrThrow(req.object);   // checks every rule declared above
}

validateOrThrow checks required, min/max, minLength/maxLength, enum and pattern, and throws a Parse VALIDATION_ERROR listing every failure at once. Putting it in @BeforeSave means it runs on every save path — cloud function, REST, dashboard or script.

applyMongoValidators() pushes the same constraints into MongoDB $jsonSchema validators, so the database enforces them even for writes that never touch your code.