如果您正在使用 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 Guide 和 Community Handbook,以了解可供您使用的资源。加入社区 Slack 或 discussion forum 参与互动。
寻找你的 MeshMate
MeshMates 是经验丰富的社区成员,他们将帮助你熟悉环境、发现活跃项目并扩展你的社区网络。今天就与一位 Meshmate 建立联系!
在 Meshery community 上了解更多。
✔️ 参加 社区日历上的任何或所有每周会议。
✔️ 观看社区会议录像。
✔️ 填写 社区成员表格以获取社区资源访问权限。
✔️ 在 社区论坛中讨论。
✔️ 在 社区手册中探索更多内容。
不知道从哪里开始? 获取带有 help-wanted 标签的开放问题。
贡献
请这样做!我们是一个温暖且欢迎开源贡献者的社区。欢迎所有类型的贡献。请阅读:
- 通用贡献者指南 - 贡献流程概述
- Schema 贡献者指南 - Schema 特定的开发工作流程和指南
🧬 Schema 驱动开发指南
Meshery 采用 Schema-Driven Development (SDD) 方法。这意味着在整个系统中使用的 数据结构 通过 schemas 进行集中定义。这些 schemas 为 Meshery 平台提供一致性、验证和代码生成功能。
🧾 Meshery 中的 Schema 定义
Meshery 使用 OpenAPI v3 规范来定义和管理 schema。鉴于平台的复杂性,Meshery 采用了一种模块化、版本化且可扩展的 schema 策略:
- ✅ 用于向后兼容性的版本化 schema。
- 🧩 用于可维护性和复用的模块化结构。
- 🧪 Schema 被用于验证、API 文档和自动代码生成。
💡 提示:在 schema 中引用模型或其他结构时,始终添加
x-go-type和x-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>/– 表示一个版本(例如,v1alpha2、v1beta1)。<construct>/– 用于存放任何给定构造(construct)(如pattern、component等)所有文件的目录。api.yml– 该构造的索引文件。此文件:- 通过
$ref引用所有子模式(subschemas)以将它们捆绑在一起 - 定义该构造的所有 API 端点(REST 操作:GET、POST、PUT、DELETE)
- 作为代码生成工具(oapi-codegen、openapi-typescript)的入口点
- 通过
<construct>.yaml– 定义该构造数据模型(名词)的子模式。包含模式属性、类型和验证规则。- 其他
.yaml文件 – 可以在单独的文件中定义额外的子模式(例如,model_core.yml、component_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 响应中返回的完整服务端对象。它必须:
- 包含所有服务端生成的字段:
id、created_at、updated_at、deleted_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 模式
每个支持 POST 或 PUT 的实体必须在 api.yml 中定义一个专用的 {Entity}Payload 模式。该负载模式:
- 仅包含客户端可设置的字段(不包含
created_at、updated_at、deleted_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 会强制客户端提供服务器生成的字段(id、created_at、updated_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>.yaml在properties和required中列出了所有服务器生成的字段 -
api.yml定义了一个仅包含客户端可设置字段的{Construct}Payload模式 - 所有
POST/PUTrequestBody条目引用{Construct}Payload,而非{Construct} -
GET响应引用完整的{Construct}实体模式
命名约定
本节为内联权威说明;如需查阅面向读者的目录(包含 26 行命名表及前后对比与正误示例),请参阅
docs/identifier-naming-contributor-guide.md。
-
属性名称
- 属性字段使用 camelCase(例如,
schemaVersion、displayName、componentsCount)。 - 标识符字段使用带 "Id" 后缀的 lowerCamelCase(例如,
modelId、registrantId、categoryId)。 - 枚举使用小写单词(例如,
enabled、ignored、duplicate)。 - 对象名称使用单数名词(例如,
model、component、design)。
- 属性字段使用 camelCase(例如,
-
OpenAPI 模式名称
components/schemas下的 PascalCase 名词(例如,Model、Component)。- 文件/文件夹使用小写:
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/v1beta1、components.meshery.io/v1beta1)。- 版本字符串遵循 k8s 风格(
v1、v1alpha1、v1beta1);semver 字段使用标准 SemVer。
🔧 Go 辅助文件
虽然 Go 结构体是从模式自动生成的,但你通常需要添加自定义方法以使这些结构体与数据库兼容、实现接口或添加实用函数。这是通过手动创建的辅助文件来完成的。
何时创建辅助文件
当您需要以下功能时,在生成的包中创建一个辅助文件(*_helper.go 或 helpers.go):
- SQL 驱动兼容性 - 实现
database/sql/driver.Scanner和driver.Valuer接口 - 实体接口实现 - 为数据库操作实现
entity.Entity接口 - GORM 表名 - 通过
TableName()方法定义自定义表名 - 实用方法 - 添加用于序列化、验证或业务逻辑的辅助函数
- 类型转换 - 添加在相关类型之间进行转换的方法
辅助文件位置
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 数据库中存储复杂类型,请实现 Scan 和 Value 方法:
// 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"`
}
重要说明
- File Header Comment: Always add
// This is not autogenerated.at the top of helper files - Same Package: Helper files must be in the same package as the generated code
- Do Commit Helper Files: Unlike generated
.gofiles, helper files ARE committed to the repository - 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 的作用:
- Bundles OpenAPI schemas 用于:
- Meshery
- 远程提供商(例如 Meshery Cloud)
- 组合(所有构造)
- 生成:
- Golang 结构体 →
models/- TypeScript 类型定义(
.d.ts) →typescript/generated/ - TypeScript 模式导出(
*Schema.ts) →typescript/generated/ - RTK Query 客户端 →
typescript/rtk/
- TypeScript 类型定义(
npm run build之后:
- 构建分发文件 →
dist/- 创建 CJS 和 ESM 捆绑包
- 生成声明文件
⚠️ 这是与 schema 变更保持同步的推荐方式。
🧱 捆绑的 Schema 输出
运行 make build 后,将创建三个捆绑的 schema 文件:
| 文件 | 用途 |
|---|---|
merged_schema.yml | 所有 schema 的合并(供 Meshery 客户端使用) |
cloud_schema.yml | 远程提供程序(例如 Meshery Cloud)的特定云 API |
meshery_schema.yml | Meshery 特定 API |
✍️ 标注 OpenAPI 路径
若要控制每个打包输出中包含哪些 schema 路径,请在 OpenAPI 操作(get、post 等)中使用 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 驱动辅助方法(Scan 和 Value)。
何时使用:被注释的模式类型必须同时满足以下两个条件:
- 它具有专用的 OpenAPI 模式定义(即,它是一个具有显式属性的命名组件,而非通用映射)。
- 它作为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.Scanner 和 driver.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 客户端之前,请确保您已具备以下条件:
-
已安装所需的依赖项:
@reduxjs/toolkit@meshery/schemas
-
设置环境变量:
RTK_CLOUD_ENDPOINT_PREFIX:Cloud API 端点的基础 URLRTK_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();
// ...
}
故障排除
常见问题
-
加载状态卡住:
- 验证环境变量是否正确设置
- 检查 CORS 问题
- 确保包含正确的身份验证头
-
循环导入:
- 始终从特定的 API 文件导入 (
cloudApi.ts,mesheryApi.ts) - 避免从通用的
api.ts文件导入
- 始终从特定的 API 文件导入 (
-
多个 RTK 实例:
- 确保正确注册 reducer 和 middleware
- 检查 reducerPaths 中的命名冲突
Redux DevTools
为了更好地进行调试,请使用 Redux DevTools 监控:
- API 请求生命周期
- 状态变更
- 缓存行为
最佳实践
-
处理加载状态:
const { data, isLoading, isFetching, error } = useGetDataQuery(); -
利用缓存选项:
const { data } = useGetDataQuery(null, { pollingInterval: 30000, // Re-fetch every 30 seconds refetchOnMountOrArgChange: true, skip: !isReady // Skip query when not ready }); -
必要时使用变换:
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 结构体。
| 阶段 | 功能 | 执行内容 |
|---|---|---|
| 1 | oapi-codegen | 根据 schema 属性名(原样)生成带有 json 标签的 Go 结构体 |
| 2 | addYamlTags() | 将每个 json 标签值复制到 yaml 标签 |
| 3 | removeSelfReferentialAliases() | 当同一包中存在手动定义时,移除 type X = X 别名 |
| 4 | addSchemaExtraTags() | 将 db、gorm 等从 x-oapi-codegen-extra-tags 合并到结构体标签中 |
| 5 | rewriteExternalRefAliases() | 将导入别名从不透明名称规范化为可读名称 |
| 6 | validateReadableImportAliases() | 验证没有残留的不透明导入别名 |
| 7 | addCompatibilityParameterAliases() | 添加向后兼容的参数类型别名 |
| 8 | ensureRequiredImports() | 当内联的 x-go-type 需要时,添加缺失的 Go 导入(例如 uuid) |
| 9 | validateGeneratedDbTags() | 验证 schema 中声明的每个 db: 标签都存在于生成的 Go 代码中 |
| 10 | validateGeneratedJsonTags() | 验证生成的 Go 代码中的每个 json: 标签都与 schema 属性名匹配 |
属性名是 json 线格式的唯一事实来源。oapi-codegen 原样读取它(阶段 1),并且 validateGeneratedJsonTags 确认它在流水线中保持不变(阶段 10)。
✅ 摘要
| 任务 | 命令 |
|---|---|
| 生成所有内容 | make build |
| 构建 TypeScript dist | npm run build |
| 仅生成 Go 代码 | make golang-generate |
| 生成 TS 类型 + schemas | make 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 是云原生计算基金会项目
