ITADN
meshery/schemas
README.md
以下内容由 AI 翻译,如有问题请点此提交 issue 反馈

Meshery Logo

如果您正在使用 Meshery 或喜欢该项目,请 此仓库以表示您的支持!🤩

Meshery Schemas

Meshery 遵循模式驱动开发。作为一个项目,Meshery 拥有不同类型的模式。一些模式是面向外部的,另一些则是 Meshery 内部使用的。此仓库作为存储模式的核心位置,供所有 Meshery 组件参考。

Meshery 模式提供了一个强大的系统,旨在:

  • 模型驱动管理: Meshery 使用显式模型来描述基础设施和应用程序。
  • 动态发现: 能够处理不同类型的关系和样式,从而构建一个可适应多种配置的复杂系统。
  • 生命周期管理: 模式属性用于跟踪资源的状态和生命周期。
  • 可扩展性: 开放式元数据和模块化模式组件支持扩展和自定义。
  • 可视化表示: 用于样式化边和节点的属性旨在创建用户友好的可视化表示。
  • 自动化操作: 模式可以支持基础设施和应用程序的验证、自动化配置以及补丁应用。

关于 Meshery 中模式、定义、声明和实例的术语解释,请参阅 Contributor's Guide to Models.

有关标识符命名规则(wire casing、DB tag 分隔、URL/path/query-param 约定、operationId 形式),请参阅 docs/identifier-naming-contributor-guide.md — 这是本仓库及所有下游消费者共享的 camelCase-on-the-wire 契约的规范且易于阅读的目录。

贡献

--> 有关本仓库目录结构的说明以及如何向 Meshery 的 schemas 贡献更改,请参阅 Contributor's Guide to Schema-Driven Development.

 

加入 Meshery 社区!

我们的项目由社区构建,欢迎协作。👍 请务必查看 Contributor Welcome GuideCommunity Handbook,以了解可供您使用的资源。加入社区 Slackdiscussion forum 参与互动。

寻找你的 MeshMate

MeshMates 是经验丰富的社区成员,他们将帮助你熟悉环境、发现活跃项目并扩展你的社区网络。今天就与一位 Meshmate 建立联系!

Meshery community 上了解更多。



Meshery Cloud Native Community

✔️ 参加 社区日历上的任何或所有每周会议。
✔️ 观看社区会议录像
✔️ 填写 社区成员表格以获取社区资源访问权限。
✔️ 社区论坛中讨论。
✔️ 社区手册中探索更多内容。

不知道从哪里开始? 获取带有 help-wanted 标签的开放问题。

 

贡献

请这样做!我们是一个温暖且欢迎开源贡献者的社区。欢迎所有类型的贡献。请阅读:

 

🧬 Schema 驱动开发指南

Meshery 采用 Schema-Driven Development (SDD) 方法。这意味着在整个系统中使用的 数据结构 通过 schemas 进行集中定义。这些 schemas 为 Meshery 平台提供一致性、验证和代码生成功能。


🧾 Meshery 中的 Schema 定义

Meshery 使用 OpenAPI v3 规范来定义和管理 schema。鉴于平台的复杂性,Meshery 采用了一种模块化、版本化且可扩展的 schema 策略:

  • ✅ 用于向后兼容性的版本化 schema
  • 🧩 用于可维护性和复用的模块化结构
  • 🧪 Schema 被用于验证、API 文档和自动代码生成。

💡 提示:在 schema 中引用模型或其他结构时,始终添加 x-go-typex-go-import-path,以避免生成冗余的 Go 结构体。请参考代码库中现有的模式。


📁 Schema 目录结构

所有 schema 均位于 Meshery 仓库根目录下的 schemas/ 目录中:

