Note
If you’re looking to dive right in, check out the Python docs.
Teleport is:
Teleport is not a serialization layer. It provides 12 built-in data types to get you started, however, using Teleport for a non-trivial project means defining data types of your own. In object-oriented languages, this often involves augmenting your classes to make them serializable.
Once registered with Teleport, a custom data type will become a first-class citizen of the serialization system. Defining an array of widgets is just as easy as defining an array of integers, provided that you made the Widget class serializable.
Such definitions (like “array of widgets”) are also serializable. This feature is crucial in allowing Cosmic clients to share a deeper understanding of each other.
The canonical implementation of Teleport is written in Python.
Many languages such as Python or JavaScript do not support static typing. But Python (to use it as an example) is not without type definitions! Even the biggest proponent of dynamic typing will admit that it’s a good idea to document the parameter types of public library functions. This kind of static typing may be adequate for libraries, but web APIs have 3 characteristics that make them practically beg for more:
Assuming that serialization, deserialization and validation code needs to be written, the question is: how do we structure this code? Teleport is a solution to precicely this problem.
Design goals:
An object that defines a serialization and deserialization function. Together, these functions define the native form as well as the JSON form of one particular type of data. As far as Teleport is concerned, a serializer is a data type definition.
Serializers may be basic (no parameters) or parametrized. For example, an array serializer needs to know what type of items the array is expected to contain. It’s these kinds of serializers that allow building deeply nested schemas for describing rich internet data.
Data in its rich internal representation. For most built-in types, this data will consist of language primitives.
In object-oriented languages, the native form of user-defined types will often take the form of class instances. When you describe your classes to Teleport, it will be able to deserialize them from JSON and instantiate them for you.
Teleport provides 12 built-in types. Each implementation must provide 12 corresponding serializers.
The native form of the built-in types is implementation-dependent and will be defined in language-specific documentation. The serialized form and the validation logic, however, is identical across all implementations. Below is a list of all built-in models and their validation logic.
Must be expressed as a JSON object. If the object has a key that is different from every field name in fields, a validation error must be thrown. For every key-value pair in the object, the value must be deserialized against the schema of the corresponding field in fields.
Each field must have a boolean attribute required, that, if true, will cause the struct to throw a validation error when the corresponding value is missing from the data being validated.
Each field may have a string attribute doc, containing the documentation for the field.
The native form of the object must be a associative array containing all key-value pairs from the original object with native values replacing the JSON values.
A schema is always a JSON object, it must always have a type property. Parametrized types will also have param property. This property needs to be serialized and deserialized along with the rest of the schema, so it is useful to define it with a Teleport schema of its own.
Array, Map and OrderedMap are parametrized simply by:
Schema
A Struct schema’s param is of the following type:
OrderedMap(Struct([
required("schema", Schema),
required("required", Boolean)
]))
To validate [{"name": "Rose", "age": 1}, {"name": "Lily"}], you could use the following schema:
{
"type": "Array",
"param": {
"type": "Struct",
"param": {
"map": {
"name": {
"required": true,
"schema": {"type": "String"}
},
"age": {
"required": false,
"schema": {"type": "Integer"}
}
},
"order": ["name", "age"]
}
}
}