2 releases
0.1.1 | Sep 8, 2020 |
---|---|
0.1.0 | Sep 8, 2020 |
#2686 in Parser implementations
61KB
2K
SLoC
Transporter
A Code Generator to for safe, cross-language API types
Setup
- make sure
~/.cargo/bin
is in yourPATH
(runexport PATH="$PATH:$HOME/.cargo/bin
) cargo install transporter
How it works
Transporter is a CLI tool that generates data structures that can easily be serialized and deserialized (mainly to/from JSON) for transmission over http(s) across different languages.
Why not GraphQL
Because you want to avoid rethinking your API entirely from the ground up. In contrast to GraphQL, Transporter is not a query language. All it does is add transport type safety.
Why not Protocol Buffers
Because Protocol Buffers are transmitted in a super space-efficient binary format. Transporter-generated types are transmitted as JSON which you can just read and debug like any other JSON-based API.
Why not OpenAPI
Because it does not support wilcard paths (variable number of path parameters).
Why not JSON Schema
Because there is a huge mess of different versions of the spec, tooling is largely outdated and there's no elegant way to map tagged unions.
Features
Transporter reads a toml file as input in which types are defined in terms of
Basic Types
- string
- int
- float
- bool
since transporter types are generally non-nullable, nullable types must be defined as
- Optional (denoted as
(string)
)
and for otherwise structured data there is also
Collection Types
- List (
[string]
), serialized as JSON arrays - Dict (
{string}
), serialized as JSON objects
User defined types are either
Aliases
[ alias.Addressbook ]
type = "[Contact]"
In this example the alias "Addressbook" is given to a list of Contacts.
Structures
[ struct.PhoneNumber ]
type = "PhoneNumberType"
number = "string"
[ struct.Contact ]
name = "string"
phone = "[PhoneNumber]"
In this example two structs are defined
PhoneNumber
, which has two fields,type
andnumber
Contact
, which also has two fields,name
andphone
Structs are serialized as JSON object ({"name":"John Doe","phone":[...]}
)
Tagged Unions
[ union.PhoneNumberType ]
Mobile = {}
Home = {}
Custom = { name = "string" }
In this example a union type is defined. Unions in Transporter are generally
tagged unions. An instance of PhoneNumberType::Mobile
would be serialized
as just "Mobile"
. An instance of PhoneNumberType::Custom
with name set to
"Work"
would be serialized as {"Custom":{"name":"Work"}}
.
Language support
Currently, transporter supports rust und php. In near future, support for Elm and Typescript / Javascript is planned.
Rust
In rust the above examples would roughly (omitting mainly some serde macros) translate to
type Addressbook = Vec<Contact>;
struct PhoneNumber {
type_: PhoneNumberType,
number: String,
}
struct Contact {
name: String,
phone: Vec<PhoneNumber>,
}
enum PhoneNumberType {
Mobile,
Home,
Custom {
name: String,
},
}
PHP
In php the above examples would translate to classes such as
// Addressbook.php
class Addressbook {
private $value;
public function __construct(array $value) {...}
public function get() : array {...}
public function set(array $value) {...}
public function deserialize($input) : Self {...}
}
// PhoneNumber.php
class PhoneNumber {
private $type;
private $number;
public function __construct(array $fields) {...}
public function getType() : PhoneNumberType {...}
public function setType(PhoneNumberType $value) {...}
public function getNumber() : string {...}
public function setNumber(string $value) {...}
...
}
// Contact.php
class Contact {...}
// PhoneNumberType.php
abstract class PhoneNumberType {...}
// PhoneNumberType/Mobile.php
class Mobile extends PhoneNumberType {...}
// PhoneNumberType/Home.php
class Home extends PhoneNumberType {...}
// PhoneNumberType/Custom.php
class Custom extends PhoneNumberType {...}
Dependencies
~2.5–3.5MB
~58K SLoC