Spineリクエストの処理過程を隠さないフレームワーク
Spineは、リクエストがどのように解決され、どのような順序で実行され、いつビジネスロジックが呼び出され、どのようにレスポンスとして完成するかを、明示的な実行パイプラインとして明らかにします。コントローラーはユースケースのみを表現し、実行に関するすべての判断はランタイムが責任を持ちます。
Spineは、リクエストがどのように解決され、どのような順序で実行され、いつビジネスロジックが呼び出され、どのようにレスポンスとして完成するかを、明示的な実行パイプラインとして明らかにします。コントローラーはユースケースのみを表現し、実行に関するすべての判断はランタイムが責任を持ちます。
IoCコンテナ · 実行パイプライン · インターセプターチェーン
魔法のない実行構造
Spring、NestJSの開発者ならすぐに始められます。Controller → Service → Repository のレイヤー構造とコンストラクタ注入、インターセプターチェーンまで。使い慣れたエンタープライズアーキテクチャを採用しつつ、実行はSpineの明示的なパイプラインが担当します。
func NewUserService(repo *UserRepository) *UserService {
return &UserService{repo: repo}
}
func NewUserController(svc *UserService) *UserController {
return &UserController{svc: svc}
}JVMウォームアップは必要ありません。 Node.js ランタイム初期化もありません。コンパイルされたGoバイナリはすぐに要求を受け取ります。
@Injectable、@Controller、@Autowiredなどのアノテーションを使わず、型システムのみで依存関係を表現します。
アノテーションや慣例に頼らず、 シグネチャそのものが構造とコントラクトを明らかにします。
リクエストの前/後/完了時にロジックを割り込ませることができます。
認証、トランザクション、ロギングなどの横断的関心事を
ビジネスコードから分離して実行フローに配置します。
実行順序はSpineのパイプラインが明示的に制御します。
goapp.Interceptor(
&TxInterceptor{},
&AuthInterceptor{},
&LoggingInterceptor{},
)Spineでは、リクエストは例外なく単一実行パイプラインを通過します。
Routerは実行対象を選択するだけであり、
実行順序とフローを認識しているのはPipelineただ一つだけです。
アノテーションなし、モジュール定義なし
// 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
func RegisterUserRoutes(app spine.App) {
// ✅ ルートとハンドラーの接続が明示的
// ✅ どのメソッドがどのパスであるか一目で把握
app.Route("GET", "/users", (*UserController).GetUser)
app.Route("POST", "/users", (*UserController).CreateUser)
}// 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
// ✅ アノテーションなし
type UserService struct {
repo *UserRepository
}
func NewUserService(repo *UserRepository) *UserService {
return &UserService{repo: repo}
}// repository.go
// ✅ アノテーションなし
type UserRepository struct {
db *bun.DB
}
func NewUserRepository(db *bun.DB) *UserRepository {
return &UserRepository{db: db}
}