@mittwald/api-models

中文文档
4.509.0发布于 2026/11/02MITTypeScriptES Module构建来源已验证

用于与API进行一致交互的领域模型的集合

中文使用文档
文档目录17 节
  1. 许可证
  2. 安装
  3. 设置
  4. 示例
  5. React中的用法
  6. 安装
  7. 不变性和状态更新
  8. 贡献
  9. 文件结构
  10. 使用基类
  11. 坚持使用通用语言
  12. 作为抽象层的模型
  13. 模型类型
  14. 使用正确的动词
  15. 访问“链接”模型
  16. 模型行为的抽象
  17. 为React做准备

mittwald API模型

这个包包含了一组用于连贯交互的领域模型 使用mittwald API。

许可证

版权所有:Mittwald CM Service GmbH & Co. KG

本项目(以及其中的所有NPM软件包)在MIT许可下获得许可; 看到 许可证 文件查看详细信息。

安装

你可以从普通的NPM注册表中安装这个包:

yarn add @mittwald/api-models

设置

您将需要初始化API客户端,以便对模型进行操作 由这个包提供。使用 api 初始化的全局实例 一些方法。

import { api } from "@mittwald/api-models";

api.setupWithApiToken(process.env.MW_API_TOKEN);

示例

  • 一、 Reference 或者 ReferenceModel 代表一个特定的模型 ID。
  • 一、 DetailedModel 包含资源的所有数据。

有关更详细的描述,请参阅本节 模型类型

// Get a detailed project
const detailedProject = await Project.get("p-vka9t3");

// Create a project reference
const projectRef = Project.ofId("p-vka9t3");

// Get the detailed project from the reference
const anotherDetailedProject = await projectRef.getDetailed();

// Update project description
await detailedProject.updateDescription("My new description!");

// This method just needs the ID and a description and
// thus is also available on the reference
await projectRef.updateDescription("My new description!");

// Accessing the projects server reference
const server = project.server;

// List all projects of this server
const serversProjects = await server.projects.execute();

// List all projects
const allProjects = await Project.query().execute();

// Iterate over project List Models
for (const project of serversProjects) {
  await project.leave();
}

React中的用法

这个包还提供了在React组件中使用的方法。它 使用 @mittwald / react-use-promise 将所有异步函数封装到AsyncResources中。更多的细节 关于如何使用AsyncResources,请参阅包文档。

安装

要使用React客户端,您必须安装附加的 @mittwald/react-use-promise 包:

yarn add @mittwald/react-use-promise

所有异步方法都提供 use方法属性。这种方法使用 @mittwald / react-use-promise 在底层以“React的方式”“解析”承诺。

const detailedProject = Project.get.use("p-vka9t3");

// Create a project reference
const projectRef = Project.ofId("p-vka9t3");

// Get the detailed project from the reference
const anotherDetailedProject = projectRef.getDetailed.use();

// Accessing the projects server reference
const server = project.server;

// List all projects of this server
const serversProjects = server.projects.execute.use();

// List all projects
const allProjects = Project.query().execute.use();

不变性和状态更新

这个包提供的大多数模型都代表了一个相关的对应部分 在后端。当从后端加载模型时,当前状态为 合并到模型实例中。为了保持简单和可预测 状态是不可变的,在任何情况下都不会改变. 结果是 您必须创建一个新实例来获取更新的模型并传播它 整个运行时代码。

这也适用于在客户端发起的操作。例如,当 updateDescription 方法在项目上调用时,项目实例将调用 仍然有旧的描述。

“关注变化”不在本包的范围内,将在 未来版本或其他包™️。

贡献

作为一般的建议,在贡献时,一定要查看现有的源代码 编写代码并将其用作模板!

在添加或修改模型时,请考虑以下约定。

文件结构

在有意义的目录中构建模型。

使用基类

模型应该扩展(或继承)正确的基类。你可以找到底 类 src/base. 以下是可用的类。

DataModel

数据模型是所有模型类的基础,这些模型类包含一组 不可变的通用数据。

ReferenceModel

ReferenceModel仅通过其ID表示某个模型。作为最基本的 模型操作通常只需要ID和一些输入数据(删除、重命名、 …),参考模型可以避免不必要的API往返。

坚持使用通用语言

