Skip to content

feat: add tag api#3

Merged
sorphwer merged 10 commits intomainfrom
feat/add-image-api
Nov 13, 2025
Merged

feat: add tag api#3
sorphwer merged 10 commits intomainfrom
feat/add-image-api

Conversation

@ZhouhaoJiang
Copy link
Collaborator

🚀 Feature: RESTful API for Programmatic Access

📝 概述

本 PR 为 dify-helm-watchdog 添加了完整的 RESTful API,允许其他应用(Terraform、CI/CD、Python 脚本等)以编程方式访问 Helm Chart 版本信息、镜像列表和验证数据。

✨ 新增功能

API 端点

端点 方法 描述
/api/versions GET 列出所有缓存的 Helm Chart 版本
/api/versions/latest GET 获取最新版本信息及相关链接
/api/versions/{version} GET 获取指定版本的详细元数据
/api/versions/{version}/images GET 获取镜像列表(支持 JSON/YAML 格式)
/api/versions/{version}/values GET 下载完整的 values.yaml
/api/versions/{version}/validation GET 获取镜像可用性验证结果

主要特性

  • 多格式支持 - JSON/YAML 格式切换(?format=json|yaml
  • 可选验证信息 - 通过 ?include_validation=true 获取镜像可用性状态
  • HTTP 缓存 - 所有端点支持 CDN 缓存(1小时 + stale-while-revalidate)
  • 统一错误处理 - 标准化的错误响应格式
  • 完整文档 - API 文档 + 快速开始指南 + 测试脚本
  • 零破坏性变更 - 完全向后兼容,原有功能不受影响

📁 文件变更

新增文件

src/app/api/versions/
├── route.ts                               # 版本列表 API
├── latest/
│   └── route.ts                           # 最新版本快捷方式
└── [version]/
    ├── route.ts                           # 版本详情 API
    ├── images/
    │   └── route.ts                       # 镜像列表 API (核心)
    ├── values/
    │   └── route.ts                       # values.yaml 下载
    └── validation/
        └── route.ts                       # 镜像验证结果

docs/
├── API.md                                 # 完整 API 文档 (773 行)
└── QUICKSTART.md                          # 5分钟快速上手指南

scripts/
└── test-api.sh                            # 自动化测试脚本

修改文件

README.md                                  # 更新功能列表,添加 API 文档链接

🎯 使用场景

1. Terraform 集成

data "http" "dify_images" {
  url = "https://your-domain.com/api/versions/latest/images"
}

locals {
  images = jsondecode(data.http.dify_images.body).images
}

resource "helm_release" "dify" {
  # 使用最新的镜像标签
  set {
    name  = "api.image.tag"
    value = local.images[0].tag
  }
}

2. CI/CD Pipeline

# 获取最新版本
VERSION=$(curl -s https://your-domain.com/api/versions/latest | jq -r '.version')

# 获取镜像列表(YAML 格式)
curl -s "https://your-domain.com/api/versions/$VERSION/images?format=yaml"

# 下载 values.yaml
curl -s "https://your-domain.com/api/versions/$VERSION/values" -o values.yaml

3. Python 自动化

import requests

# 获取最新版本
latest = requests.get("https://your-domain.com/api/versions/latest").json()

# 获取镜像列表(包含验证信息)
images = requests.get(
    f"https://your-domain.com/api/versions/{latest['version']}/images",
    params={"include_validation": "true"}
).json()

4. Dify Workflow

通过 HTTP 节点调用 API,实现版本检查和自动通知。

🧪 测试

运行测试脚本

# 测试本地开发环境
./scripts/test-api.sh

# 测试生产环境
./scripts/test-api.sh https://your-production-domain.com

测试覆盖

  • ✅ 版本列表获取(带/不带验证统计)
  • ✅ 最新版本获取
  • ✅ 版本详情获取
  • ✅ 镜像列表获取(JSON/YAML 格式)
  • ✅ 镜像验证信息
  • ✅ values.yaml 下载
  • ✅ 验证结果获取
  • ✅ 错误处理(404 等)

📚 文档

完整 API 文档

docs/API.md - 773 行完整文档,包含:

  • 所有端点的详细说明
  • 请求/响应示例
  • 6 个真实应用场景(Terraform、CI/CD、Python、yq、Dify、Ansible)
  • 错误处理指南
  • 性能优化建议
  • 缓存策略说明

快速开始指南

docs/QUICKSTART.md - 5 分钟上手指南:

  • 最常用的 3 个 API 调用
  • 实用脚本示例
  • Python 示例代码
  • 常见问题解答

🔧 技术实现

API 设计原则

  1. RESTful 风格 - 遵循标准 REST 约定
  2. 向后兼容 - 不影响现有功能
  3. 性能优先 - 充分利用 HTTP 缓存和 ISR
  4. 灵活性 - 多格式支持,可选字段

缓存策略

Cache-Control: public, s-maxage=3600, stale-while-revalidate=86400
  • CDN 缓存:1 小时
  • 过期后可用期:24 小时(同时后台更新)

响应格式

成功响应

{
  "version": "1.0.0",
  "total": 10,
  "images": [...]
}

错误响应

{
  "error": "Error type",
  "message": "Detailed error message",
  "availableVersions": ["..."]  // 可选
}

🎨 代码质量

  • ✅ TypeScript 严格类型检查
  • ✅ 无 ESLint 错误
  • ✅ 统一的错误处理模式
  • ✅ 完整的 JSDoc 注释
  • ✅ 遵循项目现有代码风格

🚀 部署说明

无需额外配置

本 PR 不需要任何额外的环境变量或配置。所有新端点使用现有的:

  • BLOB_READ_WRITE_TOKEN (已配置)
  • ENABLE_LOCAL_MODE (开发环境)
  • 现有的缓存机制

兼容性

  • ✅ 向后兼容 - 原有端点 /api/cache/api/cron 继续工作
  • ✅ 零配置 - 部署后立即可用
  • ✅ 渐进式采用 - 可以逐步迁移到新 API

📊 影响评估

正面影响

  1. 可编程访问 - 支持自动化工具链集成
  2. 提升效率 - 减少手动操作,支持 CI/CD
  3. 更好的可用性 - 清晰的 API 设计和完整文档
  4. 扩展性 - 为未来功能(如 AST 生成)奠定基础

性能影响

  • 最小化 - 利用现有缓存机制,无额外数据库查询
  • CDN 友好 - 所有响应可被 CDN 缓存
  • 按需加载 - 大文件(values.yaml)仅在请求时加载

维护成本

  • - 复用现有的 loadCache() 和存储逻辑
  • 文档完善 - 减少支持负担
  • 测试覆盖 - 自动化测试脚本

✅ Checklist

  • 所有新端点已实现
  • TypeScript 类型定义完整
  • 无 linter 错误
  • 编写完整 API 文档(773 行)
  • 编写快速开始指南
  • 创建测试脚本
  • 更新 README.md
  • 向后兼容性验证
  • 错误处理测试
  • HTTP 缓存配置
  • 多格式支持测试(JSON/YAML)

🔮 未来计划(可选)

后续可考虑添加:

  1. API 3: 更新 AST - POST /api/images/update-ast

    • 生成用于更新 values.yaml 的结构化数据
    • 支持生成 Helm、yq、Terraform 命令
  2. 镜像对比 - POST /api/images/compare

    • 对比两个版本的镜像差异
  3. Webhook 通知 - 新版本发布时自动通知

📸 示例截图

API 响应示例

$ curl https://your-domain.com/api/versions/latest/images?format=yaml

api:
  repository: langgenius/dify-api
  tag: "0.7.0"
worker:
  repository: langgenius/dify-worker
  tag: "0.7.0"
frontend:
  repository: langgenius/dify-web
  tag: "0.7.0"

测试脚本输出

================================================
  Dify Helm Watchdog API 测试
  Base URL: http://localhost:3000
================================================

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 1. 列出所有版本
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
测试: GET /api/versions ... ✓ PASS (HTTP 200)
测试:   检查 total 字段 ... ✓ PASS (total = 50)
测试:   检查 versions 数组 ... ✓ PASS (versions | length = 50)

...

================================================
  测试总结
================================================
✅ 通过: 20
❌ 失败: 0

🎉 所有测试通过!

审查要点

请重点关注:

  1. API 设计 - 端点命名、参数设计是否合理
  2. 错误处理 - 边界情况是否覆盖完整
  3. 文档质量 - 是否清晰易懂
  4. 向后兼容 - 是否影响现有功能
  5. 性能影响 - 缓存策略是否合理

欢迎提出任何建议和改进意见!

@vercel
Copy link

vercel bot commented Nov 11, 2025

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

Project Deployment Preview Comments Updated (UTC)
dify-helm-watchdog Ready Ready Preview Comment Nov 13, 2025 6:32am

@ZhouhaoJiang
Copy link
Collaborator Author

纯 vibe 的

@ZhouhaoJiang ZhouhaoJiang marked this pull request as ready for review November 11, 2025 03:32
@sorphwer
Copy link
Owner

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

这个 PR 为 programmatic access 引入了一套完整的 RESTful API,这是一个非常棒的功能。API 设计结构清晰,遵循了 REST 原则,并且实现中包含了多格式支持(JSON/YAML)和灵活的缓存策略等深思熟虑的特性。文档异常详尽,为 Terraform、CI/CD 和 Python 脚本等多种场景提供了出色的用例。

然而,我发现了一个贯穿所有动态路由处理器([version])的严重问题:请求中的 params 对象的类型定义和访问方式不正确,它被错误地当作一个 Promise。这将导致运行时错误,并使这些端点无法工作。我已在每个受影响的文件中提供了修复建议。

此外,我还提供了一些建议,以提高 API 文档中示例脚本的健壮性和性能。

总的来说,这是一次高质量的贡献。一旦解决了路由参数的严重问题,这个 PR 就可以合并了。

@sorphwer
Copy link
Owner

/gemini I notice that the cron API now supports GET and bots may trigger them, is it true?

@gemini-code-assist
Copy link
Contributor

您好,感谢您的提问!

关于 /api/cron 端点:

  1. 支持 GET 请求:是的,README.md 中明确指出 /api/cron 支持 GET 请求来运行同步任务(也支持 POST)。这意味着通过 GET 访问该端点会触发数据同步。
  2. 机器人触发:任何公开可访问的 GET 端点都有可能被机器人触发。因此,如果该端点是公开的,机器人确实可能会触发它。

需要注意的是,这个 GET 支持在本次 PR 之前就已经存在于 README.md 中,并非本次 PR 新增的功能。它的主要作用是用于触发缓存数据的同步更新。

如果您担心频繁的机器人触发可能导致不必要的资源消耗,可以考虑以下几点(这属于现有功能的优化建议,而非本次 PR 的问题):

  • 速率限制 (Rate Limiting):为 /api/cron 端点添加速率限制,以防止短时间内被频繁调用。
  • 认证 (Authentication):如果同步任务需要更高的安全性,可以考虑为该端点添加某种形式的认证(例如 API Key),使其不再是完全公开的。

希望这能解答您的疑问!

ZhouhaoJiang and others added 2 commits November 12, 2025 13:40
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@sorphwer
Copy link
Owner

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

这是一个出色的拉取请求,为项目引入了一套设计良好且功能全面的 RESTful API。代码结构清晰,新增的 API 端点覆盖了所有核心功能,并且提供了极其详尽的文档,这将极大地便利自动化和程序化集成。我的审查意见主要集中在两个方面:一是提升代码在处理外部数据时的健壮性,以防止潜在的运行时错误;二是在 API 文档中提供更具弹性的代码示例,以改善用户体验。总体而言,这是一项高质量的贡献。

Comment on lines 110 to 122
const validation = JSON.parse(validationText) as {
images?: ImageValidationRecord[];
};
// 创建一个映射表,方便查找
validationData = {};
for (const img of validation.images || []) {
const key = `${img.sourceRepository}:${img.sourceTag}`;
validationData[key] = {
status: img.status,
targetImageName: img.targetImageName,
variants: img.variants,
};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

这里的 JSON.parse 配合类型断言 as { images?: ImageValidationRecord[] } 存在一定的风险。如果 validationText 解析后的 images 字段存在但不是一个数组(例如是 null 或一个对象),validation.images || [] 的行为可能不符合预期,for...of 循环会抛出运行时错误。

虽然外层的 try...catch 会捕获这个错误,但更健壮的做法是在访问前明确检查 images 是否为数组。

建议修改以更安全地处理可能格式不正确的数据,避免意外的运行时错误,并使代码更加稳健。

Suggested change
const validation = JSON.parse(validationText) as {
images?: ImageValidationRecord[];
};
// 创建一个映射表,方便查找
validationData = {};
for (const img of validation.images || []) {
const key = `${img.sourceRepository}:${img.sourceTag}`;
validationData[key] = {
status: img.status,
targetImageName: img.targetImageName,
variants: img.variants,
};
}
const validation = JSON.parse(validationText);
// 创建一个映射表,方便查找
validationData = {};
if (validation && Array.isArray(validation.images)) {
for (const img of validation.images) {
const key = `${img.sourceRepository}:${img.sourceTag}`;
validationData[key] = {
status: img.status,
targetImageName: img.targetImageName,
variants: img.variants,
};
}
}

Comment on lines 50 to 53
const validation = JSON.parse(validationText) as {
images?: ImageValidationRecord[];
};
const images = validation.images || [];
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

与另一个路由文件中的问题类似,这里对 JSON.parse 的结果使用了不安全的类型断言。如果 validation.images 字段存在但不是数组,validation.images || [] 可能会导致 filter 方法调用失败,从而引发运行时错误。

为了增强代码的健壮性,建议在处理 images 字段前,先验证其是否为数组。这样可以确保 images 变量始终是一个数组,从而安全地调用数组方法,使函数对异常数据有更好的容错能力。

    const validation = JSON.parse(validationText);
    const images = validation?.images && Array.isArray(validation.images) ? validation.images : [];

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@sorphwer sorphwer merged commit 644aa96 into main Nov 13, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants