Skip to content

All features of Tealina work in one api-dir directory, When there are other API directories, such as api-v2, manual processing is required:

1. Update 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. Create first API

will genereate all relative files

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. Build v2 API route

Copy a copy of src/app/buildV1Router.ts, rename it to buildV2Router.ts, and modify the file content as needed.

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. Registe v2 API router

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.Registe v2 doc router

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. Create a new req.ts

Copy a copy of web/src/api/req.ts, rename it to reqV2.ts, and modify the file content as needed.

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);