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'
}
)
NestJS Request LifeCycle
NestJS 請求生命週期:詳細解說
NestJS 是一個流行的 Node.js 框架,它專注於模組化和可維護性的伺服器端邏輯管理。理解 NestJS 如何運作的關鍵之一,就是了解請求的生命週期。在本文中,我們將逐步介紹每個階段,詳細說明一個請求從進入到結束所經歷的過程。
### 請求進入 (Incoming Request)
每個生命週期的開始都是一個 **請求進入**。這是應用程式接收到 HTTP 請求的初始點。這一步標誌著客戶端互動(通常通過瀏覽器或 API 客戶端)進入 NestJS 應用程式,並觸發整個處理過程。
### 中介軟體 (Middleware)
在請求進入系統後,它會經過 **中介軟體** 的處理。中介軟體用於執行例如日誌記錄、請求驗證,或向請求物件附加額外屬性等任務。在 NestJS 中,中介軟體可以分為兩種類型:
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)
訂閱:
文章 (Atom)