乐于分享
好东西不私藏

OpenClaw 30 天系列 - Day 20:API 集成:调用外部 API、Webhook、数据同步

OpenClaw 30 天系列 - Day 20:API 集成:调用外部 API、Webhook、数据同步

🎯 学习目标:学会调用外部 API、Webhook、数据同步

⏱️ 阅读时间:约 12 分钟 

💡 前置要求:无


🔌 API 集成能做什么?

核心能力总览

能力
说明
使用场景
HTTP 请求
调用 REST/GraphQL API
获取数据、提交表单
Webhook
接收外部事件通知
实时同步、自动触发
数据同步
定时同步多系统数据
数据备份、报表生成
认证管理
管理 API 密钥和 Token
安全访问、自动刷新

🌐 HTTP 请求

基础使用

module.exports = {name'http-request',asyncexecute({ method, url, headers, body }) {try {const response = awaitfetch(url, {        method,headers: {'Content-Type''application/json',          ...headers        },body: body ? JSON.stringify(body) : undefined      });if (!response.ok) {thrownewError(`HTTP ${response.status}${response.statusText}`);      }const data = await response.json();return data;    } catch (error) {console.error('HTTP 请求失败:', error);throw error;    }  }};

调用第三方 API

场景 1:天气 API

module.exports = {name'weather-api',asyncexecute({ city }) {try {const response = awaitfetch(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${process.env.WEATHER_API_KEY}&units=metric&lang=zh_cn`      );const data = await response.json();return`🌤️ ${data.name} 天气🌡️ 温度:${data.main.temp}°C💧 湿度:${data.main.humidity}%💨 风速:${data.wind.speed} m/s🌤️ 状况:${data.weather[0].description}      `.trim();    } catch (error) {console.error('天气查询失败:', error);throw error;    }  }};

场景 2:GitHub API

module.exports = {name'github-api',asyncexecute({ action, repo, params }) {constBASE_CONFIG = {baseUrl'https://api.github.com',headers: {'Authorization'`token ${process.env.GITHUB_TOKEN}`,'Accept''application/vnd.github.v3+json'      },maxDisplayItems10    };if (!action) thrownewError('缺少必要参数:action');if (!repo) thrownewError('缺少必要参数:repo');try {constfetchGitHubData = async (endpoint) => {const response = awaitfetch(`${BASE_CONFIG.baseUrl}${endpoint}`, {headersBASE_CONFIG.headers        });if (!response.ok) {const errorData = await response.json().catch(() => ({ message'未知错误' }));thrownewError(`GitHub API 请求失败 [${response.status}]:${errorData.message}`);        }return response.json();      };const actionConfig = {issues: {endpoint`/repos/${repo}/issues`,titlePrefix'📋',itemFormatter(issue) =>`#${issue.number}${issue.title} (${issue.state})`        },pr: {endpoint`/repos/${repo}/pulls`,titlePrefix'🔀',itemFormatter(pr) =>`#${pr.number}${pr.title} by ${pr.user?.login || '未知用户'}`        }      };const config = actionConfig[action];const dataList = awaitfetchGitHubData(config.endpoint);const displayItems = dataList.slice(0BASE_CONFIG.maxDisplayItems);const itemsText = displayItems.length > 0        ? displayItems.map(config.itemFormatter).join('\n')        : '暂无相关数据';return`${config.titlePrefix}${repo}${action === 'issues' ? 'Issues' : 'Pull Requests'}${itemsText}      `.trim();    } catch (error) {console.error(`GitHub API 调用失败 [action: ${action}, repo: ${repo}]:`, error.message);thrownewError(`获取 ${action} 失败:${error.message}`);    }  }};

🔔 Webhook

接收 GitHub Webhook

module.exports = {name'github-webhook',asyncinit() {try {awaitregisterWebhook('/webhook/github'async (request) => {const valid = awaitverifySignature(          request.headers['x-hub-signature-256'],          request.body,          process.env.GITHUB_WEBHOOK_SECRET        );if (!valid) {return { status401body'Invalid signature' };        }const event = request.headers['x-github-event'];const payload = request.body;if (event === 'push') {awaithandlePush(payload);        }if (event === 'pull_request') {awaithandlePullRequest(payload);        }return { status200body'OK' };      });return'✅ GitHub Webhook 已注册';    } catch (error) {console.error('注册 Webhook 失败:', error);throw error;    }  }};

🔄 数据同步

定时同步

module.exports = {name'data-sync',asyncinit() {try {// 每小时同步一次awaitcreateCronJob({cron'0 * * * *',taskasync () => {console.log('开始数据同步...');// 同步 CRM 客户数据const customers = awaitsyncCRM();// 同步 ERP 订单数据const orders = awaitsyncERP();// 生成同步报告const report = `📊 **数据同步报告**✅ CRM 客户:${customers.count} 条✅ ERP 订单:${orders.count} 条同步时间:${newDate().toLocaleString()}          `.trim();awaitsendToFeishu({chatIdgetDataChannelId(),content: report          });        }      });return'✅ 数据同步已启用,每小时执行一次';    } catch (error) {console.error('数据同步初始化失败:', error);throw error;    }  }};

🔐 认证管理

API Key 管理

classSecretManager {constructor() {this.storage = process.env.SECRET_STORAGE || 'env';  }asyncget(secretName) {if (this.storage === 'env') {return process.env[secretName];    }if (this.storage === 'aws-secrets') {returnawaitthis.getFromAWSSecrets(secretName);    }if (this.storage === 'vault') {returnawaitthis.getFromVault(secretName);    }thrownewError(`未知的密钥存储方式:${this.storage}`);  }}// 使用示例const secrets = newSecretManager();const apiKey = await secrets.get('OPENAI_API_KEY');

自动刷新 Token

module.exports = {name'token-refresh',asyncinit() {try {// 每天检查 Token 是否过期awaitcreateCronJob({cron'0 0 * * *',taskasync () => {const tokens = awaitlistTokens();for (const token of tokens) {if (isExpiringSoon(token)) {const newToken = awaitrefreshToken(token);awaitupdateToken(token.service, newToken);console.log(`已刷新 ${token.service} Token`);            }          }        }      });return'✅ Token 自动刷新已启用';    } catch (error) {console.error('Token 刷新初始化失败:', error);throw error;    }  }};

💡 实用场景

场景 1:跨平台消息同步

module.exports = {name'message-bridge',asyncinit() {try {// 飞书 → 钉钉awaitsubscribeEvent('feishu.message'async (event) => {const message = event.message;awaitsendToDingtalk({webhook: process.env.DINGTALK_WEBHOOK,content`📢 飞书消息\n\n${message.content.text}`        });      });// 钉钉 → 飞书awaitsubscribeEvent('dingtalk.message'async (event) => {const message = event.message;awaitsendToFeishu({chatId: process.env.FEISHU_CHAT_ID,content`📢 钉钉消息\n\n${message.text}`        });      });return'✅ 消息桥接已启用';    } catch (error) {console.error('消息桥接初始化失败:', error);throw error;    }  }};

场景 2:CI/CD 通知

module.exports = {name'cicd-notify',asyncinit() {try {awaitregisterWebhook('/webhook/cicd'async (request) => {const { pipeline, status, commit } = request.body;let emoji, color;if (status === 'success') {          emoji = '✅';          color = 'green';        } elseif (status === 'failed') {          emoji = '❌';          color = 'red';        } else {          emoji = '⏳';          color = 'yellow';        }awaitsendToFeishu({chatIdgetDevChatId(),content`${emoji} **CI/CD 通知**流水线:${pipeline}状态:${status}提交:${commit.message}分支:${commit.branch}          `.trim()        });return { status200 };      });return'✅ CI/CD 通知已启用';    } catch (error) {console.error('CI/CD 通知初始化失败:', error);throw error;    }  }};

✅ 学完这篇你能做什么

学完 Day 20,你将能够:

  • ✅ 调用外部 API(天气、GitHub、钉钉、企业微信)
  • ✅ 配置 Webhook(GitHub、支付通知)
  • ✅ 实现数据同步(定时同步、双向同步)
  • ✅ 管理 API 密钥(SecretManager、自动刷新 Token)
  • ✅ 处理 API 相关错误

🔜 下篇预告

Day 21:第三周复盘:企业级应用总结

  • 📚 第三周内容回顾
  • ❓ 常见问题 Q&A
  • 📊 学习成果自测

💬 互动环节

你想集成什么外部系统?留言分享!


公众号:OpenClaw 研习社系列:OpenClaw 30 天入门到精通作者:OpenClaw 研习社