This repository has been archived by the owner on Feb 16, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 23
Home
gcanti edited this page Nov 8, 2014
·
2 revisions
Use cases:
- Trusted data
- Consuming a JSON API payload on a client
- Handle form values
- Untrusted data
- Receiving a JSON Api payload on a server
Flow:
- receive the payload
- get an instance of the payload model (asserts)
- transform data (optional)
- get a domain model instance (optional)
// JSON received from the JSON API
var json = {
name: 'giulio',
surname: 'canti',
age: 123462000000, // unix time
adresses: [
{country: 'IT', street: 'street1'},
{country: 'US', street: 'street2'}
]
};
//
// JSON API payload model
//
var AddressJSON = struct({
country: Country,
street: Str
});
var PersonJSON = struct({
name: Str,
surname: Str,
age: Num,
adresses: list(AddressJSON)
});
//
// domain model
//
var Address = struct({
country: Str,
street: Str
});
var Person = struct({
fullName: Str,
age: Dat,
adresses: list(Address)
});
//
// transformation
//
function toCountry(isoCode) {
return isoCode === 'IT' ? 'Italy' : 'United States';
}
// transforms the payload to a model
PersonJSON.toPerson = function (json) {
return new Person({
fullName: json.name + ' ' + json.surname,
age: new Date(json.age),
adresses: json.adresses.map(function (address) {
return {
country: toCountry(address.country),
street: address.street
};
})
});
};
Can I generalize the toPerson
transformation? That is, can I manage the general transformation:
transform: Data -> Data
In general it's too hard. Let's consider only coordinates-wise bijective transformations:
// x: A -> parse -> y: E
// y: E -> format -> x: A (optional)
// y = parse(x)
// x = format(y)
var Transformer = struct({
from: Type,
to: Type,
parse: Func, // from -> to
format: Func // to -> from
});
var Address = struct({
country: Str,
street: Str
});
var Person = struct({
name: Str, // name and surname now are distinct
surname: Str,
age: Dat,
adresses: list(Address)
});
// transform: (Any, list(Transformer)) -> Any
PersonJSON.toPerson = function (json) {
var value = transform(json, [
{from: Str, to: Dat: parse: ..., format: ...},
{from: AddressJSON, to: Address: parse: ..., format: ...}
]);
return new Person(value);
};
Flow:
- validate data
- get a domain model instance..
- ..or handle error messages (optional)
var result = validate(data, type);
if (reault.isValid()) {
// use result.value
} else {
// use result.errors
}
How to handle error messages?
// a validation error
var error = {
actual: Any,
expected: Type,
path: list(Str)
};
Solution: implement a getMessage: ValidationError -> Str
function.
Flow:
-
transform state (
format
, optional) - collect form data
-
transform data (
parse
, optional) - validate data
// payload received on a server
var payload = {...};
var result = validate(payload, type);
if (result.isValid()) {
// use result.value
} else {
res.error(result.errors);
}