schemas/
  constructs/
    <schema-version>/               # e.g., v1beta1
      <construct>/                  # e.g., model, component
        api.yml                     # Index file: references all subschemas + defines API endpoints
        <construct>.yaml            # Subschema: data model definition for the construct
        <other_subschema>.yaml      # Additional subschemas (optional)
        templates/                  # Manually defined templates directory
          <construct>_template.json # JSON template from schema
          <construct>_template.yaml # YAML template from schema
          <variant>_template.json   # Additional variant templates (optional)
  
  typescript/                       # TypeScript source and generated files
    index.ts                        # Manually maintained - public API surface
    generated/                      # Auto-generated (do NOT commit)
      <schema-version>/
        <construct>/
          <Construct>.d.ts          # TypeScript type definitions
          <Construct>Schema.ts      # OpenAPI schema as JS object
    rtk/                            # RTK Query client configurations
      cloud.ts
      meshery.ts
  
  dist/                             # Built distribution (do NOT commit)
    index.js, index.d.ts
    cloudApi.js, mesheryApi.js
    constructs/                     # Built schema exports (renamed from 'generated')
      <schema-version>/<construct>/<Construct>Schema.js
  
  models/                           # Auto-generated Go code (do NOT commit)
    <schema-version>/
      <construct>/
        <construct>.go

🧠 说明

  • constructs/ – 保存各个版本的模式(schemas)。
    • <schema-version>/ – 表示一个版本(例如,v1alpha2v1beta1)。
      • <construct>/ – 用于存放任何给定构造(construct)(如 patterncomponent 等)所有文件的目录。
        • api.yml – 该构造的索引文件。此文件:
          1. 通过 $ref 引用所有子模式(subschemas)以将它们捆绑在一起
          2. 定义该构造的所有 API 端点(REST 操作:GET、POST、PUT、DELETE)
          3. 作为代码生成工具(oapi-codegen、openapi-typescript)的入口点
        • <construct>.yaml – 定义该构造数据模型(名词)的子模式。包含模式属性、类型和验证规则。
        • 其他 .yaml 文件 – 可以在单独的文件中定义额外的子模式(例如,model_core.ymlcomponent_metadata.yml),并从 api.yml 中引用。
        • templates/ – 包含手动定义的模板文件的子目录。您可以在此处添加任意数量的不同模板,用于不同的变体、用例或配置。模板是带有默认值或示例值的模式实例。
          • <construct>_template.json / <construct>_template.yaml – JSON/YAML 格式的默认模板。
          • 可以添加额外的变体模板(例如,<construct>_minimal_template.json<construct>_full_template.yaml)以用于不同的用例。

模式设计原则:双模式模式

Meshery 中的每个持久化实体都遵循严格的双模式契约。违反此契约会导致生成的 Go 结构体和 API 客户端不正确。

规则 1 — 实体模式 = 仅响应模式

<construct>.yaml 文件表示在 API 响应中返回的完整服务端对象。它必须:

  • 包含所有服务端生成的字段:idcreated_atupdated_atdeleted_at
  • required 中列出服务端生成的必填字段(它们在响应中始终存在)
  • 在顶层具有 additionalProperties: false
# keychain.yaml — response schema ✅
type: object
additionalProperties: false
required:
  - id
  - name
  - owner
  - created_at
  - updated_at
properties:
  id:
    $ref: ../../v1alpha1/core/api.yml#/components/schemas/uuid
  name:
    type: string
  owner:
    $ref: ../../v1alpha1/core/api.yml#/components/schemas/uuid
  created_at:
    $ref: ../../v1alpha1/core/api.yml#/components/schemas/created_at
  updated_at:
    $ref: ../../v1alpha1/core/api.yml#/components/schemas/updated_at
  deleted_at:
    $ref: ../../v1alpha1/core/api.yml#/components/schemas/nullTime

规则 2 — 写操作使用独立的 *Payload 模式

