0.6.0 • Published 3 years ago

superest v0.6.0

Weekly downloads
-
License
Apache-2.0
Repository
github
Last release
3 years ago

superest

Typed API data serialization for frontends

Features

The main problem solved by superest is the processing of relational data. It automatically links relational data (by defining getters) according to the primary key to construct nested data objects, so that you could access your data like this: users[3].friendships[4].target.name (even longer if you want).

  • Process primary key related fields to embed related data
  • Fairly strongly typed
  • Basic data validations
  • Computed attributes
  • Permanent effective object reference

Usage

Creating Serializers

A Serializer is a top-level Field composed by multiple children Field objects.

FieldInternal ValueExternal Value
StringFieldstringstring
NumberFieldnumbernumber
BooleanFieldbooleanboolean
DateFieldDatestring
ListFieldArrayArray
// general options
const id = new NumberField({});
const pkField = "id";

// types
export type Label = FieldValues<LabelSerializer<{}>>["internal"];
export type User = FieldValues<UserSerializer<{}>>["internal"];

// object pools for storage
export const labels: Record<PK<Label>, Label> = {};
export const users: Record<PK<User>, User> = {};

export class LabelSerializer<Opts extends FieldOptions> extends build({
  fields: {
    both: {
      // fields in both responses and requests
      name: new StringField({}),
    },
    response: {
      // fields in responses
      id,
    },
    request: {
      // fields in requests
    },
  },
  pkField, // field name of the primary key field
  getters: {}, // computed attributes
})<Opts> {
  static readonly storage = new Storage(labels);
}

export class UserSerializer<Opts extends FieldOptions> extends build({
  fields: {
    both: {
      username: new StringField({}),
    },
    response: {
      id,
      label: new LabelSerializer({}), // nested input
    },
    request: {
      password: new StringField({}),
      label: new NumberField({}), // primary key output
    },
  },
  pkField,
  getters: {
    idGetter: (data) => data.id,
  },
})<Opts> {
  static readonly storage = new Storage(users);
}

Serializing

const labelRawResponseData: FieldValues<LabelSerializer<{}>>["rawInternal"] = {
  id: 1,
  name: "administrators",
  createdAt: new Date().toISOString(),
};

const userRawResponseData: FieldValues<UserSerializer<{}>>["rawInternal"] = {
  id: 1,
  username: "admin",
  label: 1, // primary key
};

const labelInternalData = new LabelSerializer({}).toInternal(
  labelRawResponseData
)();
labelInternalData.createdAt instanceof Date; // true
labels[labelInternalData.id] == labelInternalData; // true

const userInternalData = new UserSerializer({}).toInternal(
  userRawResponseData
)();
userInternalData.idGetter == userInternalData.id; // true
userInternalData.label == labelInternalData; // true

// duplicated serializing: reference will be permanently effective
const duplicatedUserRawResponseData = {
  ...userRawResponseData,
  username: "updated",
};
const duplicatedUserInternalData = new UserSerializer({}).toInternal(
  duplicatedUserRawResponseData
)();
duplicatedUserInternalData == userInternalData; // true

Deserializing

new UserSerializer({}).toExternal({
  username: "admin",
  label: 1,
  password: "abcdefg",
});

Utilities

transformCase()

const raw = {
  a: {
    a: [
      {
        a: null,
      },
    ],
  },
};

const ret = transformCase(raw, (v) => v.toUpperCase());
// { A: { A: [ { A: null } ] } }
raw == ret; // true

transformCase("a", v.toUpperCase()); // "a"

mixinStatic()

class Base {
  static both = 1;
  static base = null;
}
class Mixin1 {
  static both = 2;
  static mixin1 = null;
}
class Mixin2 {
  static both = 3;
  static mixin2 = null;
}

const mixined = mixinStatic(Base, Mixin1, Mixin2);
mixined.base == null; // true
mixined.mixin1 == null; // true
mixined.mixin2 == null; // true
mixined.both = 3; // true
0.5.0

3 years ago

0.4.0

3 years ago

0.6.0

3 years ago

0.3.2

3 years ago

0.3.0

3 years ago

0.3.1

3 years ago

0.2.0

3 years ago

0.1.0

3 years ago