Skip to content

Spineリクエストの処理過程を隠さないフレームワーク

Spineは、リクエストがどのように解決され、どのような順序で実行され、いつビジネスロジックが呼び出され、どのようにレスポンスとして完成するかを、明示的な実行パイプラインとして明らかにします。コントローラーはユースケースのみを表現し、実行に関するすべての判断はランタイムが責任を持ちます。

IoCコンテナ · 実行パイプライン · インターセプターチェーン
魔法のない実行構造

主な特徴

1. 慣れ親しんだ構造

Spring、NestJSの開発者ならすぐに始められます。Controller → Service → Repository のレイヤー構造とコンストラクタ注入、インターセプターチェーンまで。使い慣れたエンタープライズアーキテクチャを採用しつつ、実行はSpineの明示的なパイプラインが担当します。

go
func NewUserService(repo *UserRepository) *UserService {
    return &UserService{repo: repo}
}

func NewUserController(svc *UserService) *UserController {
    return &UserController{svc: svc}
}

2. 高速な起動

JVMウォームアップは必要ありません。 Node.js ランタイム初期化もありません。コンパイルされたGoバイナリはすぐに要求を受け取ります。

zsh — 80x24
➜ spine-app go run .

3. 少ないコード

@Injectable@Controller@Autowiredなどのアノテーションを使わず、型システムのみで依存関係を表現します。

アノテーションや慣例に頼らず、 シグネチャそのものが構造とコントラクトを明らかにします。

4. インターセプターパイプライン

リクエストの前/後/完了時にロジックを割り込ませることができます。
認証、トランザクション、ロギングなどの横断的関心事を
ビジネスコードから分離して実行フローに配置します。

実行順序はSpineのパイプラインが明示的に制御します。

go
goapp.Interceptor(
    &TxInterceptor{},
    &AuthInterceptor{},
    &LoggingInterceptor{},
)

実行は単一のパイプラインのみを経由します

Spineでは、リクエストは例外なく単一実行パイプラインを通過します。

Routerは実行対象を選択するだけであり、
実行順序とフローを認識しているのはPipelineただ一つだけです。

見えるものがすべてです

アノテーションなし、モジュール定義なし

main.go

go
// main.go
func main() {
    app := spine.New()
    
    // ✅ コンストラクタを登録するだけで依存関係を自動解決
    // ✅ 登録順序は不問
    app.Constructor(NewUserRepository, NewUserService, NewUserController)
    
    routes.RegisterUserRoutes(app)
    app.Run(boot.Options{
		Address:                ":8080",
		EnableGracefulShutdown: true,
		ShutdownTimeout:        10 * time.Second,
		HTTP: &boot.HTTPOptions{},
	})
}

routes.go

go
// routes.go
func RegisterUserRoutes(app spine.App) {
    // ✅ ルートとハンドラーの接続が明示的
    // ✅ どのメソッドがどのパスであるか一目で把握
    app.Route("GET", "/users", (*UserController).GetUser)
    app.Route("POST", "/users", (*UserController).CreateUser)
}

controller.go

go
// controller.go
// ✅ アノテーションなし — 純粋なGo構造体
// ✅ テスト時のモック化が容易
type UserController struct {
    svc *UserService
}

// ✅ コンストラクタパラメータ = 依存関係の宣言
// ✅ 隠された魔法はなし
func NewUserController(svc *UserService) *UserController {
    return &UserController{svc: svc}
}

// ✅ 関数シグネチャがそのままAPIスペック
// ✅ 入力(query.Values)、出力(UserResponse, error)が明確
func (c *UserController) GetUser(ctx context.Context, q query.Values) (UserResponse, error) {
    return c.svc.Get(ctx, q.Int("id", 0))
}

service.go

go
// service.go
// ✅ アノテーションなし
type UserService struct {
    repo *UserRepository
}

func NewUserService(repo *UserRepository) *UserService {
    return &UserService{repo: repo}
}

repository.go

go
// repository.go
// ✅ アノテーションなし
type UserRepository struct {
    db *bun.DB
}

func NewUserRepository(db *bun.DB) *UserRepository {
    return &UserRepository{db: db}
}

"リクエストの処理過程を隠さないフレームワーク"