每个支持 POSTPUT 的实体必须在 api.yml 中定义一个专用的 {Entity}Payload 模式。该负载模式:

  • 仅包含客户端可设置的字段(不包含 created_atupdated_atdeleted_at
  • 对于 upsert 模式,使用 omitempty 使 id 变为可选,或者对于仅创建操作则完全省略它
  • POST/PUT 操作中被 requestBody 引用
  • 绝不被复用为响应体
# In api.yml — write schema ✅
components:
  schemas:
    KeychainPayload:
      type: object
      description: Payload for creating or updating a keychain.
      required:
        - name
      properties:
        id:
          $ref: ../../v1alpha1/core/api.yml#/components/schemas/uuid
          description: Existing keychain ID for updates; omit on create.
          x-oapi-codegen-extra-tags:
            json: "id,omitempty"
        name:
          type: string
          description: Name of the keychain.
        owner:
          $ref: ../../v1alpha1/core/api.yml#/components/schemas/uuid
          description: Owner UUID; set server-side from auth context if omitted.
          x-oapi-codegen-extra-tags:
            json: "owner,omitempty"

paths:
  /api/auth/keychains:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/KeychainPayload"   # ← Payload, not Keychain
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Keychain"        # ← Full entity in response

规则 3 — 切勿将实体模式用作 POST/PUT 请求体

使用完整的实体模式作为 requestBody 会强制客户端提供服务器生成的字段(idcreated_atupdated_at),并生成错误的客户端代码。

# ❌ Wrong — exposes server-generated required fields to clients
post:
  requestBody:
    content:
      application/json:
        schema:
          $ref: "#/components/schemas/Keychain"

# ✅ Correct — separate payload type for writes
post:
  requestBody:
    content:
      application/json:
        schema:
          $ref: "#/components/schemas/KeychainPayload"

添加新实体时的检查清单

  • <construct>.yaml 具有 additionalProperties: false
  • <construct>.yamlpropertiesrequired 中列出了所有服务器生成的字段
  • api.yml 定义了一个仅包含客户端可设置字段的 {Construct}Payload 模式
  • 所有 POST/PUT requestBody 条目引用 {Construct}Payload,而非 {Construct}
  • GET 响应引用完整的 {Construct} 实体模式

命名约定

本节为内联权威说明;如需查阅面向读者的目录(包含 26 行命名表及前后对比与正误示例),请参阅 docs/identifier-naming-contributor-guide.md

  • 属性名称

    • 属性字段使用 camelCase(例如,schemaVersiondisplayNamecomponentsCount)。
    • 标识符字段使用带 "Id" 后缀的 lowerCamelCase(例如,modelIdregistrantIdcategoryId)。
    • 枚举使用小写单词(例如,enabledignoredduplicate)。
    • 对象名称使用单数名词(例如,modelcomponentdesign)。
  • OpenAPI 模式名称

    • components/schemas 下的 PascalCase 名词(例如,ModelComponent)。
    • 文件/文件夹使用小写:api.yml(索引)、<construct>.yaml(子模式)、templates/<construct>_template.(json|yaml)
  • 端点与操作

    • 路径位于 /api 下,使用 kebab-case 复数名词(例如,/api/workspaces/api/environments)。
    • 路径参数使用 camelCase(例如,{subscriptionId}{connectionId})。
    • 非 CRUD 操作追加动词段(例如,.../register.../export.../cancel);可能出现遗留的 lowerCamelCase(例如,.../upgradePreview)。
    • operationId 使用 camelCase 动词名词(例如,registerMeshmodels)。
  • 版本控制

    • schemaVersion 使用组/版本(例如,models.meshery.io/v1beta1components.meshery.io/v1beta1)。
    • 版本字符串遵循 k8s 风格(v1v1alpha1v1beta1);semver 字段使用标准 SemVer。

🔧 Go 辅助文件

虽然 Go 结构体是从模式自动生成的,但你通常需要添加自定义方法以使这些结构体与数据库兼容、实现接口或添加实用函数。这是通过手动创建的辅助文件来完成的。

何时创建辅助文件

当您需要以下功能时,在生成的包中创建一个辅助文件(*_helper.gohelpers.go):

  1. SQL 驱动兼容性 - 实现 database/sql/driver.Scannerdriver.Valuer 接口
  2. 实体接口实现 - 为数据库操作实现 entity.Entity 接口
  3. GORM 表名 - 通过 TableName() 方法定义自定义表名
  4. 实用方法 - 添加用于序列化、验证或业务逻辑的辅助函数
  5. 类型转换 - 添加在相关类型之间进行转换的方法

辅助文件位置

models/
├── core/
│   ├── core.go                    # Auto-generated (do NOT edit)
│   ├── helpers.go                 # Manual: utility functions
│   ├── datatype_map.go            # Manual: Map type with SQL driver methods
│   └── datatype_null_time.go      # Manual: NullTime with SQL driver methods
├── v1beta1/
│   ├── model/
│   │   ├── model.go               # Auto-generated (do NOT edit)
│   │   └── model_helper.go        # Manual: Entity interface, TableName, etc.
│   ├── component/
│   │   ├── component.go           # Auto-generated (do NOT edit)
│   │   └── component_helper.go    # Manual: Entity interface, TableName, etc.
│   └── category/
│       ├── category.go            # Auto-generated (do NOT edit)
│       └── category_helper.go     # Manual: Entity interface, TableName, etc.

SQL 驱动程序接口实现

要在 SQL 数据库中存储复杂类型,请实现 ScanValue 方法:

// helpers.go - This is NOT autogenerated
package mypackage

import (
    "database/sql/driver"
    "encoding/json"
    
    "github.com/meshery/schemas/models/core"
)

// Scan implements sql.Scanner interface for reading from database
func (m *MyComplexType) Scan(value interface{}) error {
    mapVal := core.Map{}
    err := mapVal.Scan(value)
    if err != nil {
        return err
    }
    return core.MapToStruct(mapVal, m)
}

// Value implements driver.Valuer interface for writing to database
func (m MyComplexType) Value() (driver.Value, error) {
    mapVal, err := core.StructToMap(m)
    if err != nil {
        return nil, err
    }
    return core.Map(mapVal).Value()
}

实体接口实现

对于需要数据库 CRUD 操作的结构体,实现 entity.Entity 接口:

// component_helper.go - This is NOT autogenerated
package component

import (
    "fmt"
    
    "github.com/gofrs/uuid"
    "github.com/meshery/meshkit/database"
    "github.com/meshery/meshkit/models/meshmodel/entity"
    "gorm.io/gorm/clause"
)

// TableName returns the database table name for GORM
func (c ComponentDefinition) TableName() string {
    return "component_definition_dbs"
}

// Type returns the entity type identifier
func (c ComponentDefinition) Type() entity.EntityType {
    return entity.ComponentDefinition
}

// GenerateID generates a new UUID for the entity
func (c *ComponentDefinition) GenerateID() (uuid.UUID, error) {
    return uuid.NewV4()
}

// GetID returns the entity's ID
func (c ComponentDefinition) GetID() uuid.UUID {
    return c.Id
}

// GetEntityDetail returns a human-readable description
func (c *ComponentDefinition) GetEntityDetail() string {
    return fmt.Sprintf("type: %s, name: %s, model: %s", 
        c.Type(), c.DisplayName, c.Model.Name)
}

// Create inserts the entity into the database
func (c *ComponentDefinition) Create(db *database.Handler, hostID uuid.UUID) (uuid.UUID, error) {
    c.Id, _ = c.GenerateID()
    err := db.Omit(clause.Associations).Create(&c).Error
    return c.Id, err
}

// UpdateStatus updates the entity's status in the database
func (c *ComponentDefinition) UpdateStatus(db *database.Handler, status entity.EntityStatus) error {
    return nil
}

核心实用类型

models/core/ 包提供了内置 SQL 兼容性的可复用类型:

类型用途使用场景
core.Map支持 SQL 的 map[string]any在数据库中存储 JSON 对象
core.NullTime支持 JSON/YAML 的可空时间可选的时间戳字段
core.Time支持自定义格式的时间包装器必需的时间戳字段

示例:使用核心类型

// In your helper file
package mypackage

import "github.com/meshery/schemas/models/core"

// For nullable timestamps (e.g., deleted_at)
type MyStruct struct {
    DeletedAt core.NullTime `json:"deleted_at" gorm:"column:deleted_at"`
}

// For JSON metadata stored as blob
type MyStruct struct {
    Metadata core.Map `json:"metadata" gorm:"type:bytes;serializer:json"`
}

重要说明

  1. File Header Comment: Always add // This is not autogenerated. at the top of helper files
  2. Same Package: Helper files must be in the same package as the generated code
  3. Do Commit Helper Files: Unlike generated .go files, helper files ARE committed to the repository
  4. Mutex for Creation: Use sync.Mutex when implementing Create() to prevent race conditions

⚙️ 代码生成

Meshery 支持从 schema 进行自动化代码生成,适用于:

  • Go:用于后端的强类型模型 → models/<version>/<package>/
  • TypeScript Types:接口和类型定义 → typescript/generated/<version>/<package>/<Package>.d.ts
  • TypeScript Schemas:作为 const JS 对象的 OpenAPI schema → typescript/generated/<version>/<package>/<Package>Schema.ts
  • RTK Query:从 OpenAPI 生成用于 Redux 的客户端 → typescript/rtk/
  • JSON/YAML:包含默认值和已解析引用的模板。

TypeScript Schema 导出

每个构造的 OpenAPI schema 都作为 const JavaScript 对象导出,供运行时使用:

// Import from main index
import {
  ModelDefinitionV1Beta1OpenApiSchema,
  ComponentDefinitionV1Beta1OpenApiSchema,
  DesignDefinitionV1Beta1OpenApiSchema,
} from "@meshery/schemas";

// Or import individual schemas directly
import ModelSchema from "@meshery/schemas/dist/constructs/v1beta1/model/ModelSchema";
import ComponentSchema from "@meshery/schemas/dist/constructs/v1beta1/component/ComponentSchema";

TypeScript 类型命名空间

类型按版本在命名空间中组织:

import { v1beta1, v1alpha1 } from "@meshery/schemas";

const component: v1beta1.Component = { /* ... */ };
const model: v1beta1.Model = { /* ... */ };
const design: v1beta1.Design = { /* ... */ };

🚀 统一构建:一条命令搞定一切

使用以下命令执行完整的 schema 驱动生成工作流

make build
npm run build  # Build TypeScript distribution with tsup

🔧 make build 的作用:

  1. Bundles OpenAPI schemas 用于:
  • Meshery
    • 远程提供商(例如 Meshery Cloud)
    • 组合(所有构造)
  1. 生成:
  • Golang 结构体 → models/
    • TypeScript 类型定义(.d.ts) → typescript/generated/
    • TypeScript 模式导出(*Schema.ts) → typescript/generated/
    • RTK Query 客户端 → typescript/rtk/
  1. npm run build 之后:
  • 构建分发文件 → dist/
    • 创建 CJS 和 ESM 捆绑包
    • 生成声明文件

⚠️ 这是与 schema 变更保持同步的推荐方式。


🧱 捆绑的 Schema 输出

运行 make build 后,将创建三个捆绑的 schema 文件:

文件用途
merged_schema.yml所有 schema 的合并(供 Meshery 客户端使用)
cloud_schema.yml远程提供程序(例如 Meshery Cloud)的特定云 API
meshery_schema.ymlMeshery 特定 API

✍️ 标注 OpenAPI 路径

若要控制每个打包输出中包含哪些 schema 路径,请在 OpenAPI 操作(getpost 等)中使用 x-internal 注解。该注解在每个操作中均为必需 —— validate-schemas(规则 14)和打包器均会拒绝省略该注解的操作。

示例:

paths:
  /api/entitlement/plans:
    get:
      x-internal: ["cloud"]
      operationId: getPlans
      tags:
        - Plans
      summary: Get all plans supported by the system
      responses:
        "200":
          description: Plans fetched successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Plan"
  • x-internal: ["cloud"] — 仅包含在 cloud bundle 中。
  • x-internal: ["meshery"] — 仅包含在 meshery bundle 中。
  • x-internal: ["cloud", "meshery"] — 包含在两个 bundle 中。

x-generate-db-helpers

components/schemas 下的命名组件上使用 x-generate-db-helpers: true 作为模式级注释(而非针对单个属性),以指示 Go 生成器为该类型自动生成 SQL 驱动辅助方法(ScanValue)。

何时使用:被注释的模式类型必须同时满足以下两个条件:

  1. 它具有专用的 OpenAPI 模式定义(即,它是一个具有显式属性的命名组件,而非通用映射)。
  2. 它作为JSON 数据块存储在单个数据库列中——而不是分散在具有每个字段一列的专用表中。

何时不使用:不要注释没有固定模式定义的非结构化类型(例如,通用的 metadata 对象)。这些字段应改用 x-go-type: "core.Map"。也不要注释映射到具有每个属性对应单独列的完整数据库表的类型——这些由正常的 DB 标签生成处理。

示例

components:
  schemas:
    Quiz:
      x-generate-db-helpers: true   # ← schema-level; not on individual properties
      type: object
      required:
        - id
        - title
      properties:
        id:
          $ref: "../../v1alpha1/core/api.yml#/components/schemas/uuid"
        title:
          type: string

生成器生成包含以下内容:zz_generated.helpers.go

func (value *Quiz) Scan(src interface{}) error {
    if src == nil {
        *value = Quiz{}
        return nil
    }
    mapVal := core.Map{}
    if err := mapVal.Scan(src); err != nil {
        return err
    }
    return core.MapToStruct(mapVal, value)
}

func (value Quiz) Value() (driver.Value, error) {
    mapVal, err := core.StructToMap(value)
    if err != nil {
        return nil, err
    }
    return core.Map(mapVal).Value()
}

这些实现了 Go 的 sql.Scannerdriver.Valuer 接口,因此该结构体在从数据库列读取或写入时会被透明地序列化为 JSON。

反例 — metadata:以 JSON 形式存储在数据库中的 metadata 字段故意使用 x-generate-db-helpers 进行标注,因为它是非结构化的——它没有固定的属性列表。对于这些字段,请改用 x-go-type: "core.Map"

metadata:
  type: object
  additionalProperties: true
  x-go-type: "core.Map"
  x-go-type-skip-optional-pointer: true
  x-oapi-codegen-extra-tags:
    db: "metadata"

🛠️ 高级用法(可选)

📌 在 generate.sh 中自定义生成

Meshery 使用一个辅助脚本(generate.sh)将 schema 结构映射到生成的输出:

generate_schema_models <construct> <schema-version> [<openapi-file>]

generate_schema_models "capability" "v1alpha1"
generate_schema_models "category" "v1beta1"
generate_schema_models "pattern" "v1beta1" "schemas/constructs/v1beta1/design/api.yml"

这映射到如下 Go 包:

models/v1alpha1/capability/capability.go

🧩 RTK Query 客户端生成

OpenAPI 包会被传递给代码生成工具以生成 RTK Query 客户端。使用 x-internal 注释包含相关路径,并适当定义请求/响应模式。

您可以使用以下方式构建 OpenAPI 包:

# Build per-construct bundles, merge them, and emit cloud/meshery OpenAPI specs
make bundle-openapi

使用生成的 RTK Query 客户端

前提条件

在使用生成的 RTK 客户端之前,请确保您已具备以下条件:

  1. 已安装所需的依赖项:

    • @reduxjs/toolkit
    • @meshery/schemas
  2. 设置环境变量:

    • RTK_CLOUD_ENDPOINT_PREFIX:Cloud API 端点的基础 URL
    • RTK_MESHERY_ENDPOINT_PREFIX:Meshery API 端点的基础 URL

存储配置

正确导入 API 切片

为避免可能破坏应用程序的循环导入,请从各自的特定导出中导入 API 切片:

// ✅ Correct: Import from specific API exports
import { cloudApi as cloudBaseApi } from "@meshery/schemas/dist/cloudApi";
import { mesheryApi } from "@meshery/schemas/dist/mesheryApi";

// ❌ Incorrect: Do not import directly from generic API file
// import { api } from "@meshery/schemas/dist/api"; // Can cause cyclical imports

配置 Redux Store

将 API 的 reducers 和 middleware 添加到你的 Redux store 配置中:

import { combineReducers, configureStore } from "@reduxjs/toolkit";
import { cloudApi as cloudBaseApi } from "@meshery/schemas/dist/cloudApi";
import catalogReducer from "./slices/catalog";
import connectionReducer from "./slices/connection";
import organizationReducer from "./slices/organization";
import chartReducer from "./slices/charts";
import themeReducer from "./slices/theme";
// Optional: If you have locally defined APIs
import { cloudApi } from "../api";

// Combine reducers
const rootReducer = combineReducers({
  catalog: catalogReducer,
  charts: chartReducer,
  organization: organizationReducer,
  connection: connectionReducer,
  theme: themeReducer,
  // Add generated API reducers
  [cloudBaseApi.reducerPath]: cloudBaseApi.reducer,
  // Optional: Add locally defined API reducers
  [cloudApi.reducerPath]: cloudApi.reducer
});

// Configure store with middleware
export const store = configureStore({
  reducer: reduxPersist.createPersistEnhancedReducer(rootReducer),
  middleware: getDefaultMiddleware =>
    getDefaultMiddleware()
      // Add generated API middleware
      .concat(cloudBaseApi.middleware)
      // Optional: Add locally defined API middleware
      .concat(cloudApi.middleware)
      // Add persistence middleware if needed
      .concat(reduxPersist.persistMiddleware)
});

// Set up listeners for RTK Query cache behaviors like refetchOnFocus/refetchOnReconnect
setupListeners(store.dispatch);

使用 API 钩子

配置好您的商店后,您可以导入并使用生成的钩子:

云 API 钩子

import {
  useGetPlansQuery,
  useCreateDesignMutation,
  useGetDesignsQuery,
  // Other cloud API hooks...
} from "@meshery/schemas/dist/cloudApi";

function MyComponent() {
  // Use hooks directly in your components
  const { data: plans, isLoading, error } = useGetPlansQuery();

  // Handle loading states
  if (isLoading) return <div>Loading plans...</div>;

  // Handle errors
  if (error) return <div>Error loading plans</div>;

  // Use data
  return (
    <div>
      {plans.map(plan => (
        <div key={plan.id}>{plan.name}</div>
      ))}
    </div>
  );
}

Meshery API 钩子

import {
  useGetMeshModelsQuery,
  useSubmitMeshConfigMutation,
  // Other Meshery API hooks...
} from "@meshery/schemas/dist/mesheryApi";

function MesheryComponent() {
  const { data: meshModels } = useGetMeshModelsQuery();
  // ...
}

故障排除

常见问题

  1. 加载状态卡住:

    • 验证环境变量是否正确设置
    • 检查 CORS 问题
    • 确保包含正确的身份验证头
  2. 循环导入:

    • 始终从特定的 API 文件导入 (cloudApi.ts, mesheryApi.ts)
    • 避免从通用的 api.ts 文件导入
  3. 多个 RTK 实例

    • 确保正确注册 reducer 和 middleware
    • 检查 reducerPaths 中的命名冲突

Redux DevTools

为了更好地进行调试,请使用 Redux DevTools 监控:

  • API 请求生命周期
  • 状态变更
  • 缓存行为

最佳实践

  1. 处理加载状态:

    const { data, isLoading, isFetching, error } = useGetDataQuery();
  2. 利用缓存选项

    const { data } = useGetDataQuery(null, {
      pollingInterval: 30000, // Re-fetch every 30 seconds
      refetchOnMountOrArgChange: true,
      skip: !isReady // Skip query when not ready
    });
  3. 必要时使用变换

    const transformedData = data?.map(item => ({
      ...item,
      formattedValue: formatValue(item.value)
    }));

🧪 测试与验证 Schemas

在提交之前,通过运行以下命令来验证您的模式更新:

make build

对于仓库验证检查:

make validate-schemas

模式验证

validation/ Go 包(通过 go run ./cmd/validate-schemas 调用)强制执行 41 条规则,这些规则分为四个问题层级。不同的 make 目标控制哪些层级可见,以及违规是否会阻止构建。

模式命令阻止风格设计契约
构建默认make validate-schemas退出码 1静默静默静默
建议性审计make audit-schemas退出码 0静默可见可见
完整建议性积压make audit-schemas-full退出码 0静默可见可见
风格债务报告make audit-schemas-style-full退出码 0可见可见可见
完整债务报告make audit-schemas-debt-full退出码 0可见可见可见
严格 CI 门禁make validate-schemas-strict退出码 1错误错误错误
  • 阻止(规则 1-2, 5, 11-22, 27, 32-33):始终强制执行。破坏代码生成或违反结构契约。
  • 风格(规则 3-4, 6-10, 19):命名约定。默认静默;使用 --style-debt 时可见;使用 --strict-consistency 时阻止。
  • 设计(规则 23-26, 30-31):API 设计模式。在 --warn 模式下作为建议可见。
  • 契约(规则 28-29):已发布的 API 契约检查(响应代码、重复模式)。在 --warn 模式下作为建议可见。

运行验证逻辑的单元测试:

go test ./validation/...

构建流水线

make build 按顺序执行 8 个步骤。每个步骤都依赖于前一个步骤。

schemas/constructs/          (OpenAPI YAML source files)
        |
        v
[1] validate-schemas         go run ./cmd/validate-schemas
        |                    41 rules: casing, dual-schema, templates, pagination
        v
[2] bundle-openapi           node build/bundle-openapi.js
        |                    Per-construct: in-repo dereference to merged-openapi.json
        |                    Merge all: in-repo prefixing merge → merged_openapi.yml
        |                    Filter: cloud_openapi.yml, meshery_openapi.yml
        v
[3] generate-golang          node build/generate-golang.js
        |                    Per-package: oapi-codegen → models/<ver>/<pkg>/<pkg>.go
        |                    Post-processing pipeline (see below)
        v
[4] generate-rtk             node build/generate-rtk.js
        |                    RTK Query clients from bundled OpenAPI specs
        v
[5] generate-ts              npm run generate:types
        |                    openapi-typescript → typescript/generated/<ver>/<pkg>/
        v
[6] generate-permissions     Go + TypeScript permission key generation
        v
[7] build-ts                 npm run build (tsup)
        |                    Bundles TypeScript distribution → dist/
        v
[8] test-golang              go build ./... && go test ./...

Go 生成流水线

build/generate-golang.js 为每个包运行一个 10 阶段的流水线。该流水线生成、转换并验证 Go 结构体。

阶段功能执行内容
1oapi-codegen根据 schema 属性名(原样)生成带有 json 标签的 Go 结构体
2addYamlTags()将每个 json 标签值复制到 yaml 标签
3removeSelfReferentialAliases()当同一包中存在手动定义时,移除 type X = X 别名
4addSchemaExtraTags()dbgorm 等从 x-oapi-codegen-extra-tags 合并到结构体标签中
5rewriteExternalRefAliases()将导入别名从不透明名称规范化为可读名称
6validateReadableImportAliases()验证没有残留的不透明导入别名
7addCompatibilityParameterAliases()添加向后兼容的参数类型别名
8ensureRequiredImports()当内联的 x-go-type 需要时,添加缺失的 Go 导入(例如 uuid
9validateGeneratedDbTags()验证 schema 中声明的每个 db: 标签都存在于生成的 Go 代码中
10validateGeneratedJsonTags()验证生成的 Go 代码中的每个 json: 标签都与 schema 属性名匹配

属性名是 json 线格式的唯一事实来源。oapi-codegen 原样读取它(阶段 1),并且 validateGeneratedJsonTags 确认它在流水线中保持不变(阶段 10)。


✅ 摘要

任务命令
生成所有内容make build
构建 TypeScript distnpm run build
仅生成 Go 代码make golang-generate
生成 TS 类型 + schemasmake generate-ts
Schema 验证(阻塞)make validate-schemas
Schema 审计(建议性)make audit-schemas
完整 schema 债务报告make audit-schemas-debt-full
验证单元测试npm run test:validate-schemas

导入 Schemas

// Via namespaces (types)
import { v1beta1 } from "@meshery/schemas";
const model: v1beta1.Model = { /* ... */ };

// Via schema exports (runtime)
import { ModelDefinitionV1Beta1OpenApiSchema } from "@meshery/schemas";

// Direct schema import
import ModelSchema from "@meshery/schemas/dist/constructs/v1beta1/model/ModelSchema";

许可证

本仓库和网站以开源形式提供,遵循 Apache 2.0 许可证] 的条款。

MESHERY 是云原生计算基金会项目