Skip to content

Add RBAC, dynamic schema linking, protocol extensibility, and conflict resolution to API Registry#484

Merged
hotlong merged 4 commits into
copilot/manage-api-registration-unificationfrom
copilot/add-unified-api-registry
Feb 2, 2026
Merged

Add RBAC, dynamic schema linking, protocol extensibility, and conflict resolution to API Registry#484
hotlong merged 4 commits into
copilot/manage-api-registration-unificationfrom
copilot/add-unified-api-registry

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 2, 2026

Enhances the Unified API Registry with four enterprise-grade capabilities identified in architectural review: automatic permission enforcement, self-updating API schemas, multi-protocol plugin support, and deterministic route conflict resolution.

Changes

1. RBAC Integration

  • requiredPermissions field on endpoints enables gateway-level authorization
  • Supports object permissions (customer.read) and system permissions (manage_users)
  • Eliminates per-handler permission checks
ApiEndpointRegistration.create({
  path: '/api/v1/customers/:id',
  requiredPermissions: ['customer.read'],  // Auto-enforced at gateway
  responses: [...]
});

2. Dynamic Schema Linking

  • ObjectQLReferenceSchema links API schemas to ObjectQL objects
  • API documentation auto-updates when object definitions change
  • Supports field inclusion/exclusion and relation expansion
{
  statusCode: 200,
  schema: {
    $ref: {
      objectId: 'customer',
      excludeFields: ['password_hash'],
      includeRelated: ['account']
    }
  }
}

3. Protocol Extensibility

  • protocolConfig field allows plugins to define protocol-specific metadata
  • Supports gRPC, tRPC, WebSocket without core code changes
  • Enables protocol-specific UI rendering
{
  protocolConfig: {
    subProtocol: 'grpc',
    serviceName: 'CustomerService',
    methodName: 'GetCustomer'
  }
}

4. Route Conflict Resolution

  • priority field (0-1000) for deterministic route ordering
  • conflictResolution strategy enum: error | priority | first-wins | last-wins
  • Prevents silent plugin route overwrites
ApiRegistry.create({
  conflictResolution: 'priority',
  apis: [{
    endpoints: [{
      path: '/api/v1/data/:object',
      priority: 950  // Core API wins over plugins
    }]
  }]
});

Backward Compatibility

All fields are optional with sensible defaults:

  • requiredPermissions: [] (public)
  • priority: 100 (medium)
  • conflictResolution: 'error' (fail-safe)

Test Coverage

  • 53 test cases covering all enhancement scenarios
  • Integration tests combining all features
  • 3,129 total tests passing
Original prompt

拉取请求: #483

