Follow the conventions, So Tealina can help you generate API documentation, type declarations, and updated index files.
File Structure
- All API files store in
[api-dir]/[method]
,
md
api-dir
├─ index.ts
└─ post
├─ index.ts
├─ login.ts
├─ category
└─── create.ts
api-dir
├─ index.ts
└─ post
├─ index.ts
├─ login.ts
├─ category
└─── create.ts
- One API one file
md
api-dir
├─ index.ts
└─ post
├─ index.ts
├─ login.ts
├─ category
└─── create.ts
api-dir
├─ index.ts
└─ post
├─ index.ts
├─ login.ts
├─ category
└─── create.ts
Inside File
- Each API file has an export default handler
ts
import type { AuthedHandler } from '../../../../types/handler.js'
import type { Pure } from '../../../../types/pure.js'
import { convention } from '../../../convention.js'
type ApiType = AuthedHandler<{ body: Pure.CategoryCreateInput }, Pure.Category>
/** Comement declare here will be extra to API document */
const handler: ApiType = async (req, res) => {
...
}
export default convention(handler)
import type { AuthedHandler } from '../../../../types/handler.js'
import type { Pure } from '../../../../types/pure.js'
import { convention } from '../../../convention.js'
type ApiType = AuthedHandler<{ body: Pure.CategoryCreateInput }, Pure.Category>
/** Comement declare here will be extra to API document */
const handler: ApiType = async (req, res) => {
...
}
export default convention(handler)
ts
import type { NextFunction, Request, Response } from 'express'
interface RawPayload {
body?: unknown
params?: unknown
query?: unknown
}
export interface AuthedHandler<
T extends RawPayload = {},
Tresponse = null,
Theaders extends Request['headers'] = AuthHeaders,
Tlocals extends Record<string, any> = AuthedLocals,
> {
(
req: Request<T['params'], Tresponse, T['body'], T['query']>,
res: Response<Tresponse, Tlocals>,
next: NextFunction,
): any
}
...
import type { NextFunction, Request, Response } from 'express'
interface RawPayload {
body?: unknown
params?: unknown
query?: unknown
}
export interface AuthedHandler<
T extends RawPayload = {},
Tresponse = null,
Theaders extends Request['headers'] = AuthHeaders,
Tlocals extends Record<string, any> = AuthedLocals,
> {
(
req: Request<T['params'], Tresponse, T['body'], T['query']>,
res: Response<Tresponse, Tlocals>,
next: NextFunction,
): any
}
...
ts
export namespace Pure {
interface Category{
/** @default {autoincrement()} */
id: number
categoryName: string
description: string
}
interface CategoryCreateInput{
/** @default {autoincrement()} */
id?: number
categoryName: string
description: string
}
}
export namespace Pure {
interface Category{
/** @default {autoincrement()} */
id: number
categoryName: string
description: string
}
interface CategoryCreateInput{
/** @default {autoincrement()} */
id?: number
categoryName: string
description: string
}
}
ts
import type { RequestHandler } from 'express'
import type { CustomHandlerType } from '../types/handler.js'
type ConstrainedHandlerType = readonly [...RequestHandler[], CustomHandlerType]
type EnsureHandlerType = <const T extends ConstrainedHandlerType>(
...handlers: T
) => T
// just do the check type
export const convention: EnsureHandlerType = (...handlers) => handlers
import type { RequestHandler } from 'express'
import type { CustomHandlerType } from '../types/handler.js'
type ConstrainedHandlerType = readonly [...RequestHandler[], CustomHandlerType]
type EnsureHandlerType = <const T extends ConstrainedHandlerType>(
...handlers: T
) => T
// just do the check type
export const convention: EnsureHandlerType = (...handlers) => handlers
Index
[api-dir]/[method]/index.ts
declare route and hanlder Map
ts
export default {
'category/create': import('./category/create.js'),
...
}
export default {
'category/create': import('./category/create.js'),
...
}
[api-dir]/index.ts
declare method and routes Map
ts
export default {
'post': import('./post/index.js'),
...
}
export default {
'post': import('./post/index.js'),
...
}
Type declaration
[api-dir].d.ts
for APIs type entry
ts
import apis from '../src/api-v1/index.ts'
import type { ResolveApiType } from './handler.js'
type RawApis = typeof apis
export type ApiTypesRecord = {
[Method in keyof RawApis]: ResolveApiType<Awaited<RawApis[Method]>['default']>
}
import apis from '../src/api-v1/index.ts'
import type { ResolveApiType } from './handler.js'
type RawApis = typeof apis
export type ApiTypesRecord = {
[Method in keyof RawApis]: ResolveApiType<Awaited<RawApis[Method]>['default']>
}