-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: openapi doc generator (#2644)
* chore: extract the type and comment from apis * chore: template code * feat: openapi * pref: openapi generator. send into public/openapi folder
- Loading branch information
Showing
12 changed files
with
2,221 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
SEARCH_PATH=support |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
*.js | ||
openapi.json | ||
openapi.out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { parseAPI } from './utils'; | ||
import * as fs from 'fs'; | ||
import * as path from 'path'; | ||
import { convertOpenApi } from './openapi'; | ||
|
||
const rootPath = 'projects/app/src/pages/api'; | ||
const exclude = ['/admin', '/proApi']; | ||
|
||
function getAllFiles(dir: string) { | ||
let files: string[] = []; | ||
const stat = fs.statSync(dir); | ||
if (stat.isDirectory()) { | ||
const list = fs.readdirSync(dir); | ||
list.forEach((item) => { | ||
const fullPath = path.join(dir, item); | ||
if (!exclude.some((excluded) => fullPath.includes(excluded))) { | ||
files = files.concat(getAllFiles(fullPath)); | ||
} | ||
}); | ||
} else { | ||
files.push(dir); | ||
} | ||
return files; | ||
} | ||
|
||
const searchPath = process.env.SEARCH_PATH || ''; | ||
|
||
const files = getAllFiles(path.join(rootPath, searchPath)); | ||
// console.log(files) | ||
const apis = files.map((file) => { | ||
return parseAPI({ path: file, rootPath }); | ||
}); | ||
|
||
const openapi = convertOpenApi({ | ||
apis, | ||
openapi: '3.0.0', | ||
info: { | ||
title: 'FastGPT OpenAPI', | ||
version: '1.0.0', | ||
author: 'FastGPT' | ||
}, | ||
servers: [ | ||
{ | ||
url: 'http://localhost:4000' | ||
} | ||
] | ||
}); | ||
|
||
const json = JSON.stringify(openapi, null, 2); | ||
|
||
fs.writeFileSync('./scripts/openapi/openapi.json', json); | ||
fs.writeFileSync('./scripts/openapi/openapi.out', JSON.stringify(apis, null, 2)); | ||
|
||
console.log('Total APIs:', files.length); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
import { ApiType } from './type'; | ||
|
||
type OpenAPIParameter = { | ||
name: string; | ||
in: string; | ||
description: string; | ||
required: boolean; | ||
schema: { | ||
type: string; | ||
}; | ||
}; | ||
|
||
type OpenAPIResponse = { | ||
[code: string]: { | ||
description?: string; | ||
content: { | ||
[mediaType: string]: { | ||
schema: { | ||
type: string; | ||
properties?: { | ||
[key: string]: { | ||
type: string; | ||
description?: string; | ||
}; | ||
}; | ||
}; | ||
}; | ||
}; | ||
}; | ||
}; | ||
|
||
type PathType = { | ||
[method: string]: { | ||
description: string; | ||
parameters: OpenAPIParameter[]; | ||
responses: OpenAPIResponse; | ||
}; | ||
}; | ||
|
||
type PathsType = { | ||
[url: string]: PathType; | ||
}; | ||
|
||
type OpenApiType = { | ||
openapi: string; | ||
info: { | ||
title: string; | ||
version: string; | ||
author: string; | ||
}; | ||
paths: PathsType; | ||
servers?: { | ||
url: string; | ||
}[]; | ||
}; | ||
|
||
export function convertPath(api: ApiType): PathType { | ||
const method = api.method.toLowerCase(); | ||
const parameters: any[] = []; | ||
if (api.query) { | ||
if (Array.isArray(api.query)) { | ||
api.query.forEach((item) => { | ||
parameters.push({ | ||
name: item.key, | ||
description: item.comment, | ||
in: 'query', | ||
required: item.required, | ||
schema: { | ||
type: item.type | ||
} | ||
}); | ||
}); | ||
} else { | ||
parameters.push({ | ||
description: api.query.comment, | ||
name: api.query.key, | ||
in: 'query', | ||
required: api.query.required, | ||
schema: { | ||
type: api.query.type | ||
} | ||
}); | ||
} | ||
} else if (api.body) { | ||
if (Array.isArray(api.body)) { | ||
api.body.forEach((item) => { | ||
parameters.push({ | ||
description: item.comment, | ||
name: item.key, | ||
in: 'body', | ||
required: item.required, | ||
schema: { | ||
type: item.type | ||
} | ||
}); | ||
}); | ||
} | ||
} | ||
|
||
const responses: OpenAPIResponse = (() => { | ||
if (api.response) { | ||
if (Array.isArray(api.response)) { | ||
const properties: { | ||
[key: string]: { | ||
type: string; | ||
description?: string; | ||
}; | ||
} = {}; | ||
|
||
api.response.forEach((item) => { | ||
properties[item.type] = { | ||
type: item.key ?? item.type, | ||
description: item.comment | ||
}; | ||
}); | ||
const res: OpenAPIResponse = { | ||
'200': { | ||
description: api.description ?? '', | ||
content: { | ||
'application/json': { | ||
schema: { | ||
type: 'object', | ||
properties | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
return res; | ||
} else { | ||
return { | ||
'200': { | ||
description: api.response.comment ?? '', | ||
content: { | ||
'application/json': { | ||
schema: { | ||
type: api.response.type | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
} | ||
} else { | ||
return { | ||
'200': { | ||
description: api.description ?? '', | ||
content: { | ||
'application/json': { | ||
schema: { | ||
type: 'object' | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
} | ||
})(); | ||
return { | ||
[method]: { | ||
description: api.description ?? '', | ||
parameters, | ||
responses | ||
} | ||
}; | ||
} | ||
export function convertOpenApi({ | ||
apis, | ||
...rest | ||
}: { | ||
apis: ApiType[]; | ||
} & Omit<OpenApiType, 'paths'>): OpenApiType { | ||
const paths: PathsType = {}; | ||
apis.forEach((api) => { | ||
paths[api.url] = convertPath(api); | ||
}); | ||
return { | ||
paths, | ||
...rest | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"name": "test", | ||
"module": "index.js", | ||
"scripts": { | ||
"build": "tsc index.ts" | ||
}, | ||
"devDependencies": { | ||
"@babel/types": "^7.25.6", | ||
"@types/babel__generator": "^7.6.8", | ||
"@types/babel__traverse": "^7.20.6" | ||
}, | ||
"peerDependencies": { | ||
"typescript": "^5.0.0" | ||
}, | ||
"dependencies": { | ||
"@babel/generator": "^7.25.6", | ||
"@babel/parser": "^7.25.6", | ||
"@babel/traverse": "^7.25.6", | ||
"babel": "^6.23.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
```ts | ||
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next'; | ||
import { NextAPI } from '@/service/middleware/entry'; | ||
|
||
// This should be at the top of the file after the imports | ||
export const ApiMetadata = { | ||
name: 'template example api', | ||
author: 'Finley', | ||
version: '0.1.0', | ||
} | ||
|
||
export type TemplateQuery = { | ||
// The App's ID | ||
appId?: string[], | ||
// The App's Name | ||
name: string, | ||
// The App's Description | ||
description: string | Something<AppDetailType>, | ||
}; | ||
|
||
export type TemplateBody = { | ||
// The App's Name | ||
name: string, | ||
}; | ||
|
||
// This is the response type for the API | ||
export type TemplateResponse = AppDetailType; | ||
|
||
// This is the template API for FASTGPT NextAPI | ||
async function handler( | ||
req: ApiRequestProps<TemplateBody, TemplateQuery>, | ||
res: ApiResponseType<any>, | ||
): Promise<TemplateResponse> { | ||
|
||
return {} | ||
} | ||
|
||
export default NextAPI(handler); | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
export type ApiMetaData = { | ||
name?: string; | ||
author?: string; | ||
version?: string; | ||
}; | ||
|
||
export type ApiType = { | ||
description?: string; | ||
path: string; | ||
url: string; | ||
query?: itemType | itemType[]; | ||
body?: itemType | itemType[]; | ||
response?: itemType | itemType[]; | ||
method: 'GET' | 'POST' | 'PUT' | 'DELETE'; | ||
} & ApiMetaData; | ||
|
||
export type itemType = { | ||
comment?: string; | ||
key?: string; | ||
type: string; | ||
required?: boolean; | ||
}; |
Oops, something went wrong.