mappet
![CircleCI](https://circleci.com/gh/MichalZalecki/mappet.svg?style=svg)
Lightweight, composable mappers for object transformations/normalization.
API Docs | Examples
Installation (npm)
npm i -S mappet
Use cases
- Fault tolerant object transformations, no more
Cannot read property of undefined
. - Normalizing API responses shape and key names e.g. to camelCase or flattening nested payloads
- Preparing nested API request payloads from flat form data
- Filtering object entries e.g. omitting entries with
undefined
value - Per field modifications e.g.
null
to empty string to make React inputs happy
Examples
Basic
Simple value to value transformation
const schema = [
["firstName", "first_name"],
["cardNumber", "card.number"],
];
const mapper = mappet(schema);
const source = {
first_name: "Michal",
last_name: "Zalecki",
card: {
number: "5555-5555-5555-4444",
},
};
const result = mapper(source);
Mapping values
Third element of schema entry is modifier which allows for mapping values. Modifier accepts current
value and entire, original source object.
const formatDate = (date, source) => moment(date).format(source.country === "us" ? "MM/DD/YY" : "DD/MM/YY");
const upperCase = v => v.toUpperCase();
const schema = [
["country", "country", upperCase],
["date", "date", formatDate],
];
const mapper = mappet(schema);
const source = {
country: "gb",
date: "2016-07-30",
};
const result = mapper(sourceUS);
Filtering entries
Fourth element of schema entry is filter which allows for omitting entry based on its value or
entire, original source object.
const skipIfNotAGift = (value, source) => source.isGift;
const skipIfGift = (value, source) => !source.isGift;
const mapToNull = () => null;
const schema = [
["quantity", "quantity"],
["gift.message", "giftMessage", undefined, skipIfNotAGift],
["gift.remind_before_renewing", "remindBeforeRenewingGift", undefined, skipIfNotAGift],
["gift", "gift", mapToNull, skipIfGift],
];
const mapper = mappet(schema);
const source = {
quantity: 3,
isGift: false,
giftMessage: "All best!",
remindBeforeRenewingGift: true,
};
const result = mapper(sourceNotGift);
Composing mappers
Mappers are just clojures. It's easy to combine them using modifiers.
const userSchema = [
["firstName", "first_name"],
["lastName", "last_name"],
];
const userMapper = mappet(userSchema);
const usersSchema = [
["totalCount", "total_count"],
["users", "items", users => users.map(userMapper)],
];
const usersMapper = mappet(usersSchema);
const source = {
total_count: 5,
items: [
{ first_name: "Michal", last_name: "Zalecki" },
{ first_name: "Foo", last_name: "Bar" },
],
};
const result = usersMapper(source);
Strict mode
Mappers in strict mode will throw exception when value is not found on source object.
const schema = [
["firstName", "first_name"],
["lastName", "last_name"],
];
const mapper = mappet(schema, { strictMode: true });
const source = {
first_name: "Michal",
};
const result = mapper(source);
You can specify mapper name for easier debugging.
const userMapper = mappet(schema, { strictMode: true, name: "User Mapper" });
const user = mapper(source);
Greedy mode
Mappers in greedy mode will copy all properties from source object.
const schema = [
["last_name", "last_name", str => str.toUpperCase()],
];
const mapper = mappet(schema, { greedyMode: true });
const source = {
first_name: "Michal",
last_name: "Zalecki",
email: "example@michalzalecki.com",
};
const actual = mapper(source);
See tests for more examples.