簡介
Spine 是透過 Go 程式碼註冊建構函式、路由與攔截器的網頁框架。從註冊程式碼就能看出由哪個處理器接收請求,以及在呼叫前後執行哪些工作。
如果是第一次使用,請從第一個應用程式開始,透過 CLI 建立專案並確認 GET /health 的回應。本篇介紹設定應用程式時會用到的核心概念。
設定與執行應用程式
在 CLI 建立的專案中,應用程式的設定程式碼集中放在 internal/application/application.go 的 BuildApplication()。main.go 依照 BuildApplication → Validate → Run 的順序,先設定及驗證應用程式,再執行。
以下是自行實作使用者功能後的註冊範例。範例省略了 UserController 與攔截器的實作,請勿用這段程式碼覆寫產生的檔案。
func BuildApplication() (spine.App, boot.Options, error) {
app := spine.New()
// 생성자를 등록하면 등록 순서와 관계없이 의존성을 해결합니다.
app.Constructor(NewUserRepository, NewUserService, NewUserController)
// 인터셉터를 실행할 순서대로 등록합니다.
app.InterceptorFor(boot.InterceptorHTTP, &TxInterceptor{}, &LoggingInterceptor{})
// HTTP 메서드와 경로에 핸들러를 연결합니다.
app.Route("GET", "/users", (*UserController).GetUser)
return app, boot.Options{
Address: ":8080",
EnableGracefulShutdown: true,
ShutdownTimeout: 10 * time.Second,
HTTP: &boot.HTTPOptions{},
}, nil
}CLI 指令 spine generate resource user 產生的程式碼,其名稱與路徑和上述範例不同。產生的處理器是 src/user 中的 UserController.Get,路徑則是 GET /user/:id。建構函式已註冊時,請勿再次註冊相同的建構函式或路由。也必須保留新增至 BuildApplication 的 user.Register(app) 呼叫及錯誤處理。詳細步驟請參閱專案結構。
核心概念
1. 以建構函式進行相依性注入
透過建構函式的參數宣告所需的相依性,再將建構函式註冊至 app.Constructor。在下列範例中,UserService 會接收 UserRepository。
// 생성자 파라미터가 곧 의존성 선언
func NewUserService(repo *UserRepository) *UserService {
return &UserService{repo: repo}
}
// 등록만 하면 자동으로 의존성 그래프 해결
app.Constructor(NewUserRepository, NewUserService, NewUserController)2. 攔截器管線
攔截器在控制器呼叫前後,執行身分驗證、交易與記錄日誌等共通工作。以下範例展示三個自行實作的攔截器的註冊順序。
app.Interceptor(
&TxInterceptor{}, // 1. 트랜잭션 시작
&AuthInterceptor{}, // 2. 인증 확인
&LoggingInterceptor{}, // 3. 로깅
)PreHandle 依註冊順序執行。控制器返回後的 PostHandle、處理回應前的 BeforeResponse,以及處理回應後的 AfterCompletion,則依反向順序執行。發生錯誤時的呼叫條件,請參閱攔截器。
3. 明確的路由註冊
使用 app.Route 將 HTTP 方法、路徑與處理器連結起來。為各項功能建立註冊函式,就能集中管理相關路由。
// 한 곳에서 모든 라우트를 관리
func RegisterUserRoutes(app spine.App) {
app.Route("GET", "/users", (*UserController).GetUser)
app.Route("POST", "/users", (*UserController).CreateUser)
app.Route("PUT", "/users", (*UserController).UpdateUser)
app.Route("DELETE", "/users", (*UserController).DeleteUser)
}4. 型別安全的處理器
透過處理器的參數與回傳型別,表達要從請求讀取的值及回應格式。下列範例的查詢處理器會讀取查詢參數,建立處理器則會以結構體指標接收 JSON 請求主體。服務、請求與回應型別都需要自行實作。
// 함수 시그니처가 곧 API 스펙
func (c *UserController) GetUser(
ctx context.Context, // 컨텍스트
q query.Values, // 쿼리 파라미터
) (httpx.Response[UserResponse], error) { // 응답 타입
user, err := c.svc.Get(ctx, q.Int("id", 0))
if err != nil {
return httpx.Response[UserResponse]{}, err
}
return httpx.Response[UserResponse]{Body: user}, nil
}
// DTO는 자동으로 바인딩
func (c *UserController) CreateUser(
ctx context.Context,
req *CreateUserRequest, // JSON body → 구조체 (포인터)
) (httpx.Response[UserResponse], error) {
user, err := c.svc.Create(ctx, req)
if err != nil {
return httpx.Response[UserResponse]{}, err
}
return httpx.Response[UserResponse]{Body: user}, nil
}開始使用
go install github.com/NARUBROWN/spine-cli/cmd/spine@v0.1.4
spine version