Tealina 所有特性都是作用在一个 [api-dir]
目录, 当有其他API目录, 比如: api-v2, 需要手动处理:
1. 更新 server/packages.json
json
{
"scripts": {
"v1": "tealina src/api-v1",
"v2": "tealina src/api-v2"
},
"exports": {
"./api/v1": "./types/api-v1.d.ts",
"./api/v2": "./types/api-v2.d.ts"
}
}
{
"scripts": {
"v1": "tealina src/api-v1",
"v2": "tealina src/api-v2"
},
"exports": {
"./api/v1": "./types/api-v1.d.ts",
"./api/v2": "./types/api-v2.d.ts"
}
}
2. 创建一个 API
会自动生成关联文件
bash
yarn v2 get/status
yarn v2 get/status
output
+ api-v2/index.ts
+ api-v2/get/index.ts
+ api-v2/get/status.ts
+ types/api-v2.d.ts
3. 构建 v2
API 路由
复制一份 src/app/buildV1Router.ts, 更名为 buildV2Router.ts, 并按需修改文件内容
ts
import { Router } from 'express'
import { map, pipe, omitFn } from 'fp-lite'
import apisV2 from '../api-v2/index.js'
// ...
const registeSeparetely = (record: ResolvedAPIs) => {
// ...
}
export const buildV1Router = async () => {
const record = await loadAPIs(apisV2)
validateMethod(record)
const [openRouter, authRouter] = registeSeparetely(record)
const router = Router().use(openRouter).use(authRouter)
return router
}
import { Router } from 'express'
import { map, pipe, omitFn } from 'fp-lite'
import apisV2 from '../api-v2/index.js'
// ...
const registeSeparetely = (record: ResolvedAPIs) => {
// ...
}
export const buildV1Router = async () => {
const record = await loadAPIs(apisV2)
validateMethod(record)
const [openRouter, authRouter] = registeSeparetely(record)
const router = Router().use(openRouter).use(authRouter)
return router
}
4. 注册路由
ts
// server/src/app/buildApiRouter.ts
import { Router } from 'express'
import { setupApiHeaders } from '../middlewares/setupApiHeaders.js'
import { buildV1Router } from './buildV1Router.js'
import { buildV2Router } from './buildV2Router.js'
import { apiNotFoundHandler } from '../middlewares/notFoundHandler.js'
export const buildApiRoute = async () => {
const v1ApiRouter = await buildV1Router()
return (
Router({ caseSensitive: true })
.use(setupApiHeaders)
.use('/v1', v1ApiRouter)
.use('/v2', v2ApiRouter)
.use(apiNotFoundHandler)
)
}
//...
// server/src/app/buildApiRouter.ts
import { Router } from 'express'
import { setupApiHeaders } from '../middlewares/setupApiHeaders.js'
import { buildV1Router } from './buildV1Router.js'
import { buildV2Router } from './buildV2Router.js'
import { apiNotFoundHandler } from '../middlewares/notFoundHandler.js'
export const buildApiRoute = async () => {
const v1ApiRouter = await buildV1Router()
return (
Router({ caseSensitive: true })
.use(setupApiHeaders)
.use('/v1', v1ApiRouter)
.use('/v2', v2ApiRouter)
.use(apiNotFoundHandler)
)
}
//...
5. 注册 v2
文档路由
Details
ts
// server/src/app/docRouter.ts
const vDocCofig: TealinaVdocWebConfig = {
sources: [
{
baseURL: '/api/v1',
jsonURL: `${VDOC_BASENAME}/v1.json`,
name: 'v1',
},
{
baseURL: '/api/v2',
jsonURL: `${VDOC_BASENAME}/v2.json`,
name: 'v2',
},
],
///....
}
const docRouter = Router({ caseSensitive: true })
.get('/index.html', (_req, res) => {
assembleHTML(vDocCofig).then(html => res.send(html))
})
.get('/v1.json', (_req, res) => {
res.sendFile(path.resolve('docs/api-v1.json'))
})
.get('/v2.json', (_req, res) => {
res.sendFile(path.resolve('docs/api-v2.json'))
})
.use(express.static(getAssetsPath()))
export { docRouter, VDOC_BASENAME }
// server/src/app/docRouter.ts
const vDocCofig: TealinaVdocWebConfig = {
sources: [
{
baseURL: '/api/v1',
jsonURL: `${VDOC_BASENAME}/v1.json`,
name: 'v1',
},
{
baseURL: '/api/v2',
jsonURL: `${VDOC_BASENAME}/v2.json`,
name: 'v2',
},
],
///....
}
const docRouter = Router({ caseSensitive: true })
.get('/index.html', (_req, res) => {
assembleHTML(vDocCofig).then(html => res.send(html))
})
.get('/v1.json', (_req, res) => {
res.sendFile(path.resolve('docs/api-v1.json'))
})
.get('/v2.json', (_req, res) => {
res.sendFile(path.resolve('docs/api-v2.json'))
})
.use(express.static(getAssetsPath()))
export { docRouter, VDOC_BASENAME }
6. 前端创建一个新的 req.ts
复制一份 web/src/api/req.ts, 更名为 reqV2.ts, 并按需修改文件内容
ts
// web/src/api/reqV2.ts
import axios from "axios";
import { ApiTypesRecord } from "server/api/v2";
import { MakeReqType, createReq } from "./createReq";
const instance = axios.create({
baseURL: "/api/v2",
});
instance.interceptors.response.use((v) => v.data);
export const req = createReq<MakeReqType<ApiTypesRecord>>(instance);
// web/src/api/reqV2.ts
import axios from "axios";
import { ApiTypesRecord } from "server/api/v2";
import { MakeReqType, createReq } from "./createReq";
const instance = axios.create({
baseURL: "/api/v2",
});
instance.interceptors.response.use((v) => v.data);
export const req = createReq<MakeReqType<ApiTypesRecord>>(instance);