import {
DocumentBuilder,
SwaggerModule as NestSwaggerModule
} from '@nestjs/swagger'
// 建立Swagger的設定
const config = new DocumentBuilder()
.addSecurity('JWT', {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
in: 'header'
})
.build()
// 設定Swagger的路徑
NestSwaggerModule.setup(path, app, document, {
swaggerOptions: {
// 永久儲存授權
persistAuthorization: true,
// 預設分類不展開
docExpansion: 'none',
onComplete: () => {
// 設定是否為登入請求
let isLoginRequest = false
// 取得fetch
const originalFetch = window.fetch
// 覆寫fetch
window.fetch = async function (...args) {
// 執行原本的fetch
const response = await originalFetch.apply(this, args)
try {
// 如果為SingIn Request
if (isLoginRequest) {
// clone response
const clone = response.clone()
// 取得Content-Type
const contentType =
response.headers.get('content-type')
// 如果為JSON
if (contentType?.includes('application/json')) {
// 取得JSON
const data = await clone.json()
// 檢查 token
const token = data?.data?.token
// 如果有token
if (token) {
// 設定 Token
;(window as any).ui.preauthorizeApiKey(
'JWT',
token
)
// 重置標記
isLoginRequest = false
}
}
}
} catch (error) {
console.error('Error processing response:', error)
}
return response
}
// 添加點擊事件監聽
;(window as any).document.addEventListener(
'click',
(e: any) => {
if (
e.target.matches(
'.btn.execute.opblock-control__btn'
)
) {
// 取得URL的Query
const urlQuery = window.location.hash.slice(1)
// 如果URL的Query包含 _singIn_
if (urlQuery.includes('_singIn_')) {
// 如果是登入請求
isLoginRequest = true
}
}
}
)
}
},
customSiteTitle: 'API Documentation'
})
2024/11/19
Auto-filling JWT Token in NestJS Swagger Documentation
2024/11/16
Implement a Current Language Decorator in NestJS
再Nestjs要取得當前Request語系可以透過Decorator去取得
import { createParamDecorator, ExecutionContext } from '@nestjs/common'
import { Request } from 'express'
/**
* 取得語系
* @param data {unknown}
* @example
* @Controller('users')
* export class UserController {
* @Get('profile')
* getProfile(@CurrentUser() userId: number) {
* return { userId };
* }
* }
*
* // 與其他guard結合使用
* @Controller('users')
* export class UserController {
* @UseGuards(JwtAuthGuard)
* @Get('profile')
* getProfile(@CurrentUser() userId: number) {
* return { userId };
* }
* }
*/
export const Lang = createParamDecorator(
/**
* Factory
* @param data {unknown}
* @param ctx {ExecutionContext}
* @return {string}
*/
(data: unknown, ctx: ExecutionContext): string => {
//取得Http上下文
const httpContext = ctx.switchToHttp()
// 取得Request
const request: Request = httpContext.getRequest()
// 回傳語系 找不到就預設台灣
return (request?.headers?.lang as string) || 'zh-TW'
}
)
Implementing Global HTTP Status 200 Response in NestJS
根據不同的 HTTP 方法,NestJS 會自動設置對應的 HTTP 狀態碼,但基於特定需求,我會另作考量和調整
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor
} from '@nestjs/common'
import { Observable } from 'rxjs'
import { Response } from 'express'
/**
* Response Interceptor
* @class {ResponseInterceptor}
* @implements {NestInterceptor}
*/
@Injectable()
export class ResponseInterceptor implements NestInterceptor {
/**
* Intercept
* @param context {ExecutionContext} - 執行上下文
* @param next {CallHandler} - 呼叫處理程序
* @return {Observable} 返回 Observable
*/
intercept(context: ExecutionContext, next: CallHandler): Observable {
// 取得 Http 上下文
const contextHttp = context.switchToHttp()
// 取得 Response 物件
const response: Response = contextHttp.getResponse()
// 設定成Http Status 200
response.status(200)
return next.handle()
}
}
main.ts
2024/11/13
Nestjs 透過Exception攔截找不到API問題
要在Nestjs攔截API或url找不到問題可以透過Exception或Middleware的方式實現
先安裝express
代碼如下
記得要在listen前加入這段代碼
先安裝express
pnpm i @types/express express -D
代碼如下
import {
ArgumentsHost,
Catch,
ExceptionFilter,
NotFoundException
} from '@nestjs/common'
import { Request, Response } from 'express'
/**
* Filter to catch not found exceptions
* @class {NotFoundFilter}
* @implements {ExceptionFilter}
*/
@Catch()
export class NotFoundFilter implements ExceptionFilter {
/**
* Catch the exception
* @param exception {NotFoundException}
* @param host {ArgumentsHost}
* @return {Promise}
*/
catch(
exception: NotFoundException,
host: ArgumentsHost
): Promise {
// 取得Http的上下文
const ctx = host.switchToHttp()
// 取得Response
const response = ctx.getResponse()
//取得Request
const request = ctx.getRequest()
// 取得使用者語系
const lang = request.headers['lang'] as string
// 取得錯誤訊息
const errorResponse = {
msg: 'API route not found',
err: true
}
// 透過Response回傳錯誤訊息
response.status(200).json(errorResponse)
}
}
記得要在listen前加入這段代碼
2024/11/03
NestJS 實現API版本控制
在現代API開發中,實現API版本控制是不可或缺的設計模式,特別是當應用逐步擴展且不斷迭代時,良好的版本管理至關重要。本文將介紹如何在NestJS中使用 VersioningType.URI
來實現API的版本控制,並深入分析兩種控制器的版本設定方式,幫助開發者根據實際需求選擇最佳方案。
Step 1: 設定全域前綴詞(setGlobalPrefix)
首先,設定全域前綴詞是必要的。務必先設定 setGlobalPrefix
,再啟用版本控制,否則後續的版本控制將無法正確應用到API路徑。
// 設置全域的API前綴詞
const globalPrefix = 'api';
app.setGlobalPrefix(globalPrefix);
這行代碼會將所有API路徑統一設為/api
開頭,例如/api/v1/test/echo
。這樣可以讓API結構層次分明,並方便後續的維護和版本管理。
Step 2: 啟用版本控制(enableVersioning)
使用NX 體驗 Monorepo的美好
什麼是 Monorepo?為什麼要使用它?
隨著軟體專案的成長,特別是在多模組、多應用程式的環境下,管理代碼的挑戰也隨之增加。傳統的 Multi-Repo 策略(每個模組使用獨立儲存庫)在版本一致性和依賴管理方面存在不少痛點,特別是當需要頻繁更新和協作時,容易引發衝突和整合困難。
Monorepo 是一種更集中的管理方式。透過將所有模組放在一個儲存庫中,開發團隊可以更容易地維持一致的依賴版本和共享代碼。這種方法在大型專案中具備幾個顯著優勢:
- 依賴一致性:Monorepo 確保所有模組使用相同版本的依賴,避免因為版本衝突而引起的問題。
- 跨模組重用和同步:允許模組之間共享代碼,並在單一提交中完成多個模組的變更,方便同步更新。
- 統一的 CI/CD 管理:可以使用一套測試和構建流程來處理所有模組,簡化 CI/CD 配置。
- 增量編譯和快取:通過增量構建和快取技術(如 NX 的增量編譯),Monorepo 能顯著減少重複編譯的時間,提高開發效率。
NX:專為 Monorepo 優化的開發工具
NX 是一個強大的 Monorepo 工具,專為管理多模組、多應用的專案而設計。它支援增量編譯、自動快取、依賴視覺化等功能,幫助開發團隊減少不必要的構建,提升整體開發效率。此外,NX 還具有任務調度、代碼生成和豐富的插件生態,適合大型團隊的專案開發需求。
此外,NX 可以與高效的包管理器 pnpm 搭配使用。pnpm 具備高度優化的快取和依賴管理能力,使得構建和測試更加高效。接下來,我們將介紹如何使用 NX 和 pnpm 建立並管理一個 Monorepo 專案,並說明其主要操作指令。
訂閱:
文章 (Atom)