这份修改方案(PR #483)提出的 统一 API 注册表 (Unified API Registry) 方案非常合理,且是构建企业级低代码平台(尤其是涉及多协议、多插件架构时)的关键基础设施。

它填补了之前架构中“如何管理异构 API”的空白,完美呼应了战略路线图中的“生态系统建设”和“开发者体验”目标。

以下是基于现有 API 协议的详细评估:

✅ 方案的合理性与亮点

  1. 解决了“协议碎片化”问题

    • 在一个微内核架构(Microkernel Architecture)中,核心系统通常只通过 REST/GraphQL 暴露标准 CRUD,但插件往往需要暴露特殊的端点(如支付回调 Webhook、即时通讯 WebSocket、老旧系统的 OData)。
    • 该方案通过 ApiProtocolType 枚举(支持 rest, graphql, odata, websocket, file, plugin 等)将这些异构协议统一纳管,使得前端或网关层可以统一处理路由和文档。
  2. 文档与测试的“协议优先”落地

    • 通过 documentation.zod.ts 定义了文档生成的元数据(OpenAPI Spec),这意味着系统可以自动为所有注册的 API(包括插件的)生成 Swagger/Redoc 文档。
    • 这对于低代码平台至关重要:用户安装一个插件后,立刻能在统一的 API Portal 中看到并测试该插件的 API,无需查阅分散的 PDF 或 Markdown 文档。
  3. 插件机制的良好支持

    • ApiRegistryEntry 包含 metadata.pluginSource,这允许系统追踪 API 的来源,方便在卸载插件时自动注销对应的 API,维护系统的整洁。

⚠️ 改进意见与潜在风险

虽然方案整体优秀,但为了更好地与 Roadmap 中的其他协议(如 RBAC、ObjectQL)融合,建议进行以下优化:

1. 🔐 安全定义的集成 (Security Integration)

  • 当前问题ApiEndpointRegistrationSchema 中的 security 字段目前沿用了 OpenAPI 的标准定义(如 oauth2, apiKey)。
  • 改进建议
    • 增加 requiredPermissions 字段:企业级应用的核心是权限。建议在 Schema 中明确集成 ObjectStack 的 RBAC 协议
    • 这样,网关层(Gateway)可以自动拦截没有 user.readorder.delete 权限的请求,而不需要每个 API 处理函数自己去写权限判断逻辑。
    • 代码示例
      // 建议增加
      permissions: z.array(z.string()).describe('Required RBAC permissions, e.g. "user.read"'),

2. 🔄 数据模型的动态链接 (Schema Linkage)

  • 当前问题ApiResponseSchemaApiParameterSchema 中的 schema 字段类型是 z.any()。这意味着注册表存储的是“静态快照”。
  • 改进建议
    • 支持引用 ObjectQL 对象:如果 API 返回的是系统中的标准对象(如 Customer),建议允许直接引用对象名,而不是复制一份 JSON Schema。
    • 价值:当用户修改了 Customer 对象的字段(如增加“VIP等级”),API 文档和 Mock 数据能自动更新,无需重新注册 API。
    • 代码示例
      // 允许直接引用对象 ID
      schema: z.union([
        z.any(), // 原有的 JSON Schema
        z.object({ objectId: z.string() }) // 动态链接到 ObjectQL 定义
      ])

3. 🧩 协议类型的扩展性 (Protocol Extensibility)

  • 当前问题ApiProtocolType 是一个硬编码的 z.enum。如果未来你想支持 gRPCtRPC,需要修改核心代码。
  • 改进建议:虽然 enum 对核心协议没问题,但对于 plugin 类型,建议允许插件在 config 字段中定义具体的子协议类型,以便前端 UI 能根据子类型渲染不同的测试界面(例如 gRPC 需要不同的测试工具)。

4. 🏷️ 路由冲突检测 (Route Conflict Detection)

  • 建议:在实施指南中补充说明:当多个插件注册了相同的 path(例如都想监听 /api/v1/webhook)时,注册表应该采取什么策略?(报错?覆盖?还是按优先级?)建议增加 priority 字段或明确“先到先得/报错”的机制。

结论

批准该方案 (Approve)
它是实现“全球最顶流企业管理软件平台”愿景中API 网关开发者门户的基石。上述改进意见可以在后续的 PEP 迭代中逐步完善,不影响当前架构的正确性。

建议合并后,下一步优先实现基于此注册表的 "API Explorer"(API 浏览器) 插件,直观展示其价值。


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 2, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Feb 2, 2026 5:41am

Request Review

Copilot AI and others added 3 commits February 2, 2026 05:36
…otocol extensibility, and conflict resolution

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…ments

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…hancements

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Add unified API registry for enterprise low-code platform Add RBAC, dynamic schema linking, protocol extensibility, and conflict resolution to API Registry Feb 2, 2026
Copilot AI requested a review from hotlong February 2, 2026 05:40
@hotlong hotlong marked this pull request as ready for review February 2, 2026 05:42
Copilot AI review requested due to automatic review settings February 2, 2026 05:42
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests size/xl labels Feb 2, 2026
@hotlong hotlong merged commit d2dfbf2 into copilot/manage-api-registration-unification Feb 2, 2026
9 checks passed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request enhances the Unified API Registry (from PR #483) with four enterprise-grade capabilities identified during architectural review: RBAC integration, dynamic schema linking via ObjectQL references, protocol extensibility, and route conflict resolution.

Changes:

  • Added requiredPermissions field for gateway-level authorization (RBAC)
  • Introduced ObjectQLReferenceSchema for linking API schemas to ObjectQL objects with field-level control
  • Added protocolConfig field for protocol-specific metadata (gRPC, tRPC, WebSocket support)
  • Implemented route conflict resolution with priority field and ConflictResolutionStrategy enum

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/spec/src/api/registry.zod.ts Core schema enhancements: ObjectQL references, RBAC permissions, priority-based routing, and conflict resolution
packages/spec/src/api/registry.test.ts Comprehensive test coverage with 25 new tests for all enhancement features
packages/spec/src/api/registry.example.ts Production-ready examples demonstrating all four enhancement capabilities
packages/spec/json-schema/api/SchemaDefinition.json Generated JSON schema placeholder (build artifact)
packages/spec/json-schema/api/ObjectQLReference.json Generated JSON schema placeholder (build artifact)
packages/spec/json-schema/api/ConflictResolutionStrategy.json Generated JSON schema placeholder (build artifact)
API_REGISTRY_ENHANCEMENTS.md Comprehensive documentation of implementation, benefits, and usage patterns

Comment on lines +140 to +145
schema: {
$ref: {
objectId: 'customer',
// Only allow these fields in creation
includeFields: ['name', 'email', 'phone', 'company'],
},
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example demonstrates using ObjectQL references in request body schemas, but the actual ApiEndpointRegistrationSchema.requestBody.schema field (line 357 in registry.zod.ts) uses z.any() and does not support ObjectQL references like parameters and responses do. This example will accept the $ref syntax without validation. To make this example work correctly, the requestBody.schema field should be updated to use the same union type as parameters and responses.

Suggested change
schema: {
$ref: {
objectId: 'customer',
// Only allow these fields in creation
includeFields: ['name', 'email', 'phone', 'company'],
},
// Explicit schema listing only the fields allowed for creation
schema: {
type: 'object',
properties: {
name: { type: 'string' },
email: { type: 'string', format: 'email' },
phone: { type: 'string' },
company: { type: 'string' },
},
required: ['name', 'email'],
additionalProperties: false,

Copilot uses AI. Check for mistakes.
* }
* ```
*
* @see {@link file://../../permission/permission.zod.ts} for permission definitions
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file reference path is incorrect. The path file://../../permission/permission.zod.ts should be file://../permission/permission.zod.ts (only one level up, not two). The current file is at packages/spec/src/api/registry.zod.ts and the permission file is at packages/spec/src/permission/permission.zod.ts, which is one directory level up from api.

Suggested change
* @see {@link file://../../permission/permission.zod.ts} for permission definitions
* @see {@link file://../permission/permission.zod.ts} for permission definitions

Copilot uses AI. Check for mistakes.
Comment on lines +135 to +138
z.any().describe('Static JSON Schema definition'),
z.object({
$ref: ObjectQLReferenceSchema.describe('Dynamic reference to ObjectQL object'),
}).describe('Dynamic ObjectQL reference'),
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SchemaDefinition union type has a critical design flaw. Using z.any() as the first option in a union means it will always match first, preventing the ObjectQL reference schema from ever being validated. The union should either:

  1. Remove the z.any() option entirely and require explicit schemas, or
  2. Use discriminated union with a property to distinguish between static and dynamic schemas (e.g., a type field), or
  3. Place the more specific $ref object schema first in the union order.

However, option 3 won't work reliably because the $ref schema will still match any object with a $ref property. The best solution is a discriminated union or removing z.any() altogether.

Suggested change
z.any().describe('Static JSON Schema definition'),
z.object({
$ref: ObjectQLReferenceSchema.describe('Dynamic reference to ObjectQL object'),
}).describe('Dynamic ObjectQL reference'),
z.object({
$ref: ObjectQLReferenceSchema.describe('Dynamic reference to ObjectQL object'),
}).describe('Dynamic ObjectQL reference'),
z.record(z.unknown()).describe('Static JSON Schema definition'),

Copilot uses AI. Check for mistakes.
Comment on lines +252 to +255
z.any().describe('Static JSON Schema'),
z.object({
$ref: ObjectQLReferenceSchema,
}).describe('Dynamic ObjectQL reference'),
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The response schema union has the same critical flaw as SchemaDefinition. Using z.any() as the first option means it will always match, preventing ObjectQL references from being validated. The union should place the more specific schema (the object with $ref) first, or better yet, not use z.any() at all. Consider using a more specific static schema type or implementing a discriminated union to properly distinguish between static and dynamic schemas.

Suggested change
z.any().describe('Static JSON Schema'),
z.object({
$ref: ObjectQLReferenceSchema,
}).describe('Dynamic ObjectQL reference'),
z.object({
$ref: ObjectQLReferenceSchema,
}).describe('Dynamic ObjectQL reference'),
z.any().describe('Static JSON Schema'),

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants