はじめに
Spineは、コンストラクタ、ルート、インターセプターをGoコードで登録するWebフレームワークです。リクエストを受け取るハンドラーと、その前後に実行する処理を登録コードで確認できます。
初めて使う場合は、最初のアプリで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. インターセプターのパイプライン
インターセプターは、コントローラーの呼び出し前後に、認証、トランザクション、ロギングなどの共通処理を実行します。次の例は、自分で実装した3つのインターセプターの登録順序を示しています。
app.Interceptor(
&TxInterceptor{}, // 1. 트랜잭션 시작
&AuthInterceptor{}, // 2. 인증 확인
&LoggingInterceptor{}, // 3. 로깅
)PreHandleは登録順に実行されます。コントローラーが戻った後のPostHandle、レスポンス処理前のBeforeResponse、レスポンス処理後のAfterCompletionは逆順に実行されます。エラー発生時の呼び出し条件はインターセプターで説明します。
3. 明示的なルーティング
app.RouteでHTTPメソッド、パス、ハンドラーを関連付けます。機能ごとに登録関数を用意すると、関連するルートを1か所で管理できます。
// 한 곳에서 모든 라우트를 관리
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 versionCLIをインストールしたら、最初のアプリでプロジェクトを生成し、HTTPレスポンスを確認してください。コマンドが見つからない場合は、インストール手順のパス設定を参照してください。
