#interface #specification-language #design #path #arc #url-path #post

bin+lib arc-isle

Arc 项目接口规范语言:设计和实现

3 个版本

0.1.2 2024 年 3 月 10 日
0.1.1 2024 年 3 月 7 日
0.1.0 2024 年 2 月 7 日

网络编程 中排名 621

Download history 61/week @ 2024-03-11 13/week @ 2024-04-01

每月下载量 98

Apache-2.0

75KB
2K SLoC

ArcISLE

-- Interface Specification Language

其目标是提供一种轻量级的方式来描述软件中几乎任何类型的接口,并为分析和治理提供更高级的工具。

状态

项目处于早期开发阶段。目前,它可以解析根据以下规范创建的文档,并在不解析整个文档的情况下在不符合规范的地方发出错误。

最近计划是

  • 添加类型声明验证。目前我们收集已声明的类型,但不会验证所有用法都严格遵循该声明并发出错误。
    • 仍缺少缺失声明的精确定位,在完成之前添加会很好。
  • 命令行界面。
  • 检查较大文档的速度。到目前为止,它已经在一个非常小的 API 规范上进行了测试,需要更多的真实世界示例来定义是否需要进行优化。
  • OpenAPI 与 ArcISLE 转换。
  • 混合类型和路由声明
  • 不同的路由版本
  • 默认响应代码猜测

结构

所有规范仅使用 YAML 编写。这允许写出更少的内容,更快地完成,并且仍然有强大的工具来满足广泛的需求。JSON 存在一些不便的限制,例如几乎在所有地方都需要引号,这使得手动编写更困难。

主要部分如下

  • types — 描述 API 中使用的对象列表。
  • interfaces — 描述 API 提供的端点。

默认情况下,建议不要维护包含所有描述的单个文档,而是开始将文件分解成两组:类型和接口。可以通过导入文档的子集来完成此操作

types:
    _import: types.yml

导入还可以包括文件列表

_import:
    - file1.yml
    - file2.yml
    - file3.yml
    - file4.yml

文件的路径相对于请求导入的根文档解析。

类型

API 通常包含许多特定类型,例如用户、帖子或交易等。这些实体在定义接口时出现在许多地方。通过提前定义它们并重复使用,我们可以简化未来的工作流程。这就是类型的作用。

类型声明允许在 types 部分(或该部分包含的分离文件)中声明。要声明一个类型,指定其名称和字段集。每个字段都有自己的名称和类型,定义在分号之后。

user:
    id: uuid
    name: str
    role: str

您还可以嵌套类型至3级(这个限制是人为设定的,旨在提高可读性)

settings:
    version: str?
    flags:
        a: bool
        b: bool	
        c: bool

类型可以在其他类型内部进行引用

post:
    title: str
    body: str
    author: user

内置

规范支持一组默认类型:基本数据类型、容器和格式。它们用于满足基本需求,并允许构建自定义类型。

基本数据类型

我们正在处理的所有数据在最终分析后都有一些基本类型,其中大多数是最基本的,得到了支持

  • int - 表示整数
  • double - 表示双精度数字
  • bool - 表示布尔值
  • str - Unicode字符串

容器

为了满足集合或嵌套JSON的需求,有两种容器类型

  • array[type]array
  • dict[key, value]dict

方括号用于定义内部元素,通过在其中指定类型,您可以表示期望的元素,例如整数数组或键为字符串且值为整数的字典。没有对可以使用的数据类型的限制。

无括号的表示法移除了元素的类型定义,这在某些情况下可能很有用,但通常不推荐使用。

特定格式

某些类型的数据被频繁使用,仅将其指定为字符串可能会丢失信息。为了改进这一点,规范提供了一些默认类型,这些类型被识别为常用类型。

  • timestamp — 作为双精度数字,表示期望这个双精度数字是UNIX格式的时间。
  • date_iso8601 — 作为字符串,表示和验证字段以确认ISO 8601日期标准。
  • uuid — 作为字符串,表示和验证字段以包含有效的UUID值。
  • url

可选性

类型内的字段可能是必需的或可选的。为了简化声明,每个字段都有一个表示可选性的参数,该参数用 ? 符号表示。将其添加到字段类型末尾表示该字段是可选的,并且可以在该类型的实例中省略。

title: str
description: str?
connections: array[uuid]?

可选性 指字段,而不是类型,这意味着指定例如 array[int?] 合法的语法。

JSON Schema

所有类型都按照设计与JSON Schema兼容。任何本规范的实现都必须提供一种方法从类型生成有效的模式。

接口


现在,每个REST API的核心实际上是端点,在这里被称为接口,因为它们是服务器和客户端之间的接口。接口的声明比类型的声明要复杂一些。每个接口的两个必填字段是 pathmethod

- path: news
  method: get

路径可以使用花括号进行参数化

- path: users/{user_id}

如果可能的话,建议在参数名称中包含类型名称以提高可读性。比较以下版本

  • users/{id}/posts/{id}/comments/{id}
  • users/{user_id}/posts/{post_id}/comments/{comment_id}

不考虑嵌套决策的问题,第二个版本仅通过观察就更容易理解,因为我们清楚地知道每个参数代表什么。

其余选项取决于请求的详细信息,并遵循HTTP标准。

字段 必需 用途 限制 可能值
查询 指定请求的查询参数。 仅允许在GET和HEAD请求中使用。 必须是一个有效的自定义类型。
正文 指定请求的正文。 允许在POST、PUT和PATCH请求中使用。 必须是一个有效的自定义类型。
body_type 指定正文类型。 仅与存在正文时一起允许。 目前仅支持form-data值。
response 指定请求的响应。 无限制。 响应中允许任何类型。

这足以指定考虑成功流程的基本端点要求,例如

types:
  news_entry:
    id: str
    title: str
    link: url
interfaces:
    - path: news
      method: get
      query:
        search: str?
      response:
        items: array[news_entry]
        next_page_link: url?
    - path: news
      method: post
      body:
        title: str
        link: url
      response: news_entry
    - path: news/{entry_id}
      method: delete

不同的响应

一个高级场景是我们想为不同的案例定义自定义响应,如成功、失败、权限错误等。为了支持它,以下方式的response字段支持可变内容

- path: news/{entry_id}
  method: delete
  response:
    200: news_entry
    4xx: 
        code: int
        reason: str?
    5xx:
        message: str
    501:
        code: int
        reason: str?

您可以在示例中指定具体的状态码,如200501,或者状态码系列的模式,如4xx5xx,并且您可以组合这两种风格。

默认情况下,如果response字段未指定任何代码,则假设为2xx系列。

依赖关系

~2.2-8MB
~60K SLoC