在添加模型或方法时,请密切关注(可能存在的) 在各自领域中使用的语言。如果是的话,可以和负责的团队谈谈 不确定的。

作为抽象层的模型

模型应涵盖以下几个方面:

  • 业务逻辑的一致表示
  • 简单加载模型及其链接实体
  • 以直观的方式与模型交互的方法
  • 对模型原始数据进行预处理,增加DX
  • 一致的API

模型类型

详细模型vs.列表模型

加载单个项目或组件时,某些模型的响应类型通常不同 列表。为了减少数据量,列表响应类型通常是一个子集 的综合模型。为详细模型添加单独的类(命名它) [Model]Detailed)和列表模型(命名它 [Model]ListItem)。

如果两个模型共享一个公共代码库,您应该添加一个公共模型(命名它) [Model]Common)。

参考模型

参考模型仅通过其ID表示某个模型。作为最基本的 模型操作通常只需要ID和一些输入数据(删除、重命名、 …),参考模型可以避免不必要的API往返。这些类 应该用作新创建模型或链接模型的返回类型。

要得到实际的详细模型,参考模型 必须 有一个 function getDetailed(): Promise<ModelDetailed> 和 function findDetailed(): Promise<ModelDetailed|undefined> 方法。

在实现入口点模型时考虑扩展参考模型。

查询模型

查询模型通常需要一个查询对象——或者短查询。查询 主要包括分页设置,如 limit, skip 或者 page. 它也可能 包括以下过滤器 fromDate 或者 toDate,并过滤到其他模型,如 customerId.

查询模型表示对特定模型的特定查询,并且应该包括 以下方法:

  • execute():执行查询并返回相应的List Model
  • refine(overrideQuery):创建一个新的查询模型,其中包含一个精细化的查询对象
  • getTotalCount():获取查询的总计数(使用) limit: 0)

当一个模型支持查询时,它应该提供一个静态 query() 方法 创建各自的查询模型。

当一个模型被用作查询模型中的查询参数时,该模型应该 在该查询模型的参考模型中有一个属性。请参阅以下内容 例子:

class Server {
  public readonly projects: ProjectsListQuery;

  public constructor(id: string) {
    this.projects = new ProjectListQuery({
      server: this,
    });
  }
}

列表模式

列表模型是查询模型执行的结果。列表模型包括

  • 各自列表模型的列表,受分页配置的限制
  • 可用的总数(用于实现分页或计数数据)

列表模型应该扩展它们各自的查询模型,因为它可能是 也可以叫 refine() 在已执行的查询上。

实现细节

在实现共享功能时,例如在公共模型中,您可以使用 这个 polytype 图书馆实现 动态多重继承。请务必查看现有的源代码 实现的例子。

入口点模型

提供一个模型(命名它) [Model])作为所有不同的入口点 模型类型(详细的、查询的……)。作为惯例,为 这个模型。

使用正确的动词

find

入口点模型应该有一个静态的 find 方法。find方法返回 详细的模型或可返回 undefined 如果找不到型号。

get

除了 find 方法入口点模型应该有一个静态的 get 方法。get方法应该返回所需的对象或抛出一个 ObjectNotFoundError. 你可以使用 find 方法并断言存在 与 assertObjectFound 函数。

query

当需要查询对象列表时,使用 query 方法。它可能支持 query 参数以按给定条件过滤结果。

create

当应该创建模型时,请使用静态 create 方法。这种方法应该 返回已创建资源的引用。

访问“链接”模型

大多数模型都是更大的模型树的一部分。模型应该提供 属性来获取父模型和子模型,比如 project.server, server.projects 或者 server.customer.

使用参考模型。在可能的情况下使用入口点模型!

如果链接的模型提供了参考模型或入口点模型,则在 模型构造函数,以避免不必要的API往返。

模型行为的抽象

模型通常由一组行为支持,这些行为定义了基本模型 交互。为了实际“使用”模型,必须将其初始化为 具体的行为实现。这个抽象层移除 从模型中实现特定的代码,并生成行为 可交换而不会对模型本身产生任何影响-例如在单元内部 测试。

考虑使用以下行为:

  • API交互
  • 存储和加载本地数据
  • 复杂的计算或逻辑(可能由外部库支持)

将API交互封装在行为中

