2个版本

0.1.1 2020年9月8日
0.1.0 2020年9月8日

#2272 in 解析实现

MIT 协议

61KB
2K SLoC

Transporter

用于安全、跨语言API类型的代码生成器

设置

  • 确保 ~/.cargo/bin 已添加到您的 PATH 中(运行 export PATH="$PATH:$HOME/.cargo/bin)
  • cargo安装 transporter

工作原理

Transporter 是一个命令行工具,它生成可以轻松序列化和反序列化(主要是对/从 JSON)的数据结构,以便在不同的语言之间通过 http(s) 传输。

为什么不使用 GraphQL?

因为您想避免完全从头开始重新思考您的 API。与 GraphQL 相比,Transporter 不是一个查询语言。它所做的只是添加传输类型安全。

为什么不使用 Protocol Buffers?

因为 Protocol Buffers 以超级空间高效的二进制格式传输。Transporter 生成的类型以 JSON 格式传输,您可以像读取和调试任何其他基于 JSON 的 API 一样读取和调试它。

为什么不使用 OpenAPI?

因为它不支持通配符路径(可变数量的路径参数)。

为什么不使用 JSON Schema?

因为有大量不同版本的规范,工具大多过时,并且没有优雅的方式映射标签联合。

特性

Transporter 读取 toml 文件作为输入,其中类型是用以下术语定义的:

基本类型

  • 字符串
  • 整数
  • 浮点数
  • 布尔值

由于 Transporter 类型通常不可为空,因此可空类型必须定义为

  • 可选(表示为 (string)

对于其他结构化数据,也存在

集合类型

  • 列表([string]),序列化为 JSON 数组
  • 字典({string}),序列化为 JSON 对象

用户定义的类型可以是

别名

[ alias.Addressbook ]
type = "[Contact]"

在这个例子中,别名 "Addressbook" 被赋予联系人列表。

结构

[ struct.PhoneNumber ]
type = "PhoneNumberType"
number = "string"

[ struct.Contact ]
name = "string"
phone = "[PhoneNumber]"

在这个例子中定义了两个结构

  • PhoneNumber 包含两个字段,typenumber
  • Contact 也包含两个字段,namephone

结构体序列化为 JSON 对象({"name":"John Doe","phone":[...]}

标签联合

[ union.PhoneNumberType ]
Mobile = {}
Home = {}
Custom = { name = "string" }

在这个例子中定义了一个联合类型。Transporter 中的联合类型通常是标签联合。一个 PhoneNumberType::Mobile 的实例将被序列化为仅仅是 "Mobile"。一个设置为 "Work"PhoneNumberType::Custom 的实例将被序列化为 {"Custom":{"name":"Work"}}

语言支持

目前,Transporter 支持 Rust 和 PHP。在未来不久,计划支持 Elm 和 TypeScript / Javascript。

Rust

在 Rust 中,上述示例大致翻译为(省略了一些 serde 宏)

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

在 PHP 中,上述示例将翻译为类,例如

// 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 {...}

依赖项

~2–2.8MB
~45K SLoC