
Alapi
- 4 installs
- 8 repo stars
- Updated August 4, 2026
- wangyendt/wayne-skills
Helps with backend & apis tasks.
About
alapi is a Claude Code skill for backend & apis. It helps solo builders move faster with AI-assisted development.
- alapi
- Backend & APIs
- AI-coding skill
Alapi by the numbers
- 4 all-time installs (skills.sh)
- Ranked #3,710 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/wangyendt/wayne-skills --skill alapiAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 4 |
|---|---|
| repo stars | ★ 8 |
| Last updated | August 4, 2026 |
| Repository | wangyendt/wayne-skills ↗ |
What it does
Helps with backend & apis tasks.
Files
ALAPI
Overview
Use this skill to work against the full ALAPI OpenAPI catalog without hand-parsing the schema each time. The skill bundles the raw OpenAPI source, a generated endpoint catalog, an auth guide, and a reusable request script.
Workflow
1. Confirm whether ALAPI_TOKEN is available. 2. If the token is missing, tell the user to request one from https://apifox.com/apihub/, then ask them to send it back. 3. After the user sends the token, persist it to the active shell profile, export it in the current session, and avoid echoing it back in logs. 4. Use references/intent-router.md first to map a user request to the most likely endpoint with minimal context cost. 5. Open references/api-catalog.md only for the exact endpoint you selected. 6. Use scripts/alapi_request.py for real calls instead of rewriting HTTP boilerplate. 7. If the OpenAPI source changes, replace references/openapi-source.json and rerun scripts/generate_references.py.
Authentication
- ALAPI uses header auth:
token: $ALAPI_TOKEN - All endpoints in the bundled OpenAPI spec use
POST - All endpoints use
application/jsonrequest bodies - Base URL:
https://v3.alapi.cn
Token Handling
Run printenv ALAPI_TOKEN first.
If the token is missing:
- Tell the user to申请或管理 ALAPI token at
https://apifox.com/apihub/ - Ask the user to send the token
- After receiving it, persist it based on the active shell:
zsh: appendexport ALAPI_TOKEN='...'to~/.zshrcbash: appendexport ALAPI_TOKEN='...'to~/.bashrc- Also export it in the current shell before making API calls
Do not invent or reuse placeholder tokens for real requests.
References
references/auth-and-usage.md: auth model, calling conventions, error-handling checklistreferences/intent-router.md: lowest-cost full routing table from common intent to endpointreferences/api-catalog.md: endpoint-by-endpoint reference including purpose and request schemareferences/openapi-source.json: bundled ALAPI OpenAPI source of truth
Use rg '^### /api/' references/api-catalog.md to jump to a path quickly.
Scripts
scripts/alapi_request.py: send authenticated ALAPI requests with JSON bodiesscripts/generate_references.py: regenerate the reference markdown files fromreferences/openapi-source.json
Response Discipline
When answering a user with this skill:
- State the selected endpoint path explicitly
- Explain why that endpoint matches the request
- Show the required JSON body fields
- Mention that auth is via
ALAPI_TOKEN - Summarize the API response instead of dumping raw JSON unless the user asks for the full payload
interface:
display_name: "ALAPI Full API"
short_description: "ALAPI 全量 OpenAPI 接口文档与调用器"
default_prompt: "Use $alapi to find the correct ALAPI endpoint, explain its request body, and prepare or execute the API call."
Authentication And Usage
Authentication
- Header name:
token - Header location:
header - Environment variable:
ALAPI_TOKEN - Base URL:
https://v3.alapi.cn
Common Request Pattern
- Method:
POST - Content-Type:
application/json - Auth header:
token: $ALAPI_TOKEN - Success shape: ALAPI generally returns JSON containing fields such as
code,message,success,data,request_id,time, andusage
Missing Token
If ALAPI_TOKEN is missing:
1. Tell the user to request or manage a token at https://apifox.com/apihub/ 2. Ask the user to send the token back 3. Persist it to the active shell profile and export it in the current shell before calling the API
Reusable Caller
Use scripts/alapi_request.py:
python3 scripts/alapi_request.py /api/ip --body '{"ip":"8.8.8.8"}'Or load the request body from a file:
python3 scripts/alapi_request.py /api/ai/translate --body-file /tmp/body.jsonReference Navigation
references/api-index.md: category indexreferences/api-catalog.md: endpoint-by-endpoint catalogreferences/openapi-source.json: raw source of truth
Intent Router
Read this file first when you need to map a user goal to one ALAPI endpoint with minimal token usage.
- Total endpoints:
139 - Rule: find the closest business intent here first, then open
api-catalog.mdonly for the selected endpoint.
| Endpoint | Summary | Typical intent / when to use |
|---|---|---|
/api/abbr | 能不能好好说话 | 能不能好好说话,缩写查询, 查询网络热梗词,查询表达的意思, 如 yyds |
/api/acg | ACG动漫图片 | 随机返回一个ACG动漫图片壁纸 |
/api/ai/couplet | 智能对联生成 | 智能对联生成,输入关键字生成押韵对联 |
/api/ai/poem | 藏头诗生成 | 输入关键字,生成藏头、藏尾、藏中等诗词,支持押韵生成 |
/api/ai/quick_asr | 短语音识别 | 将60秒以内的语音精准识别为文字,可适用于手机语音输入、AI对话、语音指令等短语音交互场景,支持所有音频格式 |
/api/ai/translate | AI大模型文本翻译 | 基于业界领先的AI大模型技术,提供近乎母语水平的专业、精准、流畅的文本翻译服务 |
/api/avatar | 获取头像 | 获取头像CDN,支持QQ头像,Gravatar 头像,用于加速头像访问 |
/api/bilibili/cover | 哔哩哔哩封面获取 | 获取哔哩哔哩封面,支持:视频、直播、番剧等 |
/api/bing | 必应美图 | 获取每日必应的壁纸美图 |
/api/censor/text | 文本审核 | 检测是否包含违规文本信息。检测是否包含:色情文字, 广告文字,敏感文字,涉政文字, 灌水文字 低俗辱骂 |
/api/chat/completions | Chat对话模型 | AI大模型接口,大模型对话接口,支持OPENAI,文心一言... |
/api/china_exchange | 汇率转换 | 基于中国外汇管理局官方数据,提供人民币中间价汇率查询、实时币种转换、历史汇率及趋势分析服务,覆盖 25 种主流货币。 |
/api/china_exchange/code | 币种列表 | 基于中国外汇管理局官方数据,提供人民币中间价汇率查询、实时币种转换、历史汇率及趋势分析服务,覆盖 25 种主流货币。 |
/api/ciword | 词语字典 | 查询词语字典,查询各种词语的意思 |
/api/comment | 网易云乐评 | 网易云乐评,来自网易云歌曲高赞评论 |
/api/crypto_currency | 加密货币行情价格 | 加密货币实时价格,查询BTC,ETH,USDT等加密货币实时行情价格,秒级更新 |
/api/crypto_currency/type | 货币代码列表 | 加密货币实时价格,查询BTC,ETH,USDT等加密货币实时行情价格,秒级更新 |
/api/dog | 舔狗日记 | 卑微的爱情舔狗 |
/api/domain/checkssl | SSL证书检测 | 检查域名的证书是否部署、是否过期、证书详细信息等 |
/api/domain/dns | 域名DNS解析查询 | 查询域名DNS解析记录 |
/api/doutu | 表情包搜索 | 斗图表情包,搞笑表情包搜索 |
/api/encrypt | 内容加解密 | 内容加密接口,支持 md5 sha1 sha256 sha512 urlencode urldecode base64_encode,base64_decode |
/api/ent/check_four_name | 企业四要素验证 | 企业名,统一社会信用代码,法定代表人姓名,营业期限一致性验证 |
/api/ent/check_three_name | 企业三要素验证 | 通过输入公司编号(统一社会信用代码\注册号)、企业名称、法定代表人名称,验证三者是否匹配一致。 |
/api/ent/contact_info | 企业联系方式 | 工商公示企业联系方式,包括地址、电话、邮件 |
/api/ent/domains | 企业域名信息 | 查询企业备案域名信息,有网站名称、域名等 |
/api/ent/trademark | 商标搜索 | 根据商标名称/注册号/申请人搜索商标信息,包括注册号、国际分类号、专用权期限等。 |
/api/enterprise/simple_search | 企业工商信息搜索 | 根据企业名称或统一社会信用代码查询企业基本工商信息,支持模糊查询。 |
/api/eventHistory | 历史上的今天 | 查历史上的指定日期发生的大事 |
/api/eventHistory/get | 历史上的今天详情 | 查历史上的指定日期发生的大事 |
/api/eventHistory/search | 历史上的今天搜索 | 查历史上的指定日期发生的大事 |
/api/exchange | 汇率实时转换查询 | 根据货币代码查询货币汇率和换算,支持全球170+个国家和地区货币查询。数据来源于网络,仅供参考。 |
/api/exchange/type | 支持的货币代码列表 | 根据货币代码查询货币汇率和换算,支持全球170+个国家和地区货币查询。数据来源于网络,仅供参考。 |
/api/fanyi | 文本翻译 | 文本翻译,通过机器翻译将文本翻译为对应的语言 |
/api/garbage | 垃圾分类 | 通过关键字搜索物品是否属于哪种垃圾 |
/api/gold | 黄金实时价格 | 黄金实时价格,查询当前黄金的实时价格,最高价,最低价,品牌黄金的价格 |
/api/gold/brand | 品牌黄金价格 | 黄金实时价格,查询当前黄金的实时价格,最高价,最低价,品牌黄金的价格 |
/api/hitokoto | Hitokoto一言 | 动漫也好、小说也好、网络也好,不论在哪里,我们总会看到有那么一两个句子能穿透你的心。我们把这些句子汇聚起来,形成一言网络,以传递更多的感动。 |
/api/holiday | 节假日查询 | 查询指定年份的节假日信息,数据来源国家发布 |
/api/holiday/workday | 工作日查询 | 工作日查询,查询指定日期的工作日,节假日,周末,补班信息 |
/api/icp | ICP域名备案实时查询 | 根据域名实时返回查询域名的备案信息(与官网一致),适用于对备案信息变化及时性 要求高的用户,如备案监控,备案域名接入系统等 |
/api/icp/app | APP备案信息实时查询 | APP在中国境内提供互联网信息服务,需要对APP进行备案。通过APP备案查询接口可以实时获取例如,新闻、社交、电商、游戏、教育、医疗等行业的app是否进行了备案,是当前企业必备的查询接口。 |
/api/icp/mini | 小程序备案信息实时查询 | 小程序在中国境内提供互联网信息服务,需要对小程序进行备案。通过小程序备案查询接口可以实时获取例如,新闻、社交、电商、游戏、教育、医疗等行业的小程序是否进行了备案,是当前企业必备的查询接口。 |
/api/icp/quick | 快应用备案信息实时查询 | 快应用备案信息实时查询 |
/api/icp/unit | 企业备案实时查询 | 根据主办单位实时返回查询所有备案信息 |
/api/idcard | 身份证信息查询 | 可查询中国大陆居民身份证,港澳台居民身份证信息。可查询身份证的 出生年月,居住地 ,生日信息 星座 , 生肖 年龄 等信息,支持 15 位和 18 位身份证 |
/api/idcard/upgrade | 身份证升级 | 可查询中国大陆居民身份证,港澳台居民身份证信息。可查询身份证的 出生年月,居住地 ,生日信息 星座 , 生肖 年龄 等信息,支持 15 位和 18 位身份证 |
/api/idiom | 成语词典 | 成语词典查询,解释各种成语意思,可用于成语接龙 |
/api/ip | IP地址查询 | 高精度IP归属地查询,支持IPV4和IPV6,数据每月更新 |
/api/joke | 笑话列表 | 精选各种文字类笑话 |
/api/joke/random | 随机笑话 | 精选各种文字类笑话 |
/api/kd | 快递查询 | 快递物流轨迹查询,免费查询快递物流轨迹,支持中通、申通、顺丰、极兔、百世、圆通 |
/api/kd/com | 快递公司列表 | 快递物流轨迹查询,免费查询快递物流轨迹,支持中通、申通、顺丰、极兔、百世、圆通 |
/api/lanzou | 蓝奏云直连解析 | 蓝奏云直链解析,支持单个文件,文件夹,以及密码文件 |
/api/lunar | 农历查询 | 指定日期查询当日的星期、星座、农历、生肖、天干地支、岁次、黄历相关的福神、喜神、宜忌、节日等信息,可以进行阴阳历转换。 |
/api/mingyan | 名人名言 | 随机返回一条古今中外名人名言 |
/api/mingyan/type | 名人名言类型 | 随机返回一条古今中外名人名言 |
/api/models | 可用模型 | AI大模型接口,大模型对话接口,支持OPENAI,文心一言... |
/api/mryw | 每日一文 | 每日一文接口,随机美文 |
/api/mryw/list | 美文列表 | 每日一文接口,随机美文 |
/api/mryw/random | 随机美文 | 每日一文接口,随机美文 |
/api/music/comment/hot | 获取歌曲热评 | 网易云音乐搜索、解析、获取歌曲评论等 |
/api/music/detail | 歌曲详情 | 网易云音乐搜索、解析、获取歌曲评论等 |
/api/music/lyric | 歌词获取 | 网易云音乐搜索、解析、获取歌曲评论等 |
/api/music/playlist | 获取歌单列表 | 网易云音乐搜索、解析、获取歌曲评论等 |
/api/music/search | 歌曲搜索 | 网易云音乐搜索、解析、获取歌曲评论等 |
/api/music/url | 网易云歌曲直链 | 网易云音乐搜索、解析、获取歌曲评论等 |
/api/new/hanfu | 汉服新闻 | 汉服新闻,获取汉服相关的新闻信息 |
/api/new/toutiao | 新闻头条 | 网易新闻头条,每天更新 |
/api/new/toutiao/type | 头条类型 | 网易新闻头条,每天更新 |
/api/new/wbtop | 微博热搜榜 | 微博热搜榜单,实时获取微博搜索榜单 |
/api/nlp/keyword | 关键词提取 | 在海量文本中提取出能够反映主题或者主要内容的词或短语,可用于社交媒体、博客系统的自动打标签功能。 |
/api/nlp/phrase | 短语提取 | 通过对文本内容进行深度分析,提取出文本内容中的关键短语,为用户实现诸如新闻内容关键词自动提取、评论关键词提取等提供服务。 |
/api/nlp/summary | 自动摘要 | 自动摘要是指给出一段文本并从中提取出要点,然后再形成一个短的概括性的文本。 |
/api/nlp/word | 智能分词 | NLP智能分词,快速把一段文本切分为一个个词组,并标注了词性。 |
/api/ocr/bank-card | 银行卡识别 | 银行卡OCR识别提供银行卡照片上的信息识别 |
/api/ocr/business-license | 营业执照识别 | 支持结构化识别各类版式的营业执照,返回证件编号、社会信用代码、单位名称、地址、法人、类型、成立日期、有效日期、经营范围等关键字段信息 |
/api/ocr/cn-passport | 中国护照识别 | 结构化识别中国护照,返回护照号码、中英文姓名、出生日期、有效期至、签发地点等关键字段 |
/api/ocr/driving-license | 驾驶证识别 | 支持结构化识别驾驶证,返回证号、姓名、性别、国籍、住址、出生日期、准驾车型、有效期、发证机关、相片位置等关键字段信息 |
/api/ocr/food-business-license | 食品经营许可证识别 | 结构化识别食品经营许可证,返回许可证编号、经营者名称、法定代表人、经营场所、主体业态、经营项目、有效期等关键字段 |
/api/ocr/food-production-license | 食品生产许可证识别 | 结构化识别食品生产许可证,返回许可证编号、生产者名称、法定代表人、生产地址、食品类别、有效期等关键字段 |
/api/ocr/health-cert | 健康证识别 | 结构化识别健康证,返回姓名、发证机关、体检日期、有效日期等关键字段 |
/api/ocr/hkmo-permit | 港澳居民来往内地通行证识别 | 支持结构化识别港澳居民来往内地通行证(回乡证),返回中文姓名、英文姓名、出生日期、证件号码、有效期等关键字段信息 |
/api/ocr/id_card | 身份证识别 | 身份证识别, 提取身份证照片的信息,支持正反面识别,支持JPG/JPEG/PNG格式文件 |
/api/ocr/taxi-invoice | 出租车发票识别 | 支持结构化识别全国出租车机打发票,返回车号、上下车时间、里程、金额、发票代码、发票号码、单价、附加费、印章信息等关键字段 |
/api/ocr/text | OCR文本识别 | 可识别图片中的文字,支持中/英/数字/符号等 |
/api/ocr/train-ticket | 火车票识别 | 支持结构化识别国内全类型火车票,返回出发站、到达站、车次、姓名、座位号、票价、出发时间、身份证号、售卖站等关键字段信息 |
/api/ocr/tw-permit | 台湾居民来往大陆通行证识别 | 支持结构化识别台湾居民来往大陆通行证(台胞证),返回中文姓名、英文姓名、出生日期、证件号码、有效期等关键字段信息 |
/api/ocr/vat-invoice | 增值税发票识别 | 支持结构化识别增值税专用发票和普通发票,返回发票代码、发票号码、开票日期、金额、税额、购买方信息、销售方信息、明细项等关键字段信息 |
/api/ocr/vehicle-invoice | 机动车发票识别 | 结构化识别机动车销售发票,,包括发票代码、号码、开票日期、机器编号、购买方信息、车辆信息、销货单位信息、价税合计、价税合计小写、税率、税额、不含税价格等 |
/api/ocr/vehicle-license | 行驶证识别 | 支持结构化识别行驶证,返回号牌号码、车辆类型、所有人、品牌型号、发动机号、注册日期、总质量、核定载质量、外廓尺寸、检验记录等关键字段信息 |
/api/oil | 油价查询 | 查询全国各省份油价信息 |
/api/one | ONE · 一个 文章 | 分享ONE一个每日的最新文章、问答、摄影 |
/api/one/photo | ONE · 一个 摄影 | 分享ONE一个每日的最新文章、问答、摄影 |
/api/one/question | ONE · 一个 问答 | 分享ONE一个每日的最新文章、问答、摄影 |
/api/phone | 手机号归属地查询 | 手机号归属地查询,查询手机号码所属地区 |
/api/phonecheck | 空号检测 | 通过手机号码查询其在网活跃度,返回包括空号、实号、停机、库无、沉默号、风险号等状态 |
/api/pinyin | 中文转拼音 | 将中文转换为拼音格式 |
/api/qinghua | 土味情话 | 土味情话,快来叫教你怎么说情话 |
/api/qr | 二维码生成 | 二维码生成,输入文本或者网址生成对应的二维码 |
/api/qr/decode | 二维码识别 | 二维码识别接口,支持一图多码,支持数十二维码,条形码的识别 |
/api/riddle | 谜语大全列表 | 谜语大全,中国谜语大全宝典 |
/api/riddle/random | 随机谜语 | 谜语大全,中国谜语大全宝典 |
/api/riddle/type | 谜语类型 | 谜语大全,中国谜语大全宝典 |
/api/shici | 随机诗词 | 随机诗词服务,随机返回一篇古代诗词 |
/api/solarTerm | 24节气查询(年份) | 中国24节气信息查询,节气具体信息查询,查询指定年份的节气信息 |
/api/solarTerm/search | 二十四节气(日期) | 中国24节气信息查询,节气具体信息查询,查询指定年份的节气信息 |
/api/soul | 心灵毒鸡汤 | 生活已经够苦,需要一点“毒”味来提神 |
/api/star | 星座运势 | 提供星座运势查询服务,支持查询十二星座今日或明日、本周、本月、本年的运势。 |
/api/tianqi | 实况天气查询 | 支持全国的天气查询,包含3400+个城市实况数据,支持查询当天实况天气,7天天气,40天天气,天气预警、天气指数,AQI数据等 |
/api/tianqi/forty | 40天天气查询 | 支持全国的天气查询,包含3400+个城市实况数据,支持查询当天实况天气,7天天气,40天天气,天气预警、天气指数,AQI数据等 |
/api/tianqi/index | 天气指数 | 支持全国的天气查询,包含3400+个城市实况数据,支持查询当天实况天气,7天天气,40天天气,天气预警、天气指数,AQI数据等 |
/api/tianqi/seven | 7天天气查询 | 支持全国的天气查询,包含3400+个城市实况数据,支持查询当天实况天气,7天天气,40天天气,天气预警、天气指数,AQI数据等 |
/api/tophub | 今日热榜 | 今日热榜,聚合各大网站热点资讯,如:抖音、微博、腾讯,微信、今日头条、知乎等数百个热门站点热榜数据 |
/api/tophub/site | 今日热榜站点列表 | 今日热榜,聚合各大网站热点资讯,如:抖音、微博、腾讯,微信、今日头条、知乎等数百个热门站点热榜数据 |
/api/tracking | 快递查询 | 快递查询V2计次版,支持全球2000多家快递公司查询 |
/api/tts/free | 语音合成 | 短语音合成接口,将文字转换为音频 |
/api/tts/pro | 语音合成 | 语音合成[高级版],支持更多的文字,支持更多的语音音色 |
/api/tts/voice_type | 音色列表 | 语音合成[高级版],支持更多的文字,支持更多的语音音色 |
/api/url | 短网址生成 | 快速将长网址缩短为短网址 |
/api/url/batchQuery | 批量短网址还原 | 将短网址还原为长网址 |
/api/url/query | 短网址还原 | 将短网址还原为长网址 |
/api/url/type | 短网址类型 | 快速将长网址缩短为短网址 |
/api/urlcheck/qq | QQ网址拦截查询 | 查询域名或者网址在QQ里面是否被拦截,结果仅供参考 |
/api/urlcheck/wx | 微信链接拦截查询 | 查询对应的网址或者域名在微信里面是否拦截,结果仅供参考 |
/api/verfiy/idcard | 实名认证查询 | 身份证二要素实名认证,检测 姓名+身份证号 是否一致 |
/api/verify/telecom2 | 手机姓名二要素实名认证 | 手机二要素实名认证,通过手机号+姓名检查是否一致 |
/api/verify/telecom3 | 手机三要素实名认证 | 手机三要素实名认证, 通过 手机号+姓名+身份证检测是否一致 |
/api/video/url | 短视频解析 | 短视频聚合解析接口,用于快速下载短视频,支持热门短视频平台,抖音、快手、小红书等 |
/api/whois | 域名Whois查询 | 域名Whois查询,查询域名注册信息 |
/api/word | 新华字典 | 新华字典查询,查询制定字的意思等 |
/api/xhy | 歇后语搜索 | 歇后语大全 |
/api/xhy/random | 随机歇后语 | 歇后语大全 |
/api/zaobao | 每日早报 | 每日早报,每天60秒读懂世界接口,返回15条全球新闻速报,每日微语数据 |
/api/zhihu | 知乎日报 | 知乎日报,每天3次,每次7分钟 |
/api/zhihu/get | 指定日期日报 | 知乎日报,每天3次,每次7分钟 |
/api/zhihu/long_comments | 获取日报长评论列表 | 知乎日报,每天3次,每次7分钟 |
/api/zhihu/news | 获取日报详情 | 知乎日报,每天3次,每次7分钟 |
/api/zhihu/short_comments | 获取日报短评论列表 | 知乎日报,每天3次,每次7分钟 |
#!/usr/bin/env python3
"""Call an ALAPI endpoint with token auth and a JSON body."""
from __future__ import annotations
import argparse
import json
import os
import sys
import urllib.error
import urllib.request
from pathlib import Path
DEFAULT_BASE_URL = "https://v3.alapi.cn"
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Send a POST request to an ALAPI endpoint using ALAPI_TOKEN."
)
parser.add_argument("endpoint", help="Endpoint path such as /api/ip or /api/ai/translate")
parser.add_argument(
"--body",
default="{}",
help="Inline JSON body string. Ignored when --body-file is provided.",
)
parser.add_argument(
"--body-file",
type=Path,
help="Path to a JSON file containing the request body.",
)
parser.add_argument(
"--token",
help="Override ALAPI_TOKEN for this call. Prefer the environment variable.",
)
parser.add_argument("--base-url", default=DEFAULT_BASE_URL, help="ALAPI base URL.")
parser.add_argument("--timeout", type=float, default=30.0, help="Request timeout in seconds.")
parser.add_argument(
"--raw",
action="store_true",
help="Print the raw response body instead of pretty JSON.",
)
return parser.parse_args()
def load_body(args: argparse.Namespace) -> dict | list:
if args.body_file:
return json.loads(args.body_file.read_text())
return json.loads(args.body)
def normalize_endpoint(endpoint: str) -> str:
endpoint = endpoint.strip()
if not endpoint.startswith("/"):
endpoint = f"/{endpoint}"
return endpoint
def main() -> int:
args = parse_args()
endpoint = normalize_endpoint(args.endpoint)
token = args.token or os.environ.get("ALAPI_TOKEN")
if not token:
print(
"ALAPI_TOKEN is not set. Apply for one at https://apifox.com/apihub/ and export it first.",
file=sys.stderr,
)
return 2
try:
body = load_body(args)
except Exception as exc:
print(f"Invalid JSON body: {exc}", file=sys.stderr)
return 2
url = f"{args.base_url.rstrip('/')}{endpoint}"
payload = json.dumps(body, ensure_ascii=False).encode("utf-8")
request = urllib.request.Request(
url,
data=payload,
method="POST",
headers={
"Content-Type": "application/json",
"Accept": "application/json",
"token": token,
},
)
try:
with urllib.request.urlopen(request, timeout=args.timeout) as response:
response_body = response.read().decode("utf-8")
except urllib.error.HTTPError as exc:
body_text = exc.read().decode("utf-8", errors="replace")
print(f"HTTP {exc.code}: {body_text}", file=sys.stderr)
return 1
except urllib.error.URLError as exc:
print(f"Network error: {exc}", file=sys.stderr)
return 1
if args.raw:
print(response_body)
return 0
try:
parsed = json.loads(response_body)
except json.JSONDecodeError:
print(response_body)
return 0
print(json.dumps(parsed, ensure_ascii=False, indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())
#!/usr/bin/env python3
"""Generate ALAPI markdown references from the bundled OpenAPI source."""
from __future__ import annotations
import json
from collections import defaultdict
from copy import deepcopy
from pathlib import Path
BASE_URL = "https://v3.alapi.cn"
def pointer_get(root: dict, pointer: str):
if not pointer.startswith("#/"):
raise ValueError(f"Unsupported ref: {pointer}")
current = root
for part in pointer[2:].split("/"):
current = current[part]
return current
def merge_all_of(parts: list[dict]) -> dict:
merged: dict = {"type": "object", "properties": {}, "required": []}
for part in parts:
for key, value in part.items():
if key == "properties":
merged.setdefault("properties", {}).update(value)
elif key == "required":
merged.setdefault("required", [])
for item in value:
if item not in merged["required"]:
merged["required"].append(item)
elif key not in {"allOf"}:
merged[key] = value
return merged
def resolve_schema(schema: dict | None, root: dict) -> dict:
if not schema:
return {}
if "$ref" in schema:
target = deepcopy(pointer_get(root, schema["$ref"]))
other = {k: deepcopy(v) for k, v in schema.items() if k != "$ref"}
resolved = resolve_schema(target, root)
resolved.update(other)
return resolved
if "allOf" in schema:
resolved_parts = [resolve_schema(part, root) for part in schema["allOf"]]
merged = merge_all_of(resolved_parts)
for key, value in schema.items():
if key != "allOf":
merged[key] = deepcopy(value)
return merged
resolved = deepcopy(schema)
if "properties" in resolved:
resolved["properties"] = {
key: resolve_schema(value, root) for key, value in resolved["properties"].items()
}
if resolved.get("items"):
resolved["items"] = resolve_schema(resolved["items"], root)
return resolved
def schema_type(schema: dict) -> str:
if not schema:
return "object"
if schema.get("enum"):
return "enum[" + ", ".join(map(str, schema["enum"])) + "]"
kind = schema.get("type", "object")
if kind == "array":
return f"array<{schema_type(schema.get('items', {}))}>"
if kind == "object" and schema.get("properties"):
props = ", ".join(f"{name}:{schema_type(value)}" for name, value in schema["properties"].items())
return f"object{{{props}}}"
return str(kind)
def sample_value(name: str, schema: dict):
if "default" in schema:
return schema["default"]
if schema.get("enum"):
return schema["enum"][0]
kind = schema.get("type", "object")
if kind == "string":
lower = name.lower()
if "url" in lower:
return "https://example.com"
if "date" in lower:
return "2024-01-01"
if "time" in lower:
return "12:00:00"
if "mobile" in lower or "phone" in lower:
return "13800138000"
if lower in {"ip", "ipv4"}:
return "8.8.8.8"
if "idcard" in lower or lower == "id":
return "110101199003071234"
if "text" in lower or "content" in lower:
return "示例文本"
if "lang" in lower or lower == "to":
return "en"
if "model" in lower:
return "gpt-4o-mini"
return f"{name}_example"
if kind == "integer":
return 1
if kind == "number":
return 1
if kind == "boolean":
return bool(schema.get("default", False))
if kind == "array":
return [sample_value(f"{name}_item", schema.get("items", {}))]
if kind == "object":
properties = schema.get("properties", {})
required = schema.get("required", list(properties.keys()))
data = {}
for key in required:
if key in properties:
data[key] = sample_value(key, properties[key])
return data
return None
def fields_from_schema(schema: dict) -> list[dict]:
properties = schema.get("properties", {})
required = set(schema.get("required", []))
rows = []
for name, value in properties.items():
rows.append(
{
"name": name,
"type": schema_type(value),
"required": "yes" if name in required else "no",
"default": json.dumps(value.get("default"), ensure_ascii=False) if "default" in value else "",
"description": (value.get("description") or "").replace("\n", " ").strip(),
}
)
return rows
def json_block(value) -> str:
return "```json\n" + json.dumps(value, ensure_ascii=False, indent=2) + "\n```"
def bash_block(url: str, body) -> str:
body_json = json.dumps(body, ensure_ascii=False, indent=2)
return (
"```bash\n"
f"curl -X POST '{url}' \\\n"
" -H 'token: $ALAPI_TOKEN' \\\n"
" -H 'Content-Type: application/json' \\\n"
f" -d '{body_json}'\n"
"```"
)
def response_summary(example) -> str:
if not isinstance(example, dict):
return "返回 `application/json`。具体结构见 `references/openapi-source.json`。"
top_keys = list(example.keys())
detail = f"顶层常见字段: {', '.join(top_keys)}。"
data = example.get("data")
if isinstance(data, dict):
sample_keys = list(data.keys())[:10]
if sample_keys:
detail += f" `data` 常见字段: {', '.join(sample_keys)}。"
return detail
def category_key(path: str) -> str:
return path.removeprefix("/api/").split("/")[0]
def write_text(path: Path, text: str) -> None:
path.write_text(text.rstrip() + "\n")
def build_auth_doc(spec: dict) -> str:
scheme = spec["components"]["securitySchemes"]["apiKey"]
return f"""# Authentication And Usage
## Authentication
- Header name: `{scheme['name']}`
- Header location: `{scheme['in']}`
- Environment variable: `ALAPI_TOKEN`
- Base URL: `{BASE_URL}`
## Common Request Pattern
- Method: `POST`
- Content-Type: `application/json`
- Auth header: `token: $ALAPI_TOKEN`
- Success shape: ALAPI generally returns JSON containing fields such as `code`, `message`, `success`, `data`, `request_id`, `time`, and `usage`
## Missing Token
If `ALAPI_TOKEN` is missing:
1. Tell the user to request or manage a token at `https://apifox.com/apihub/`
2. Ask the user to send the token back
3. Persist it to the active shell profile and export it in the current shell before calling the API
## Reusable Caller
Use `scripts/alapi_request.py`:
```bash
python3 scripts/alapi_request.py /api/ip --body '{{"ip":"8.8.8.8"}}'
```
Or load the request body from a file:
```bash
python3 scripts/alapi_request.py /api/ai/translate --body-file /tmp/body.json
```
## Reference Navigation
- `references/api-index.md`: category index
- `references/api-catalog.md`: endpoint-by-endpoint catalog
- `references/openapi-source.json`: raw source of truth
"""
def build_router(spec: dict) -> str:
lines = [
"# Intent Router",
"",
"Read this file first when you need to map a user goal to one ALAPI endpoint with minimal token usage.",
"",
f"- Total endpoints: `{len(spec['paths'])}`",
"- Rule: find the closest business intent here first, then open `api-catalog.md` only for the selected endpoint.",
"",
"| Endpoint | Summary | Typical intent / when to use |",
"| --- | --- | --- |",
]
for path, methods in sorted(spec["paths"].items()):
op = methods["post"]
summary = (op.get("summary") or "").replace("|", "\\|").replace("\n", " ").strip()
description = (op.get("description") or summary).replace("|", "\\|").replace("\n", " ").strip()
if len(description) > 120:
description = description[:117] + "..."
lines.append(f"| `{path}` | {summary} | {description} |")
return "\n".join(lines)
def build_catalog(spec: dict) -> str:
grouped: dict[str, list[tuple[str, dict]]] = defaultdict(list)
for path, methods in sorted(spec["paths"].items()):
grouped[category_key(path)].append((path, methods["post"]))
lines = [
"# API Catalog",
"",
"This file is generated from `references/openapi-source.json`.",
"",
"## Table Of Contents",
"",
]
for key, items in sorted(grouped.items()):
lines.append(f"- `{key}`: {len(items)} endpoints")
for key, items in sorted(grouped.items()):
lines.extend(["", f"## {key}", ""])
for path, op in items:
summary = op.get("summary", path)
description = (op.get("description") or summary).replace("\n", " ").strip()
schema = resolve_schema(op["requestBody"]["content"]["application/json"]["schema"], spec)
fields = fields_from_schema(schema)
body_example = sample_value("body", schema)
lines.append(f"### {path}")
lines.append("")
lines.append(f"- 功能: {summary}")
lines.append(f"- 用途: {description}")
lines.append("- 调用方法:")
lines.append(f" - Method: `POST`")
lines.append(f" - URL: `{BASE_URL}{path}`")
lines.append(" - Headers: `token: $ALAPI_TOKEN`, `Content-Type: application/json`")
if fields:
lines.append("")
lines.append("| Field | Type | Required | Default | Description |")
lines.append("| --- | --- | --- | --- | --- |")
for field in fields:
default = field["default"].replace("|", "\\|")
description_text = field["description"].replace("|", "\\|")
lines.append(
f"| `{field['name']}` | `{field['type']}` | {field['required']} | {default} | {description_text} |"
)
else:
lines.append("")
lines.append("- Request body: `{}`")
lines.append("")
lines.append("请求示例:")
lines.append("")
lines.append(bash_block(f"{BASE_URL}{path}", body_example))
example = (
op.get("responses", {})
.get("200", {})
.get("content", {})
.get("application/json", {})
.get("example")
)
lines.append("")
lines.append(f"- 成功响应说明: {response_summary(example)}")
if example is not None:
lines.append("")
lines.append("响应示例:")
lines.append("")
lines.append(json_block(example))
lines.append("")
return "\n".join(lines)
def main() -> None:
skill_dir = Path(__file__).resolve().parents[1]
references_dir = skill_dir / "references"
spec = json.loads((references_dir / "openapi-source.json").read_text())
write_text(references_dir / "auth-and-usage.md", build_auth_doc(spec))
write_text(references_dir / "intent-router.md", build_router(spec))
write_text(references_dir / "api-catalog.md", build_catalog(spec))
if __name__ == "__main__":
main()