将任何API交互封装在模型行为中以防止强 模型和api特定实现的耦合。

不要🥴
class ProjectDetailed {
  public static async find(
    id: string,
  ): Promise<ProjProjectDetailed | undefined> {
    const response = await client.project.getProject({
      id,
    });

    if (response.status === 200) {
      return new Project(response.data.id, response.data);
    }
    assertStatus(response, 403);
  }
}
做😃
class ProjectDetailed {
  public static async find(id: string): Promise<ProjectDetailed | undefined> {
    const data = await config.project.behaviors.find(id);
    if (data !== undefined) {
      return new Project(data.id, data);
    }
  }
}

如何实现行为

放置一个 behaviors 模型内的文件夹,看起来应该是这样的:

Project/
├─ behaviors/
│  ├─ index.ts
│  ├─ types.ts (behavior interface)
│  ├─ api.ts   (behavior implementation)
│  ├─ inmem.ts (behavior implementation)

定义 types.ts 第一个

首先实现行为的接口是一个很好的起点。 接口通常只定义行为中使用的方法。就像

export interface ProjectBehaviors {
  find: (id: string) => Promise<ProjectData | undefined>;
  updateDescription: (projectId: string, description: string) => Promise<void>;
}

然后在全局行为配置中注册该行为 packages/models/src/config/config.ts.

使用模型中的行为

如果定义了行为接口,就可以开始实现模型了。你 还可以先实现具体的API行为,来“证明”该行为是什么 “使用”真正的API。

import { config } from "../../config/config.js";

class ProjectDetailed {
  public static async find(id: string): Promise<ProjectDetailed | undefined> {
    const data = await config.project.behaviors.find(id);
    if (data !== undefined) {
      return new Project(data.id, data);
    }
  }
}
实现API行为

API行为依赖于API客户端。您可以将该行为实现为 对象工厂,或实现接口的简单类。在使用 对象工厂,您不必重新声明方法参数类型。

做特定于实现的事情,从而准备和执行请求, 最后处理响应。

import { ProjectBehaviors } from "./types.js";
import { assertStatus, MittwaldAPIV2Client } from "@mittwald/api-client";

export const apiProjectBehaviors = (
  client: MittwaldAPIV2Client,
): ProjectBehaviors => ({
  find: async (id) => {
    const response = await client.project.getProject({
      projectId: id,
    });

    if (response.status === 200) {
      return response.data;
    }
    assertStatus(response, 403);
  },
});

为React做准备

所有异步方法都应该提供 use方法属性。这个方法 使用 @mittwald / react-use-promise 在底层以“React的方式”“解析”承诺。

为您提供此功能 异步 建模方法,包装实际方法 与 provideReact 增强剂。

class ProjectDetailed {
  public static find = provideReact(
    async (id: string): Promise<ProjectDetailed | undefined> => {
      const data = await config.behaviors.project.find(id);

      if (data !== undefined) {
        return new ProjectDetailed(data);
      }
    },
  );
}

版本与发布记录

@mittwald/api-models 共发布 689 个版本,首次发布于 2024/01/12;过去 12 个月发布了 366 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
4.509.0latest2026/11/021 天前
4.508.02026/11/012 天前
4.507.02026/10/313 天前
0.0.0-development-7d1b6db-20261028development2026/10/295 天前
4.506.02026/10/295 天前
0.0.0-development-492ba61-202610272026/10/286 天前

其他发布通道:alpha → 0.1.0-alpha.1,beta → 4.60.0-beta.4,development → 0.0.0-development-7d1b6db-20261028。

关于 @mittwald/api-models 的常见问题

@mittwald/api-models 是什么?

用于与API进行一致交互的领域模型的集合

如何安装 @mittwald/api-models?

在项目目录运行 npm install @mittwald/api-models,或使用 pnpm add / yarn add / bun add。

@mittwald/api-models 支持 TypeScript 吗?

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

@mittwald/api-models 支持 ESM 还是 CommonJS?

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

@mittwald/api-models 可以商用吗?

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

@mittwald/api-models 还在维护吗?

最新版本 4.509.0 发布于 2026/11/02(1 天前);至今共发布 689 个版本,其中过去 12 个月发布了 366 个;首次发布于 2024/01/12。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。