feat: expose API markdown doc
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,3 +9,4 @@ dist/
|
|||||||
pdf_images/
|
pdf_images/
|
||||||
|
|
||||||
public/api/
|
public/api/
|
||||||
|
public/apidoc
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
| 单绩效域详情 | `/api/performance-domains/{id}.json` |
|
| 单绩效域详情 | `/api/performance-domains/{id}.json` |
|
||||||
| 工件反查使用情况 | `/api/artifacts/{id}/usage.json` |
|
| 工件反查使用情况 | `/api/artifacts/{id}/usage.json` |
|
||||||
| 工具反查使用情况 | `/api/tools/{id}/usage.json` |
|
| 工具反查使用情况 | `/api/tools/{id}/usage.json` |
|
||||||
|
| Markdown 接口文档 | `/apidoc` |
|
||||||
|
|
||||||
## 3. 接口说明
|
## 3. 接口说明
|
||||||
|
|
||||||
@@ -397,6 +398,23 @@
|
|||||||
|---|---|
|
|---|---|
|
||||||
| `usedIn` | 使用该工具与技术的过程数组 |
|
| `usedIn` | 使用该工具与技术的过程数组 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3.13 Markdown 接口文档
|
||||||
|
|
||||||
|
用于让外部系统直接读取本说明文档。
|
||||||
|
|
||||||
|
`GET /apidoc`
|
||||||
|
|
||||||
|
响应体为 Markdown 文本字符串,不作为附件下载。
|
||||||
|
|
||||||
|
示例响应:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# 知识库 API 接口说明
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
## 4. 常用调用示例
|
## 4. 常用调用示例
|
||||||
|
|
||||||
```text
|
```text
|
||||||
@@ -420,4 +438,7 @@
|
|||||||
|
|
||||||
反查专家判断在哪些过程中使用:
|
反查专家判断在哪些过程中使用:
|
||||||
/api/tools/TT001/usage.json
|
/api/tools/TT001/usage.json
|
||||||
|
|
||||||
|
读取接口 Markdown 文档:
|
||||||
|
/apidoc
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -10,6 +10,15 @@ server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Markdown 接口说明,直接返回文本内容
|
||||||
|
location = /apidoc {
|
||||||
|
default_type text/markdown;
|
||||||
|
charset utf-8;
|
||||||
|
try_files /apidoc =404;
|
||||||
|
add_header Cache-Control "no-store";
|
||||||
|
}
|
||||||
|
|
||||||
# 知识库静态 JSON API,接口路径不存在时返回 404,避免被 SPA 回退到 index.html
|
# 知识库静态 JSON API,接口路径不存在时返回 404,避免被 SPA 回退到 index.html
|
||||||
location /api/ {
|
location /api/ {
|
||||||
try_files $uri =404;
|
try_files $uri =404;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|||||||
const rootDir = path.resolve(__dirname, '..')
|
const rootDir = path.resolve(__dirname, '..')
|
||||||
const dataDir = path.join(rootDir, 'src', 'data')
|
const dataDir = path.join(rootDir, 'src', 'data')
|
||||||
const apiDir = path.join(rootDir, 'public', 'api')
|
const apiDir = path.join(rootDir, 'public', 'api')
|
||||||
|
const apiDocPath = path.join(rootDir, 'public', 'apidoc')
|
||||||
|
|
||||||
function readJson(relativePath) {
|
function readJson(relativePath) {
|
||||||
return JSON.parse(fs.readFileSync(path.join(rootDir, relativePath), 'utf8'))
|
return JSON.parse(fs.readFileSync(path.join(rootDir, relativePath), 'utf8'))
|
||||||
@@ -24,9 +25,21 @@ function writeJson(relativePath, data) {
|
|||||||
|
|
||||||
function cleanApiDir() {
|
function cleanApiDir() {
|
||||||
fs.rmSync(apiDir, { recursive: true, force: true })
|
fs.rmSync(apiDir, { recursive: true, force: true })
|
||||||
|
fs.rmSync(apiDocPath, { force: true })
|
||||||
ensureDir(apiDir)
|
ensureDir(apiDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function writeTextFile(target, content) {
|
||||||
|
ensureDir(path.dirname(target))
|
||||||
|
fs.writeFileSync(target, content, 'utf8')
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyApiDoc() {
|
||||||
|
const source = path.join(rootDir, 'docs', '知识库API接口说明.md')
|
||||||
|
const content = fs.readFileSync(source, 'utf8')
|
||||||
|
writeTextFile(apiDocPath, content)
|
||||||
|
}
|
||||||
|
|
||||||
function extractConstArrayFromTs(filePath, constName) {
|
function extractConstArrayFromTs(filePath, constName) {
|
||||||
const text = fs.readFileSync(filePath, 'utf8')
|
const text = fs.readFileSync(filePath, 'utf8')
|
||||||
const marker = `export const ${constName}`
|
const marker = `export const ${constName}`
|
||||||
@@ -280,4 +293,7 @@ for (const tool of tools) {
|
|||||||
writeJson(`tools/${tool.id}/usage.json`, toolUsage(tool))
|
writeJson(`tools/${tool.id}/usage.json`, toolUsage(tool))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copyApiDoc()
|
||||||
|
|
||||||
console.log(`已生成静态 API 文件:${path.relative(rootDir, apiDir)}`)
|
console.log(`已生成静态 API 文件:${path.relative(rootDir, apiDir)}`)
|
||||||
|
console.log(`已生成 Markdown 接口文档:${path.relative(rootDir, apiDocPath)}`)
|
||||||
|
|||||||
@@ -121,6 +121,15 @@ const endpoints: ApiEndpoint[] = [
|
|||||||
description: '返回指定工具与技术出现的过程。',
|
description: '返回指定工具与技术出现的过程。',
|
||||||
fields: ['id:工具 ID', 'name:工具名称', 'usedIn:使用该工具的过程数组'],
|
fields: ['id:工具 ID', 'name:工具名称', 'usedIn:使用该工具的过程数组'],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'api-doc-markdown',
|
||||||
|
name: 'Markdown 接口文档',
|
||||||
|
method: 'GET',
|
||||||
|
path: '/apidoc',
|
||||||
|
samplePath: '/apidoc',
|
||||||
|
description: '返回接口说明 Markdown 文本字符串。',
|
||||||
|
fields: ['响应体:Markdown 文本字符串', '用途:供知识库或外部系统直接读取接口说明'],
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const fieldGroups = [
|
const fieldGroups = [
|
||||||
@@ -167,7 +176,7 @@ export function ApiDocPage() {
|
|||||||
setResult('')
|
setResult('')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(requestPath, { headers: { Accept: 'application/json' } })
|
const response = await fetch(requestPath, { headers: { Accept: 'application/json, text/markdown, text/plain, */*' } })
|
||||||
const contentType = response.headers.get('content-type') ?? ''
|
const contentType = response.headers.get('content-type') ?? ''
|
||||||
const body = contentType.includes('application/json') ? await response.json() : await response.text()
|
const body = contentType.includes('application/json') ? await response.json() : await response.text()
|
||||||
|
|
||||||
@@ -200,8 +209,18 @@ export function ApiDocPage() {
|
|||||||
</div>
|
</div>
|
||||||
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">API 调用说明</h1>
|
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">API 调用说明</h1>
|
||||||
<p className="mt-2 max-w-2xl text-sm leading-6 text-gray-500 dark:text-gray-400">
|
<p className="mt-2 max-w-2xl text-sm leading-6 text-gray-500 dark:text-gray-400">
|
||||||
静态 JSON 接口采用 GET 请求,路径以 /api 开头,面向知识库读取;不包含搜索、展示样式和 五问一法。
|
静态接口采用 GET 请求,/api 返回 JSON,/apidoc 返回 Markdown 文本;面向知识库读取,不包含搜索、展示样式和五问一法。
|
||||||
</p>
|
</p>
|
||||||
|
<div className="mt-4 flex flex-wrap gap-2">
|
||||||
|
<a
|
||||||
|
href="/apidoc"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="inline-flex items-center rounded-lg bg-gray-900 px-3 py-2 text-sm font-medium text-white transition hover:bg-gray-700 dark:bg-white dark:text-gray-900 dark:hover:bg-gray-200"
|
||||||
|
>
|
||||||
|
查看 Markdown 文档 /apidoc
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-3 gap-3 text-center">
|
<div className="grid grid-cols-3 gap-3 text-center">
|
||||||
<div className="rounded-xl bg-gray-50 px-4 py-3 dark:bg-gray-900/50">
|
<div className="rounded-xl bg-gray-50 px-4 py-3 dark:bg-gray-900/50">
|
||||||
@@ -213,7 +232,7 @@ export function ApiDocPage() {
|
|||||||
<div className="text-xs text-gray-500 dark:text-gray-400">请求方法</div>
|
<div className="text-xs text-gray-500 dark:text-gray-400">请求方法</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-xl bg-gray-50 px-4 py-3 dark:bg-gray-900/50">
|
<div className="rounded-xl bg-gray-50 px-4 py-3 dark:bg-gray-900/50">
|
||||||
<div className="text-lg font-bold text-gray-900 dark:text-white">JSON</div>
|
<div className="text-lg font-bold text-gray-900 dark:text-white">JSON/MD</div>
|
||||||
<div className="text-xs text-gray-500 dark:text-gray-400">响应格式</div>
|
<div className="text-xs text-gray-500 dark:text-gray-400">响应格式</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user