spine.App
Appは、コンストラクタ、HTTPルート、インターセプター、イベントコンシューマー、WebSocketハンドラー、ユーザー定義のトランスポートを登録し、アプリケーションを実行するためのエントリーポイントです。このリファレンスでは、Spine v0.5.1の公開APIと起動オプションを扱います。
import "github.com/NARUBROWN/spine"インターフェース定義
type App interface {
// 생성자 선언
Constructor(constructors ...any)
// 라우트 선언
Route(method string, path string, handler any, opts ...router.RouteOption)
// 인터셉터 선언
Interceptor(interceptors ...core.Interceptor)
// HTTP/WebSocket 범위를 지정한 전역 인터셉터 선언
InterceptorFor(scope boot.InterceptorScope, interceptors ...core.Interceptor)
// HTTP 서버 확장 (Echo 등)
Transport(fn func(any))
// 독립 실행되는 사용자 정의 전송 방식 등록
RegisterTransport(t core.CustomTransport)
// 네트워크 연결 없이 설정 검증
Validate(opts boot.Options) error
// 실행
Run(opts boot.Options) error
// 이벤트 소비자 레지스트리 반환
Consumers() *consumer.Registry
// 웹소켓 레지스트리 반환
WebSocket() *ws.Registry
}Routeのオプションは、アプリのコードからpkg/routeの関数で渡します。戻り値の型が内部パッケージにあるConsumers()とWebSocket()も、型を直接宣言せずにメソッドを続けて呼び出せます。
コンストラクタ
New
func New() App新しいSpineアプリケーションのインスタンスを作成します。
戻り値
App- アプリケーションのインスタンス
例
app := spine.New()
app.Run(boot.Options{
Address: ":8080",
HTTP: &boot.HTTPOptions{},
})メソッド
Constructor
Constructor(constructors ...any)依存性注入コンテナにコンストラクタ関数を登録します。コンストラクタの引数の型に応じて、登録済みのほかのオブジェクトを注入します。
引数
constructors- コンストラクタ関数(可変長引数)
コンストラクタの規則
- 関数である必要があります
- 戻り値は正確に1つである必要があります
- 引数の型を提供するコンストラクタも登録する必要があります
例
// 의존성 없는 생성자
func NewUserRepository() *UserRepository {
return &UserRepository{}
}
// 의존성 있는 생성자
func NewUserController(repo *UserRepository) *UserController {
return &UserController{repo: repo}
}
// 이벤트 소비자 생성자
func NewOrderConsumer() *OrderConsumer {
return &OrderConsumer{}
}
app.Constructor(
NewUserRepository,
NewUserController,
NewOrderConsumer,
)Route
Route(method string, path string, handler any, opts ...router.RouteOption)HTTPルートを登録します。methodの前後の空白を取り除き、大文字に変換します。
引数
method- HTTPメソッド("GET"、"POST"、"PUT"、"DELETE"など)。大文字と小文字は区別しませんpath- URLパスのパターン。:param形式でパスパラメータを定義しますhandler- コントローラーのメソッド式opts- ルートオプション(省略可能)
パスのパターン
/users- 静的パス/users/:id- 単一のパラメータ/users/:userId/posts/:postId- 複数のパラメータ
例
// 기본 라우트
app.Route("GET", "/users", (*UserController).List)
app.Route("GET", "/users/:id", (*UserController).GetUser)
app.Route("POST", "/users", (*UserController).CreateUser)
app.Route("PUT", "/users/:id", (*UserController).UpdateUser)
app.Route("DELETE", "/users/:id", (*UserController).DeleteUser)
// 중첩 경로
app.Route("GET", "/users/:userId/posts/:postId", (*PostController).GetPost)ルートオプション
route.WithInterceptorsで、特定のルートだけにインターセプターを適用します。
import "github.com/NARUBROWN/spine/pkg/route"
// 라우트별 인터셉터 적용
app.Route(
"GET",
"/users/:id",
(*UserController).GetUser,
route.WithInterceptors(&LoggingInterceptor{}),
)
// 타입이 있는 nil 포인터는 컨테이너에서 조회
app.Route(
"POST",
"/admin/users",
(*AdminController).CreateUser,
route.WithInterceptors((*AuthInterceptor)(nil)),
)
// 여러 인터셉터 적용
app.Route(
"POST",
"/admin/users",
(*AdminController).CreateUser,
route.WithInterceptors(
(*AuthInterceptor)(nil),
&AdminRoleInterceptor{},
),
)Interceptor
Interceptor(interceptors ...core.Interceptor)HTTPリクエストとWebSocketメッセージにグローバルインターセプターを登録します。app.Interceptor(...)はapp.InterceptorFor(boot.InterceptorAll, ...)と同じです。登録順にPreHandleを実行し、逆順にPostHandle、BeforeResponse、AfterCompletionを実行します。
同じポインターのインスタンスを複数のスコープに登録すると、スコープをまとめて1回実行します。同じ型でも、異なるインスタンスはそれぞれ実行します。(*AuthInterceptor)(nil)のような型付きnilポインターを登録すると、コンテナから共有インスタンスを取得して使用します。
引数
interceptors: インターセプターのインスタンスの一覧
実行順序
- グローバルインターセプターの
PreHandleを登録順に実行します。 - ルーティング後に入力値を解釈します。
- ルートインターセプターの
PreHandleを登録順に実行します。 - コントローラーを実行してレスポンスを準備した後、実行後フックを呼び出します。
- ルートインターセプター、グローバルインターセプターの順に
PostHandleを実行します。それぞれ登録の逆順です。 - 同じ逆順で
BeforeResponseを実行した後、実際のレスポンスを書き込みます。 - レスポンス処理後、同じ逆順で
AfterCompletionを実行します。
エラーや処理中断時の動作は、インターセプターリファレンスを参照してください。
例
app.Interceptor(
cors.New(cors.Config{
AllowOrigins: []string{"*"},
AllowMethods: []string{"GET", "POST", "OPTIONS"},
AllowHeaders: []string{"Content-Type"},
}),
&LoggingInterceptor{},
)InterceptorFor
InterceptorFor(scope boot.InterceptorScope, interceptors ...core.Interceptor)グローバルインターセプターを適用するトランスポートを選択します。イベントコンシューマーには適用しません。
| スコープ | 適用対象 |
|---|---|
boot.InterceptorHTTP | HTTPリクエスト |
boot.InterceptorWebSocket | WebSocketメッセージと、サポートされる接続前の処理 |
boot.InterceptorAll | 両方のスコープ |
app.InterceptorFor(boot.InterceptorHTTP, corsInterceptor)
app.InterceptorFor(boot.InterceptorWebSocket, wsAuthInterceptor)
app.InterceptorFor(boot.InterceptorAll, loggingInterceptor)Transport
Transport(fn func(any))HTTPサーバーのEchoインスタンスを設定するコールバックを登録します。コールバックでミドルウェアや静的ファイルのパスを追加できます。
引数
fn- Echoインスタンスを受け取るコールバック関数
例
import "github.com/labstack/echo/v4"
import "github.com/labstack/echo/v4/middleware"
app.Transport(func(e any) {
echo := e.(*echo.Echo)
// Echo 미들웨어 추가
echo.Use(middleware.RequestID())
// 정적 파일 서빙
echo.Static("/static", "public")
})RegisterTransport
RegisterTransport(t core.CustomTransport)HTTPパイプラインと独立して実行するトランスポートを登録します。たとえば、gRPCサーバーをSpineの依存性注入と起動および終了処理に接続するときに使用します。
引数
t-core.CustomTransportインターフェースの実装
CustomTransportインターフェース
// core/transport.go
type CustomTransport interface {
// Init은 DI 컨테이너 준비 이후 호출됩니다.
Init(container Container) error
// Start는 Init 이후 별도 고루틴에서 호출됩니다.
Start() error
// Stop은 정상 종료 시 호출됩니다.
Stop(ctx context.Context) error
}
type Container interface {
Resolve(t reflect.Type) (any, error)
}例
type GRPCTransport struct {
server *grpc.Server
}
func (t *GRPCTransport) Init(container core.Container) error {
// 컨테이너에서 서비스 조회
svc, err := container.Resolve(reflect.TypeOf((*MyService)(nil)))
if err != nil {
return err
}
t.server = grpc.NewServer()
RegisterMyServiceServer(t.server, svc.(*MyService))
return nil
}
func (t *GRPCTransport) Start() error {
lis, err := net.Listen("tcp", ":9090")
if err != nil {
return err
}
return t.server.Serve(lis)
}
func (t *GRPCTransport) Stop(ctx context.Context) error {
t.server.GracefulStop()
return nil
}
app.RegisterTransport(&GRPCTransport{})Consumers
Consumers() *consumer.Registryイベントコンシューマーを登録するためのレジストリを返します。KafkaやRabbitMQから受信するイベント名とハンドラーを登録します。コンシューマーのコンストラクタもConstructorで登録する必要があります。
戻り値
*consumer.Registry- コンシューマーレジストリ
例
// 이벤트 소비자 등록
app.Consumers().Register(
"order.created", // 토픽/이벤트 이름
(*OrderConsumer).OnCreated, // 핸들러 메서드
)
app.Consumers().Register(
"stock.created",
(*StockConsumer).OnCreated,
)イベントハンドラー
イベントハンドラーは、標準コンテキスト、イベント名、イベントDTOを引数として受け取れます。
type OrderConsumer struct{}
func NewOrderConsumer() *OrderConsumer {
return &OrderConsumer{}
}
// 이벤트 핸들러
func (c *OrderConsumer) OnCreated(
ctx context.Context,
eventName string,
event OrderCreated,
) error {
log.Println("이벤트 수신:", eventName)
log.Println("주문 ID:", event.OrderID)
return nil
}
// 이벤트 DTO
type OrderCreated struct {
OrderID int64 `json:"order_id"`
At time.Time `json:"at"`
}WebSocket
WebSocket() *ws.RegistryWebSocketレジストリを返します。WebSocketのパスとハンドラーを登録します。
戻り値
*ws.Registry- WebSocketレジストリ
例
if err := app.WebSocket().Register("/ws/chat", (*ChatController).OnMessage); err != nil {
log.Fatal(err)
}WebSocketハンドラー
WebSocketハンドラーは、wsパッケージの接続IDとメッセージDTOを引数として受け取ります。次の例では接続ごとの送信オブジェクトを保存し、メッセージをすべての接続に送信します。ChatControllerのコンストラクタはConstructorで登録します。
import "github.com/NARUBROWN/spine/pkg/ws"
type ChatController struct {
mu sync.RWMutex
clients map[string]ws.Sender
}
func NewChatController() *ChatController {
return &ChatController{clients: make(map[string]ws.Sender)}
}
type ChatMessage struct {
Message string `json:"message"`
}
type ChatEvent struct {
Type string `json:"type"`
From string `json:"from"`
Message string `json:"message"`
At string `json:"at"`
}
func (c *ChatController) OnMessage(
ctx context.Context,
connID ws.ConnectionID,
msg ChatMessage,
) error {
sender, ok := ctx.Value(ws.SenderKey).(ws.Sender)
if ok && sender != nil {
c.mu.Lock()
c.clients[connID.Value] = sender
c.mu.Unlock()
}
message := strings.TrimSpace(msg.Message)
if message == "" {
return nil
}
payload, err := json.Marshal(ChatEvent{
Type: "message",
From: connID.Value,
Message: message,
At: time.Now().UTC().Format(time.RFC3339),
})
if err != nil {
return err
}
c.mu.RLock()
clients := make(map[string]ws.Sender, len(c.clients))
for id, client := range c.clients {
clients[id] = client
}
c.mu.RUnlock()
var firstErr error
for id, client := range clients {
if err := client.Send(ws.TextMessage, payload); err != nil {
if firstErr == nil {
firstErr = err
}
c.mu.Lock()
delete(c.clients, id)
c.mu.Unlock()
}
}
return firstErr
}WebSocketはHTTPサーバーと同じEchoインスタンスにパスを登録するため、boot.Options.HTTPが必要です。オリジン、接続数、認証の設定は、セキュリティ設定を参照してください。
Validate
Validate(opts boot.Options) errorネットワーク接続を開かず、サーバーやコンシューマーを起動せずに起動オプションを検証します。KafkaとRabbitMQの接続設定、HTTPとWebSocketの制限値、グローバルインターセプターのnilの有無とスコープなどを確認します。Runも起動前に同じ検証を行います。
エラーがある場合は*boot.ConfigErrorを返します。Issuesの各項目には、設定の位置を示すPath、エラー分類を示すCode、説明のMessage、修正方法を示すHintがあります。有効なオプションの場合はnilです。
Validateはコンストラクタの依存関係を生成せず、ブローカーにも接続しません。コンストラクタとルートの適合性、DI構成、実際のインフラへの接続まで成功したとは判断できません。
options := boot.Options{Address: ":8080", HTTP: &boot.HTTPOptions{}}
if err := app.Validate(options); err != nil {
log.Fatal(err)
}
if err := app.Run(options); err != nil {
log.Fatal(err)
}Run
Run(opts boot.Options) error登録した構成とboot.Optionsに従い、HTTPサーバー、WebSocket、イベントコンシューマー、ユーザー定義のトランスポートを起動します。実行中は終了シグナルまたはランタイムエラーを待機します。設定、初期化、実行、終了に失敗すると、エラーを返します。
if err := app.Run(boot.Options{
Address: ":8080",
HTTP: &boot.HTTPOptions{},
}); err != nil {
log.Fatal(err)
}boot.Options
サーバーの実行と外部インフラの使用有無を指定します。HTTP、Kafka、RabbitMQがnilの場合、その機能を構成しません。
import "github.com/NARUBROWN/spine/pkg/boot"構造体定義
type Options struct {
Address string
EnableGracefulShutdown bool
ShutdownTimeout time.Duration
Kafka *KafkaOptions
RabbitMQ *RabbitMqOptions
HTTP *HTTPOptions
}
type HTTPOptions struct {
GlobalPrefix string
DisableRecover bool
ReadHeaderTimeout time.Duration
ReadTimeout time.Duration
WriteTimeout time.Duration
IdleTimeout time.Duration
MaxHeaderBytes int
MaxBodyBytes int64
WebSocket WebSocketOptions
}Optionsフィールド | 意味とデフォルトの動作 |
|---|---|
Address | HTTPサーバーがリッスンするアドレス。例: ":8080" |
EnableGracefulShutdown | trueの場合、HTTPサーバーでSIGINT、SIGTERMを受け取り、正常終了します。デフォルトはfalse |
ShutdownTimeout | HTTPとユーザー定義のトランスポートの終了時に使用する待機時間。0の場合は10秒。負の値は指定できません |
Kafka | Kafkaの発行と消費の設定。nilの場合は無効 |
RabbitMQ | RabbitMQの発行と消費の設定。nilの場合は無効 |
HTTP | HTTPとWebSocketの設定。nilの場合はHTTPサーバーが無効 |
HTTPOptionsフィールド | 0または省略時 | 制約 |
|---|---|---|
GlobalPrefix | プレフィックスなし | 以下のパス規則を適用 |
DisableRecover | false。panicをHTTP 500に変換するリカバリーミドルウェアを使用 | trueの場合はミドルウェアを無効化 |
ReadHeaderTimeout | 5秒 | 負の値は指定不可 |
ReadTimeout | 30秒 | 負の値は指定不可 |
WriteTimeout | 30秒 | 負の値は指定不可 |
IdleTimeout | 120秒 | 負の値は指定不可 |
MaxHeaderBytes | 1 MiB | 負の値は指定不可 |
MaxBodyBytes | 32 MiB | 負の値の場合は本文サイズの制限を無効化 |
WebSocket | WebSocketのデフォルト値 | boot.WebSocketOptions |
GlobalPrefixの検証規則
ValidateとRunは、次の規則に従わない値をHTTP_GLOBAL_PREFIX_INVALID設定エラーとして返します。空文字列の場合はプレフィックスを適用しません。
"/"で始まる必要があります":"(パスパラメータ)を含めることはできません"*"(ワイルドカード)を含めることはできません- 末尾の
"/"は自動で取り除かれます
// 유효한 접두사
HTTP: &boot.HTTPOptions{GlobalPrefix: "/api/v1"}
HTTP: &boot.HTTPOptions{GlobalPrefix: "/v2"}
// Validate와 Run이 설정 오류 반환
HTTP: &boot.HTTPOptions{GlobalPrefix: "api"} // '/'로 시작하지 않음
HTTP: &boot.HTTPOptions{GlobalPrefix: "/api/:ver"} // 경로 매개변수 포함
HTTP: &boot.HTTPOptions{GlobalPrefix: "/api/*"} // 와일드카드 포함基本的な使用方法
app.Run(boot.Options{
Address: ":8080",
HTTP: &boot.HTTPOptions{},
})正常終了
app.Run(boot.Options{
Address: ":8080",
EnableGracefulShutdown: true,
ShutdownTimeout: 10 * time.Second,
HTTP: &boot.HTTPOptions{
GlobalPrefix: "/api/v1",
},
})HTTPの正常終了を有効にすると、SIGINT、SIGTERMを受け取って新しいリクエストの受け入れを停止し、処理中のリクエストを待機します。WebSocket接続を閉じ、イベントコンシューマーを停止した後、ユーザー定義のトランスポートのStop(ctx)を呼び出します。
ShutdownTimeoutは、HTTPとユーザー定義のトランスポートの終了コンテキストに適用します。コンシューマーのStopは、処理、ACK/NACK、リーダーが終了するまで待機するため、この値をプロセス全体の強制終了期限と解釈しないでください。HTTPを使用せず、コンシューマーやユーザー定義のトランスポートだけを実行する場合も終了シグナルを処理します。
Recoverミドルウェア
デフォルトでは、panicをHTTP 500レスポンスに変換するリカバリーミドルウェアが有効です。
// Recover 비활성화
HTTP: &boot.HTTPOptions{
DisableRecover: true,
}Kafka設定
KafkaOptions
ReadとWriteは独立しています。いずれかを有効にするとBrokersが必要になり、Readを使用する場合はGroupIDも必要です。個別のトランスポート設定がない場合、TLS 1.2以上を適用します。
type KafkaOptions struct {
// Kafka 브로커 주소 목록
Brokers []string
// 사용자 정의 TLS, 리더 Dialer, 라이터 Transport
TLS *tls.Config
Dialer *kafka.Dialer
Transport *kafka.Transport
// 격리된 로컬 환경의 평문 연결 명시적 허용
AllowInsecureTransport bool
// 리더 오류와 ACK/NACK 실패 뒤 재연결 정책
ConsumerRetry ConsumerRetryOptions
// 이벤트 소비 설정
// nil이면 Kafka 소비자를 활성화하지 않음
Read *KafkaReadOptions
// 이벤트 발행 설정
// nil이면 Kafka로 이벤트를 발행하지 않음
Write *KafkaWriteOptions
}
type KafkaReadOptions struct {
// Kafka 소비자 그룹 ID
GroupID string
}
type KafkaWriteOptions struct {
// 이벤트 이름 앞에 붙일 토픽 접두사
TopicPrefix string
}例
app.Run(boot.Options{
Address: ":8080",
Kafka: &boot.KafkaOptions{
Brokers: []string{"localhost:9092"},
AllowInsecureTransport: true, // 격리된 로컬 개발 환경 전용
Read: &boot.KafkaReadOptions{
GroupID: "my-consumer-group",
},
Write: &boot.KafkaWriteOptions{
TopicPrefix: "myapp.",
},
},
HTTP: &boot.HTTPOptions{},
})RabbitMQ設定
RabbitMqOptions
ReadとWriteは独立しています。有効にした役割ごとにExchangeを指定します。デフォルトではamqps:// URLが必須です。平文のamqp://は、隔離された開発環境だけで明示的に許可します。
type RabbitMqOptions struct {
// RabbitMQ AMQP 연결 문자열
// 예: amqp://guest:guest@localhost:5672/
URL string
// 로컬 amqp:// 연결 명시적 허용
AllowInsecureTransport bool
ConsumerRetry ConsumerRetryOptions
PublisherRetry PublisherRetryOptions
// 이벤트 소비 설정
// nil이면 RabbitMQ 소비자를 활성화하지 않음
Read *RabbitMqReadOptions
// 이벤트 발행 설정
// nil이면 RabbitMQ로 이벤트를 발행하지 않음
Write *RabbitMqWriteOptions
}
type RabbitMqReadOptions struct {
// 큐를 바인딩할 교환기 이름
Exchange string
PrefetchCount int
FailurePolicy RabbitMqFailurePolicy
DeadLetter *RabbitMqDeadLetterOptions
// Deprecated: FailurePolicy 사용 권장
RequeueOnError bool
}
type RabbitMqWriteOptions struct {
// 이벤트를 발행할 교환기 이름
Exchange string
}失敗ポリシーと再試行のデフォルト値は、セキュリティ設定を参照してください。RequeueOnErrorは以前のバージョンとの互換性のための設定です。新しいコードではFailurePolicyを使用します。
例
app.Run(boot.Options{
Address: ":8080",
RabbitMQ: &boot.RabbitMqOptions{
URL: "amqp://guest:guest@localhost:5672/",
AllowInsecureTransport: true, // 격리된 로컬 개발 환경 전용
Read: &boot.RabbitMqReadOptions{
Exchange: "stock-exchange",
},
Write: &boot.RabbitMqWriteOptions{
Exchange: "stock-exchange",
},
},
HTTP: &boot.HTTPOptions{},
})イベント発行
コントローラーでドメインイベントを収集し、登録済みのKafkaやRabbitMQのパブリッシャーに送信できます。
DomainEventインターフェース
import "github.com/NARUBROWN/spine/pkg/event/publish"
type DomainEvent interface {
Name() string
OccurredAt() time.Time
}イベントの定義
type OrderCreated struct {
OrderID int64 `json:"order_id"`
At time.Time `json:"at"`
}
func (e OrderCreated) Name() string {
return "order.created"
}
func (e OrderCreated) OccurredAt() time.Time {
return e.At
}コントローラーから発行
import "github.com/NARUBROWN/spine/pkg/event/publish"
func (c *OrderController) Create(ctx context.Context, req *CreateOrderRequest) httpx.Response[Order] {
order := c.repo.Save(req)
// 이벤트 발행
publish.Event(ctx, OrderCreated{
OrderID: order.ID,
At: time.Now(),
})
return httpx.Response[Order]{Body: order}
}publish.Event()は、context.Contextに接続されたイベントバスにイベントを収集します。コントローラーの実行とレスポンスの準備が成功すると、実行後フックで登録済みのKafkaまたはRabbitMQのパブリッシャーにまとめて送信します。この送信はBeforeResponseより前に実行されるため、DBトランザクションのコミットと原子的にまとめられるわけではありません。原子的な処理が必要な場合は、トランザクショナルアウトボックスを構成してください。
CLIプロジェクトでの使用
最初のアプリを作成するで生成したプロジェクトでは、internal/application/application.goのBuildApplicationでアプリを構成し、ルートのmain.goでValidateのエラーを確認した後にRunを呼び出します。次のコマンドでプロジェクトを確認できます。
spine doctor
spine contract check
spine verify生成されるBuildApplicationの基本形は次のとおりです。
package application
import (
"os"
"github.com/NARUBROWN/spine"
"github.com/NARUBROWN/spine/pkg/boot"
"github.com/NARUBROWN/spine/pkg/httpx"
)
type HealthController struct{}
func NewHealthController() *HealthController { return &HealthController{} }
func (c *HealthController) Get() httpx.Response[map[string]string] {
return httpx.Response[map[string]string]{Body: map[string]string{"status": "ok"}}
}
// BuildApplication은 서버 실행, 계약 검사와 오프라인 검증이 함께 사용하는 앱 구성 함수입니다.
func BuildApplication() (spine.App, boot.Options, error) {
app := spine.New()
app.Constructor(NewHealthController)
app.Route("GET", "/health", (*HealthController).Get)
address := ":8080"
if port := os.Getenv("SPINE_PORT"); port != "" {
address = ":" + port
}
return app, boot.Options{Address: address, HTTP: &boot.HTTPOptions{}}, nil
}起動と終了の順序
Runはオプションの事前検証後、依存性注入コンテナとイベントパブリッシャーを構成します。ユーザー定義のトランスポートのInitを呼び出し、HTTPとWebSocketのルートおよびインターセプターを解釈して、必要なコントローラーを事前に生成します。登録済みのコンシューマーがある場合は、ブローカーのランタイムも検証します。
この準備が終わると、コンシューマーとユーザー定義のトランスポートのStartを別のゴルーチンで実行し、最後にHTTPサーバーを起動します。HTTPルートは、同じメソッドでパスが曖昧に重なると起動に失敗します。たとえば、/users/:idと/users/meは重複するパスとして検出します。
終了時は、WebSocketとHTTPへのリクエストの受け入れを先に停止し、コンシューマーの停止を待ってから、ユーザー定義のトランスポートのStopを初期化の逆順に呼び出します。その後、イベントパブリッシャーのリソースを解放します。具体的な実装は、v0.5.1の起動および終了コードを参照してください。
制約とエラー
- コンストラクタの戻り値は正確に1つである必要があります。
(T, error)を返すコンストラクタは登録できません。 - HTTP入力DTOはポインターで受け取り、成功レスポンスは
httpx.Response[T]など、サポートするレスポンス型で返します。コントローラーの書き方を参照してください。 Validateが成功しても、Runでコンストラクタ、依存関係、ルート、ブローカー接続のエラーが発生する場合があります。両方のメソッドの戻り値のエラーを確認してください。- WebSocketのパスを登録して
HTTPを省略すると、WEBSOCKET_HTTP_REQUIRED設定エラーが発生します。 InterceptorForのスコープには、InterceptorHTTP、InterceptorWebSocket、InterceptorAllのいずれかを使用します。0やサポートされていないビットが含まれる場合は、INTERCEPTOR_SCOPE_INVALID設定エラーが発生します。- ネットワーク送信、イベント発行、DBコミットは、1つの原子的な操作ではありません。再試行や重複処理への対応が必要かどうかは、アプリで判断する必要があります。
