# @abapify/speci 中文文档

规范地址：https://npmcn.com/package/%40abapify/speci/

版本：0\.4\.34
npm 元数据更新时间：2026-11-02T23:20:21.346Z
中文译文更新时间：2026-11-06T03:04:05.885Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40abapify/speci
原文对照：https://npmcn.com/package/%40abapify/speci/?lang=original
项目主页：https://github.com/abapify/adt-cli/tree/main/packages/speci#readme
源码仓库：https://github.com/abapify/adt-cli

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：90.6 kB，16 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：0 个
- 首次发布：2026-04-20T21:10:46.340Z
- 最新版本发布：2026-11-02T23:20:21.009Z
- 近 30 天下载量：5950（2026-10-05 至 2026-11-03，npm 官方下载统计）
- 已发布版本数：31（近 12 个月 31 个）

## 中文简介

TypeScript 最小箭头功能合同规格系统

## 安装

```sh
npm install @abapify/speci
```

也可以使用：`pnpm add @abapify/speci`、`yarn add @abapify/speci`、`bun add @abapify/speci`

## README

# 光谱

[![version](https://img.shields.io/github/package-json/v/abapify/adt-cli?filename=packages/speci/package.json)](https://github.com/abapify/adt-cli/pkgs/npm/%40abapify%2Fspeci)

**TypeScript 最小箭头功能合同规格系统**

零取装饰. 零号DSL. 零从属. 仅仅是 TypeScript 箭头函数 .

部分 **ADT 工具包** 基础 - 见 [主读取器](https://npmcn.com/package/README.md) 建筑概况.

## 哲学

端点 = 箭头函数,其参数定义了合同,而返回值则定义了操作.

```typescript
import { http } from '@abapify/speci/rest';

// Shortcut syntax - super clean!
const updateUser = (id: string, user: UserInput) =>
  http.put<User>(`/users/${id}`, user);
```

这在保持最低水平和TypeScript-native的同时,表现极强. 在快捷键语法中选择简单或完整的语法来控制.

## 以 ts-xsd 开发

斯佩克是紧密结合 [t-xsd](https://npmcn.com/package/%40abapify/ts-xsd) 支助 **基于XML的合同**虽然大多数REST图书馆都假设JSON, Speci是 `Serializable<T>` 接口可以与 XML 计划无缝地融合 :

```typescript
import { parse, build, type XsdSchema, type InferXsd } from 'ts-xsd';
import { http } from '@abapify/speci/rest';

// ts-xsd schema with parse/build
const TransportSchema = {
  /* ... */
} as const satisfies XsdSchema;
type Transport = InferXsd<typeof TransportSchema>;

const transportApi = {
  // Speci infers types from ts-xsd's Serializable interface
  create: (transport: Transport) =>
    http.post<Transport>('/transports', transport),
};
```

这使得Speci对于使用XML(SAP APT,SOAP服务等)的企业API来说是理想的,同时保持与Zod等基于JSON的策略完全兼容.

## 模块结构

Speci被组织成特定协议模块:

-   **`speci`** - 核心类型和公用事业(议定书不可知性)
-   **`speci/rest`** - REST API(帮助者、类型、客户端生成)
-   **`speci/openapi`** - OpenAPI生成(计划)
-   **`speci/cli`** - 生产(计划)CLI
-   **`speci/graphql`** - 图QL(计划)
-   **`speci/grpc`** - gRPC(计划)

每个协议模块都是自成一体的,有自己的类型,帮助者,以及客户端生成.

## 安装

```bash
npm install speci
# or
bun add speci
```

## 快速启动

### 1\. 确定合同

```typescript
import { http, type RestContract } from '@abapify/speci/rest';

// Define schemas (use any schema library: Zod, JSON Schema, etc.)
interface User {
  id: string;
  name: string;
  email: string;
}

interface CreateUserInput {
  name: string;
  email: string;
}

interface ErrorResponse {
  error: string;
  message: string;
}

// Define your API contract - choose your style!
export const api = {
  users: {
    // Shortcut syntax - just specify the success type
    list: () => http.get<User[]>('/users'),

    // Full syntax - explicit control over all responses
    get: (id: string) =>
      http.get(`/users/${id}`, {
        responses: {
          200: undefined as unknown as User,
          404: undefined as unknown as ErrorResponse,
        },
      }),

    // Shortcut - pass body directly
    create: (user: CreateUserInput) => http.post<User>('/users', user),

    // Full syntax with body and responses
    update: (id: string, user: Partial<User>) =>
      http.put(`/users/${id}`, {
        body: user,
        responses: {
          200: undefined as unknown as User,
          404: undefined as unknown as ErrorResponse,
        },
      }),

    // Shortcut - defaults to 204 response
    delete: (id: string) => http.delete(`/users/${id}`),
  },
} satisfies RestContract;
```

### 2\. 生成一个输入客户端

```typescript
import {
  createClient,
  createFetchAdapter,
  HttpError,
} from '@abapify/speci/rest';

const client = createClient(api, {
  baseUrl: 'https://api.example.com',
  adapter: createFetchAdapter(),
});

// Use it with full type safety - returns only success types
const users = await client.users.list(); // Type: User[]
const user = await client.users.get('123'); // Type: User

// Errors are thrown as HttpError with typed payloads
try {
  const user = await client.users.get('999');
} catch (error) {
  if (client.users.get.isError(error)) {
    // error.payload is typed as ErrorResponse!
    console.error(error.status, error.payload.error);
  }
}
```

## 核心概念

### 结束点描述符

每个端点由返回描述符的箭头函数定义:

```typescript
const endpoint = (...params) => ({
  method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS',
  path: '/path/with/${params}',
  body: any, // Request body schema
  query: any, // Query parameters schema
  headers: any, // Headers schema
  responses: {
    // Response schemas by status code
    200: SuccessSchema,
    400: ErrorSchema,
  },
  metadata: {
    // Optional metadata
    description: 'Endpoint description',
    tags: ['user', 'admin'],
    deprecated: false,
  },
});
```

### HTTP 帮助对象

这个 `@abapify/speci/rest` 模块提供 `http` 所有 HTTP 方法的对象 :

```typescript
import { http } from '@abapify/speci/rest';

// Shortcut syntax - super clean!
http.get<SuccessType>(path); // GET with 200 response
http.post<SuccessType>(path, body); // POST with 201 response
http.put<SuccessType>(path, body); // PUT with 200 response
http.patch<SuccessType>(path, body); // PATCH with 200 response
http.delete(path); // DELETE with 204 response

// Full syntax - explicit control
http.get(path, { responses: { 200: Type, 404: Error } });
http.post(path, { body, responses: { 201: Type, 400: Error } });

// Examples
const getUser = (id: string) => http.get<User>(`/users/${id}`);
const createUser = (user: CreateUserInput) => http.post<User>('/users', user);
```

**为什么 `http` 对象?** 这个 `delete` 关键词在 JavaScript 中保留, 因此我们使用 `http.delete` 而不是独立的 `delete` 函数.

### 司马支持

Speci 支持 **任何计划库** - 佐德,JSON斯克马,定制计划等等。 使用 `schema()` 干净语法的助手 :

```typescript
import { z } from 'zod';
import { schema } from '@abapify/speci/rest';

// Zod schemas
const UserSchema = z.object({
  id: z.string(),
  name: z.string(),
  email: z.string().email(),
});

type User = z.infer<typeof UserSchema>;

const api = {
  getUser: (id: string) =>
    http.get(`/users/${id}`, {
      responses: { 200: schema(UserSchema, {} as User) }, // ✅ Schema + type
    }),
};

// Custom schemas (e.g., XML schemas for ADT)
const ClassSchema = {
  element: 'class',
  attributes: ['name', 'type'],
  // ... your schema definition
};

interface ClassXml {
  name: string;
  type: string;
  // ... type definition
}

const adtApi = {
  getClass: (name: string) =>
    http.get(`/classes/${name}`, {
      responses: { 200: schema(ClassSchema, {} as ClassXml) }, // ✅ Schema + type
    }),
};
```

**如何运作:**

-   `schema(schemaObject, {} as Type)` 提供运行时间计划和编译时间类型
-    **适配器** 查看 schema 对象,并将其用于分析/验证
-   TypeScript 为全类型安全查看类型
-   只类型断言仍然有效 : `undefined as unknown as Type`

这让斯佩克 **计划不可知** - 用你喜欢的验证库!

### 全球错误反应

避免在所有端点重复错误类型 :

```typescript
import { createHttp } from '@abapify/speci/rest';

// 1. Define global error responses
const globalErrors = {
  400: undefined as unknown as ApiError,
  401: undefined as unknown as ApiError,
  403: undefined as unknown as ApiError,
  404: undefined as unknown as ApiError,
  500: undefined as unknown as ApiError,
} as const;

// 2. Create http instance with global errors
const api = createHttp(globalErrors);

// 3. Now only specify success responses!
const userApi = {
  list: () => api.get<User[]>('/users'),
  // 400, 401, 403, 404, 500 automatically added!

  get: (id: string) => api.get<User>(`/users/${id}`),
  // Global errors merged automatically

  create: (user: CreateUserInput) => api.post<User>('/users', user),
  // All endpoints get global errors
};
```

### 路径参数

路径参数自动从模板文字中提取 :

```typescript
const getPost = (userId: string, postId: string) =>
  http.get<Post>(`/users/${userId}/posts/${postId}`);

// Speci automatically maps:
// - First param (userId) → ${userId} in path
// - Second param (postId) → ${postId} in path
```

### 处理错误

错误显示为 `HttpError` 带有打出的有效载荷:

```typescript
import { HttpError } from '@abapify/speci/rest';

try {
  const user = await client.users.get('123');
  // user is typed as User (not User | ErrorResponse)
} catch (error) {
  // Option 1: Use endpoint-specific type guard
  if (client.users.get.isError(error)) {
    // error.payload is typed as ErrorResponse
    console.error(`HTTP ${error.status}:`, error.payload.error);
  }

  // Option 2: Generic HttpError check
  else if (error instanceof HttpError) {
    console.error(`HTTP ${error.status}:`, error.payload);
  }

  // Option 3: Network or other errors
  else {
    console.error('Network error:', error);
  }
}
```

### 自定义 HTTP 适配器

斯佩克是适应者-不可知论者. 带上您的 HTTP 客户端 :

```typescript
import type { HttpAdapter } from '@abapify/speci/rest';

const myAdapter: HttpAdapter = {
  async request({ method, url, body, query, headers }) {
    // Use any HTTP client: axios, got, ky, wretch, etc.
    return await yourHttpClient.request({ method, url, body, query, headers });
  },
};

const client = createClient(api, {
  baseUrl: 'https://api.example.com',
  adapter: myAdapter,
});
```

### 截取器

添加请求/答复/截取器:

```typescript
const client = createClient(api, {
  baseUrl: 'https://api.example.com',
  adapter: createFetchAdapter(),

  // Add auth token to all requests
  onRequest: async (options) => ({
    ...options,
    headers: {
      ...options.headers,
      Authorization: `Bearer ${getToken()}`,
    },
  }),

  // Transform responses
  onResponse: async (response) => {
    console.log('Response:', response);
    return response;
  },

  // Handle errors
  onError: async (error) => {
    console.error('Error:', error);
    throw error;
  },
});
```

## Speci 能够生成的

从你的箭形功能合同中,斯佩克可以生成:

-   ✅ **类型客户端** (已执行)
-   🚧 **服务器路由** (计划)
-   🚧 **OpenAPI 规格** (计划)
-   🚧 **模拟服务器** (计划)
-   🚧 **测试固定装置** (计划)
-   🚧 **CLI 工具** (计划)
-   🚧 **图QL 计划** (计划)
-   🚧 **gRPC 定义** (计划)

## 为什么是箭头函数?

✅ **没有类型脚本 AST 解析** - TS 给您本地函数类型  
✅ **无装饰器** - 他们是可选的合成糖  
✅ **没有模板升解析** - 简单的可变提取  
✅ **完全可读** - 看起来像普通域号  
✅ **完全可见** - 所有REST/HATEOAS/GRPC概念都可以包起来  
✅ **零框架组合** - 纯类型脚本

## 从Ts -rest来?

Speci使用相同的合同第一哲学,但带有箭头功能:

```typescript
// ts-rest
const contract = c.router({
  getUser: {
    method: 'GET',
    path: '/users/:id',
    responses: { 200: UserSchema },
  },
});

// Speci
const contract = {
  getUser: (id: string) => http.get<User>(`/users/${id}`),
};
```

同样的安全性, 少了锅炉板。 选择 ts-rest 表示成熟度, Speci 表示简单和 XML 支持 .

## 与 ts-rest 比较

[ts-resst (英语)](https://ts-rest.com/) 是一个优秀的,成熟的图书馆 用于类型的安全 REST 合同 我们推荐它 用于大多数使用案例。 斯佩克涵盖您需要的特定情景: **动态路由作为函数** (终点定义为有参数的箭头函数), **方案的灵活性** (通过适配器,而不仅仅是Zod)和a **灵活插件系统** 用于自定义扩展。 如果Ts -rest的第一合同方法对你有用,就使用它——它经过了战斗测试和生产准备.

## 与其他工具的比较

| 特性 | 标本 | ts-resst (英语) | tRPC 主题 | 打开API |
| --- | --- | --- | --- | --- |
| **语法** | 箭头函数 | 构建器 API | 程序 | 也门/日本 |
| **类型安全** | 满分 | 满分 | 满分 | 编码源 |
| **依赖关系** | 0 个 | 少数 | 许多 | 许多 |
| **学习曲线** | 最小值 | 低级 | 中型 | 高级 |
| **客户端** | 对 | 对 | 对 | 对 |
| **服务器** | 计划数 | 对 | 对 | \* 部分内容 |
| **验证** | 计划数 | 祖德 苏德 | 祖德 苏德 | 变相 |

## 文档

-   [体参数推论](https://npmcn.com/package/%40abapify/speci/docs/body-inference.md) - 从计划自动推断身体类型

## 许可证

麻省理工学院

## 捐款

欢迎捐款! 这是v0.1 - 最小可行的核心。 未来版本将增加:

-   服务器适配器(Express, Fastify, Hono等)
-   OpenAPI 生成
-   模拟服务器生成
-   Schema验证(佐德,JSON Schema等)
-   还有更多!

## 常见问题

### @abapify/speci 是什么？

TypeScript 最小箭头功能合同规格系统

### 如何安装 @abapify/speci？

在项目目录运行 npm install @abapify/speci，或使用 pnpm add / yarn add / bun add。

### @abapify/speci 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @abapify/speci 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @abapify/speci 可以商用吗？

@abapify/speci 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @abapify/speci 的下载量有多少？

根据 npm 官方下载统计，@abapify/speci 在 2026/10/05 – 2026/11/03 这 30 天内被下载 5,950 次，日均约 198 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @abapify/speci 还在维护吗？

最新版本 0\.4\.34 发布于 2026/11/03（3 天前）；至今共发布 31 个版本，其中过去 12 个月发布了 31 个；首次发布于 2026/04/21。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

