# 成语词典:从搜索到释义的两步流,搭建查词功能
> 接口:成语词典(apiCode=2964) · 接入点:搜索成语(2964-1) + 成语详情(2964-2) · 是否免费:是 · 请求方式:POST/GET · 返回格式:JSON · 适用人群:全栈工程师、产品经理 · 阅读时间:约 7 分钟
## 核心要点
- 搜索(2964-1)只返回 `id`+`word`,**不含释义**;释义在详情(2964-2)。
- 标准链路:搜索拿 `id` → 用 `id` 调详情拿拼音/解释/出处/示例。
- 下游查详情**优先用 `id`**,避免同名成语歧义。
## Why:为什么是「两步」而不是「一步」
你做一个查词功能,用户搜「画」,想看到「画蛇添足」并点开看解释。但搜索接口只给你成语名和 id,点开看解释必须再调一次详情。不理解这个两步流,就会在产品里卡在「只有名字没有解释」。本文把这条主链路讲透,并给出可直接套的代码。
## What:两步流接口速览
| 步骤 | 接入点 | 入参 | 出参 |
|------|--------|------|------|
| 1. 搜索 | 2964-1 | `keyword`(必填)、`page` | `list[]`(id, word) + 分页 |
| 2. 详情 | 2964-2 | `id` 或 `word` | word/pinyin/explain/derivation/sample |
## How:完整可运行实现
### 步骤 1:搜索拿 id 列表
```python
import requests
APPKEY = "YOUR_APPKEY"
def search(keyword, page=1):
r = requests.get("https://route.showapi.com/2964-1",
params={"appKey": APPKEY, "keyword": keyword, "page": str(page)},
timeout=10)
body = r.json()["showapi_res_body"]
if body.get("ret_code") != 0:
raise RuntimeError(body.get("remark"))
return body["list"], body["allPages"]
items, pages = search("画")
print(items) # [{'word':'画蛇添足','id':'...'}, ...]
```
### 步骤 2:用 id 查详情
```python
def detail_by_id(id_):
r = requests.post("https://route.showapi.com/2964-2",
data={"appKey": APPKEY, "id": id_}, timeout=10)
body = r.json()["showapi_res_body"]
if body.get("ret_code") != 0:
raise RuntimeError(body.get("remark"))
return {k: body.get(k) for k in ("word", "pinyin", "explain", "derivation", "sample")}
print(detail_by_id(items[0]["id"]))
```
### 步骤 3:前端交互时序
```
用户输入 keyword
→ 前端调 2964-1 拿 list
→ 列表展示 word
→ 用户点某条 → 前端拿该条 id 调 2964-2
→ 详情页展示 pinyin/explain/derivation/sample
```
Node.js 串联示例:
```javascript
const APPKEY = "YOUR_APPKEY";
async function lookup(keyword) {
const s = await fetch(`https://route.showapi.com/2964-1?${new URLSearchParams({appKey:APPKEY,keyword,page:"1"})}`, {method:"POST"}).then(r=>r.json());
const list = s.showapi_res_body.list;
const first = list[0];
const d = await fetch("https://route.showapi.com/2964-2", {
method:"POST",
headers:{"content-type":"application/x-www-form-urlencoded"},
body:new URLSearchParams({appKey:APPKEY, id:first.id})
}).then(r=>r.json());
return d.showapi_res_body;
}
lookup("画").then(console.log);
```
## 返回示例与解析
搜索:`list` 每项 `{word, id}`。详情:`{word, pinyin, explain, derivation, sample}`。两步拼起来即「搜索候选 → 点开看释义」。
## 进阶 / 边界
- **用 id 而非 word 查详情**:搜索结果已带 id,id 唯一,能避开「同名成语返回错条」的歧义。详见[详情参数篇](https://www.showapi.com/guides/idiom-detail-id-or-word-2964)。
- **缓存**:搜索结果和详情都可按 `keyword`/`id` 本地缓存([缓存策略](https://www.showapi.com/guides/idiom-pagination-cache-2964)),免费接口也建议做,降延迟防限流。
- **分页**:搜索多页时先取 `allPages`,逐页拉取,直到 `currentPage == allPages`。
## FAQ
**Q:能不能搜索时顺便返回解释?**
不能,接口设计如此。必须两步:搜索拿 id,详情拿释义。
**Q:用 word 查详情会有问题吗?**
当存在同名成语时可能命中非预期条;用搜索返回的 `id` 最稳。
**Q:两步会增加延迟吗?**
会多一次请求,但都很快;用缓存可基本消除(热门词/常用 id 命中本地)。
**Q:移动端点开详情卡顿怎么优化?**
详情接口可预取:列表渲染时并行用 id 预拉前几条详情并缓存,点开即显。
## 相关能力 / 下一步阅读
- [成语详情:用 id 还是 word 查询?参数用法与避坑](https://www.showapi.com/guides/idiom-detail-id-or-word-2964)
- [免费接口下如何设计分页缓存,减少重复调用?](https://www.showapi.com/guides/idiom-pagination-cache-2964)
- [成语搜索关键词怎么写才准?部分匹配 / 分页技巧](https://www.showapi.com/guides/idiom-search-keyword-tips-2964)
- **本系列共 15 篇**:查看[成语词典(apiCode=2964)官方指南总目录](https://www.showapi.com/guides/idiom-dictionary-guides-2964)