Documentation
¶
Index ¶
- Variables
- type Cache
- type Coder
- type ControllerConfig
- type Database
- type DatabaseOption
- type DistributedCache
- type ESDocumenter
- type Event
- type Initializer
- type Logger
- type Model
- type Module
- type QueryConfig
- type RBAC
- type Request
- type Response
- type SQLStatement
- type SSEBuilder
- type Service
- type ServiceContext
- func (sc *ServiceContext) ClientIP() string
- func (sc *ServiceContext) Cookie(name string) (string, error)
- func (sc *ServiceContext) Data(code int, contentType string, data []byte)
- func (sc *ServiceContext) Deadline() (time.Time, bool)
- func (sc *ServiceContext) Done() <-chan struct{}
- func (sc *ServiceContext) Encode(w io.Writer, event Event) error
- func (sc *ServiceContext) Err() error
- func (sc *ServiceContext) FormFile(name string) (*multipart.FileHeader, error)
- func (sc *ServiceContext) Host() string
- func (sc *ServiceContext) IsHTTPS() bool
- func (sc *ServiceContext) Method() string
- func (sc *ServiceContext) Param(key string) string
- func (sc *ServiceContext) Params() map[string]string
- func (sc *ServiceContext) Path() string
- func (sc *ServiceContext) Phase() consts.Phase
- func (sc *ServiceContext) PostForm(key string) string
- func (sc *ServiceContext) Query() url.Values
- func (sc *ServiceContext) RequiresAuth() bool
- func (sc *ServiceContext) Route() string
- func (sc *ServiceContext) SSE() *SSEBuilder
- func (sc *ServiceContext) SessionID() string
- func (sc *ServiceContext) SetCookie(cookie *http.Cookie)
- func (sc *ServiceContext) TenantID() string
- func (sc *ServiceContext) TraceID() string
- func (sc *ServiceContext) UserAgent() string
- func (sc *ServiceContext) UserID() string
- func (sc *ServiceContext) Username() string
- func (sc *ServiceContext) Value(key any) any
- type StandardLogger
- type StructuredLogger
- type ZapLogger
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrEntryNotFound = errors.New("cache entry not found")
ErrEntryNotFound is returned when a cache entry is not found.
Functions ¶
This section is empty.
Types ¶
type Cache ¶
type Cache[T any] interface { // Get retrieves a value from the cache by key. // Returns ErrEntryNotFound if the key does not exist. Get(key string) (T, error) // Peek retrieves a value from the cache by key without affecting its position or access time. // Returns ErrEntryNotFound if the key does not exist. Peek(key string) (T, error) // Set stores a value in the cache with the specified TTL. // A zero TTL means the entry will not expire. Set(key string, value T, ttl time.Duration) error // Delete removes a key from the cache. // Returns ErrEntryNotFound if the key does not exist. Delete(key string) error // Exists checks if a key exists in the cache. // Returns true if the key exists, false otherwise. Exists(key string) bool // Len returns the number of entries currently stored in the cache. Len() int // Clear removes all entries from the cache. Clear() // WithContext returns a cache handle that uses ctx for tracing or cancellation propagation. // // Implementations may return a new handle or mutate and return the receiver. // Callers must not assume the returned handle is independent unless a concrete // provider documents that stronger guarantee. WithContext(ctx context.Context) Cache[T] }
Cache provides a typed key/value cache abstraction with TTL and context propagation.
Type Parameters:
- T: Cached value type
Error Handling:
- Get/Peek return ErrEntryNotFound when key doesn't exist
- Set/Delete return backend errors when storage operations fail
type ControllerConfig ¶
type ControllerConfig[M Model] struct { // DB overrides the database handle used by the route. Only *gorm.DB is supported. DB any // TableName overrides the model table name used by the route. TableName string // ParamName names the route parameter that carries the resource ID. ParamName string }
ControllerConfig customizes how router.Register builds an internal handler for a route. It is the public configuration surface for controller behavior; the concrete controller handlers and their runtime state remain framework-owned.
type Database ¶
type Database[M Model] interface { // Create inserts one or more records, setting framework IDs and timestamps unless WithDryRun is enabled. Create(objs ...M) error // Delete removes one or more records using WithPurge, the model Purge setting, or soft delete by default. Delete(objs ...M) error // Update saves one or more full model values and updates timestamps unless WithDryRun is enabled. Update(objs ...M) error // UpdateByID updates a single field of a record by its ID. UpdateByID(id string, key string, value any) error // List retrieves multiple records matching the query conditions. List(dest *[]M) error // Get retrieves a single record by its ID. // The destination must be a non-nil pointer matching M. When M is *T, // both &value and new(T) are valid destinations; a nil *T returns ErrNilDest. // Get returns database.ErrRecordNotFound when no matching record exists. Get(dest M, id string) error // First retrieves the first record matching the current query conditions. First(dest M) error // Last retrieves the last record matching the current query conditions. Last(dest M) error // Take retrieves the first record in no specified order. Take(dest M) error // Count returns the total number of records matching the query conditions. Count(*int64) error // Cleanup permanently deletes all soft-deleted records; WithDryRun only builds the cleanup SQL. Cleanup() error // Health checks database connectivity and is not disabled by WithDryRun. Health() error // Transaction executes fn in a transaction for this model and passes a transaction-bound Database. Transaction(fn func(txDB Database[M]) error) error // TransactionFunc executes fn in a transaction for multi-model work; each Database used inside fn must call WithTx(tx). // WithTx also seeds the returned operation chain's context, so model hooks that receive that context and call // database.Database[*OtherModel](ctx) keep using the same transaction. TransactionFunc(fn func(tx any) error) error DatabaseOption[M] }
Database defines the model-scoped database operation contract. It provides CRUD operations, query builders, transactions, cleanup, health checks, and optional cache/dry-run behavior for a single Model type.
Type Parameters:
- M: Model type that implements Model interface
The interface embeds DatabaseOption[M] to provide chainable query building. A chain is expected to end with one terminal operation, such as Create, List, Get, Count, Cleanup, Health, Transaction, or TransactionFunc.
Implementations share an underlying GORM session. Call database.Database[M](ctx) again for each independent operation chain. Keeping the returned value in a variable and running another independent operation on it (for example, List then Get or Update) is incorrect usage; see database.Database.
type DatabaseOption ¶
type DatabaseOption[M Model] interface { // WithDB uses a custom *gorm.DB; callers must migrate custom schemas explicitly. WithDB(any) Database[M] // WithTx binds operations to a *gorm.DB transaction, primarily inside TransactionFunc. // It also stores the transaction in the operation context so model hooks can pass ctx to Database[*OtherModel](ctx) // without manually threading the raw transaction through hook signatures. WithTx(tx any) Database[M] // WithTable sets a custom table name; the table must already exist. WithTable(name string) Database[M] // WithDebug enables debug mode to show detailed SQL queries. WithDebug() Database[M] // WithQuery adds query conditions from model fields or raw SQL configuration. WithQuery(query M, config ...QueryConfig) Database[M] // WithCursor enables cursor-based pagination for List operations. WithCursor(string, bool, ...string) Database[M] // WithTimeRange applies a time range filter to the query. WithTimeRange(columnName string, startTime time.Time, endTime time.Time) Database[M] // WithSelect specifies fields for SELECT and Update column selection where supported. WithSelect(columns ...string) Database[M] // WithIndex specifies database index hints for query optimization (MySQL only). WithIndex(indexName string, hint ...consts.IndexHintMode) Database[M] // WithRollback configures a callback that runs when Transaction or TransactionFunc rolls back. WithRollback(rollbackFunc func()) Database[M] // WithLock adds row-level locking to SELECT queries (must be used within a transaction). WithLock(mode ...consts.LockMode) Database[M] // WithBatchSize sets the batch size for Create, Update, and Delete. WithBatchSize(size int) Database[M] // WithPagination applies pagination parameters (page, size) to the query. WithPagination(page, size int) Database[M] // WithLimit restricts the number of returned records for read operations. WithLimit(limit int) Database[M] // WithOffset skips records before returning read operation results. WithOffset(offset int) Database[M] // WithExclude excludes records matching specified conditions. WithExclude(map[string][]any) Database[M] // WithOrder adds ORDER BY clause to sort query results. WithOrder(order string) Database[M] // WithExpand enables eager loading of specified associations. WithExpand(expand []string, order ...string) Database[M] // WithPurge controls whether Delete permanently removes records instead of soft deleting them. WithPurge(...bool) Database[M] // WithCache enables cache reads/writes for supported read operations and cache invalidation for writes. WithCache(...bool) Database[M] // WithOmit excludes specified fields from INSERT, UPDATE, and SELECT operations. WithOmit(...string) Database[M] // WithBuildSQL builds SQL for the next terminal operation and appends Query, Args, and RenderedSQL to the collector. WithBuildSQL(statements *[]SQLStatement) Database[M] // WithDryRun builds SQL without database I/O, framework hooks, cache mutation, or object field filling. WithDryRun() Database[M] // WithoutHook disables model hooks for the operation. WithoutHook() Database[M] }
DatabaseOption provides chainable options for a single Database operation chain. Options apply to the next terminal operation and are reset afterward. Start a new chain with database.Database[M](ctx) for each independent operation.
type DistributedCache ¶
type DistributedCache[T any] interface { Cache[T] // SetWithSync stores a value in both local and distributed cache with synchronization. SetWithSync(key string, value T, localTTL time.Duration, remoteTTL time.Duration) error // GetWithSync retrieves a value from local cache first, then from distributed cache if not found. GetWithSync(key string, localTTL time.Duration) (T, error) // DeleteWithSync removes a value from both local and distributed cache with synchronization. DeleteWithSync(key string) error }
DistributedCache extends Cache with explicit local-plus-remote synchronization helpers.
Type Parameters:
- T: Cached value type
type ESDocumenter ¶
type ESDocumenter interface {
// Document returns a map representing an Elasticsearch document.
// The returned map should contain all fields to be indexed, where:
// - keys are field names (string type)
// - values are field values (any type)
//
// Implementation notes:
// 1. The returned map should only contain JSON-serializable values.
// 2. Field names should match those defined in the Elasticsearch mapping.
// 3. Complex types (like nested objects or arrays) should be correctly
// represented in the returned map.
//
// Example:
// return map[string]any{
// "id": "1234",
// "title": "Sample Document",
// "tags": []string{"tag1", "tag2"},
// }
Document() map[string]any
// GetID returns a string that uniquely identifies the document.
// This ID is typically used as the Elasticsearch document ID.
//
// Implementation notes:
// 1. The ID should be unique within the index.
// 2. If no custom ID is needed, consider returning an empty string
// to let Elasticsearch auto-generate an ID.
// 3. The ID should be a string, even if it's originally a numeric value.
//
// Example:
// return "user_12345"
GetID() string
}
ESDocumenter represents a document that can be indexed into Elasticsearch. Types implementing this interface should be able to convert themselves into a document format suitable for Elasticsearch indexing.
type Event ¶
Event is an alias for sse.Event. This allows users to use types.Event instead of importing internal/sse directly.
type Initializer ¶
type Initializer interface {
Init() error
}
Initializer defines a bootstrap component that performs one-time setup. Implementations should return an error when required configuration, connections, or runtime resources cannot be initialized.
type Logger ¶
type Logger interface {
With(fields ...string) Logger
WithObject(name string, obj zapcore.ObjectMarshaler) Logger
WithArray(name string, arr zapcore.ArrayMarshaler) Logger
WithContext(context.Context, consts.Phase) Logger
StandardLogger
StructuredLogger
ZapLogger
}
Logger combines plain, sugared structured, and typed zap logging methods. With attaches string key/value fields. WithObject, WithArray, and the context helpers return derived loggers with additional structured fields.
type Model ¶
type Model interface {
GetTableName() string // GetTableName returns the table name.
GetID() string
SetID(id ...string) // SetID method will automatically set the id if id is empty.
ClearID() // ClearID always set the id to empty.
GetCreatedBy() string
GetUpdatedBy() string
GetCreatedAt() time.Time
GetUpdatedAt() time.Time
SetCreatedBy(string)
SetUpdatedBy(string)
SetCreatedAt(time.Time)
SetUpdatedAt(time.Time)
Expands() []string // Expands returns association paths that should be preloaded by default.
Excludes() map[string][]any
Purge() bool // Purge indicates whether to permanently delete records (hard delete). Default is false (soft delete).
MarshalLogObject(zapcore.ObjectEncoder) error // MarshalLogObject implements zap.ObjectMarshaler.
CreateBefore(context.Context) error
CreateAfter(context.Context) error
DeleteBefore(context.Context) error
DeleteAfter(context.Context) error
UpdateBefore(context.Context) error
UpdateAfter(context.Context) error
ListBefore(context.Context) error
ListAfter(context.Context) error
GetBefore(context.Context) error
GetAfter(context.Context) error
}
Model defines the framework contract for database-backed and action models. Typical database resources embed model.Base. Action-only models may use model.Empty or model.Any when they do not represent persistent rows.
Type Requirements:
- Must be a pointer to struct (e.g., *User)
- Database resources should expose an ID primary key through GetID/SetID/ClearID
- Hooks should be idempotent enough to run as part of framework CRUD phases
type Module ¶
type Module[M Model, REQ Request, RSP Response] interface { // Service returns the service instance that handles business logic for this module. Service() Service[M, REQ, RSP] // Route returns the base API path for this module's endpoints. Route() string // Pub determines whether the API endpoints are public or require authentication. Pub() bool // Param returns the URL parameter name used for resource identification. Param() string }
Module describes a registered API module: route metadata, auth exposure, resource parameter name, and the service implementation used by controllers.
Type Parameters:
- M: Model type that implements Model interface
- REQ: Request type for API operations
- RSP: Response type for API operations
Features:
- Automatic route registration
- Service layer integration
- Configurable authentication
type QueryConfig ¶
type QueryConfig struct {
FuzzyMatch bool // Enable fuzzy matching (LIKE/REGEXP). Default: false
AllowEmpty bool // Allow empty query conditions. Default: false
UseOr bool // Use OR logic to combine query conditions. Default: false (uses AND)
RawQuery string // Raw SQL query string for custom WHERE conditions
RawQueryArgs []any // Arguments for the raw SQL query parameters
}
QueryConfig configures the behavior of WithQuery method.
Fields:
FuzzyMatch: Enable fuzzy matching (LIKE/REGEXP queries). Default: false (exact match with IN clause)
Single value: Uses LIKE pattern (WHERE name LIKE '%value%')
Multiple values (comma-separated): Uses REGEXP pattern (WHERE name REGEXP '.*value1.*|.*value2.*')
Empty strings in comma-separated values are automatically skipped
REGEXP special characters are automatically escaped
Note: REGEXP may not be available in all databases (e.g., SQLite requires extension)
AllowEmpty: Allow empty query conditions to match all records. Default: false (blocked for safety)
When false: Empty queries are blocked (adds WHERE 1 = 0)
When true: Empty queries match all records (full table scan)
Empty query cases: nil, empty struct, all fields are zero values, all field values are empty strings
Critical: Use with caution, especially for Delete operations
UseOr: Use OR logic to combine query conditions. Default: false (uses AND logic)
When false: Multiple fields use AND logic (WHERE name IN ('John') AND age IN (18))
When true: Multiple fields use OR logic (WHERE name IN ('John') OR age IN (18))
First condition always uses WHERE, subsequent conditions use OR
Works with both exact match and fuzzy match
RawQuery: Raw SQL query string for custom WHERE conditions. When provided, model fields are ignored
Works even when query is nil
Supports parameterized queries with RawQueryArgs
Example: "age > ? AND status = ?"
RawQueryArgs: Arguments for the raw SQL query, used with RawQuery for parameterized queries
Can be nil or empty slice if RawQuery has no placeholders
Example: []any{18, "active"}
CRITICAL SAFETY FEATURE: Empty query conditions (all fields are zero values) are blocked by default to prevent catastrophic data loss scenarios, especially when the result is used for Delete operations.
Empty Query Examples:
- WithQuery(&User{}) → all fields are zero values
- WithQuery(&User{Name: "", Email: ""}) → all field values are empty strings
- WithQuery(&KV{Key: ""}) → happens when removed slice is empty
Usage Examples:
// Exact match (default)
WithQuery(&User{Name: "John"})
WithQuery(&User{Name: "John"}, QueryConfig{})
// Exact match with multiple values (comma-separated)
WithQuery(&User{Name: "John,Jack"}) // WHERE name IN ('John', 'Jack')
WithQuery(&User{ID: "id1,id2,id3"}) // WHERE id IN ('id1', 'id2', 'id3')
// Fuzzy match - single value (LIKE)
WithQuery(&User{Name: "John"}, QueryConfig{FuzzyMatch: true}) // WHERE name LIKE '%John%'
// Fuzzy match - multiple values (REGEXP)
WithQuery(&User{Name: "John,Jack"}, QueryConfig{FuzzyMatch: true}) // WHERE name REGEXP '.*John.*|.*Jack.*'
// Allow empty query (ListFactory with pagination)
WithQuery(&User{}, QueryConfig{AllowEmpty: true}) // Returns all records
// Fuzzy match + Allow empty
WithQuery(&User{}, QueryConfig{FuzzyMatch: true, AllowEmpty: true})
// Use OR logic to combine conditions
WithQuery(&User{Name: "John", Email: "john@example.com"}, QueryConfig{UseOr: true})
// WHERE name IN ('John') OR email IN ('john@example.com')
// OR logic with fuzzy match
WithQuery(&User{Name: "John", Email: "example"}, QueryConfig{UseOr: true, FuzzyMatch: true})
// WHERE name LIKE '%John%' OR email LIKE '%example%'
// Raw SQL query (can be combined with model fields using AND logic)
WithQuery(&User{}, QueryConfig{RawQuery: "age > ? AND status = ?", RawQueryArgs: []any{18, "active"}})
WithQuery(nil, QueryConfig{RawQuery: "created_at BETWEEN ? AND ?", RawQueryArgs: []any{startDate, endDate}})
// Raw SQL with complex conditions
WithQuery(&User{}, QueryConfig{RawQuery: "created_at BETWEEN ? AND ? OR priority IN (?)", RawQueryArgs: []any{startDate, endDate, priorities}})
// Raw SQL combined with model fields
WithQuery(&User{Name: "John"}, QueryConfig{RawQuery: "age > ?", RawQueryArgs: []any{18}}) // WHERE age > ? AND name IN ('John')
// Combined options
WithQuery(&User{Name: "John"}, QueryConfig{
FuzzyMatch: true,
UseOr: true,
AllowEmpty: false,
})
type RBAC ¶
type RBAC interface {
// Authorize reports whether subject may perform action on object inside tenant.
// Implementations should treat tenant as the authorization domain, subject as
// the authenticated identity, object as the protected route or resource, and
// action as the operation being checked, such as an HTTP method.
Authorize(tenant string, subject string, object string, action string) (bool, error)
// AddRole ensures role is available inside tenant.
// Casbin-backed implementations may create roles implicitly when policies or
// grouping rules are added, so this method can be a lifecycle hook with no
// persistent side effect.
AddRole(tenant string, role string) error
// RemoveRole removes role from tenant, including its permission policies and
// subject assignments. Callers should use this when deleting a role record so
// authorization state does not retain stale grants.
RemoveRole(tenant string, role string) error
// GrantPermission grants role access to action on object inside tenant.
// This represents one exact allow policy for a tenant-scoped role.
GrantPermission(tenant string, role string, object string, action string) error
// RevokePermission removes one exact role permission inside tenant.
// Use RevokeRolePermissions when replacing or deleting the full permission set
// for a role.
RevokePermission(tenant string, role string, object string, action string) error
// RevokeRolePermissions removes every permission policy granted to role inside
// tenant without removing the role's subject assignments.
RevokeRolePermissions(tenant string, role string) error
// AssignRole assigns subject to role inside tenant.
// This creates tenant membership for subject and makes the role's
// tenant-scoped permissions available to that subject.
AssignRole(tenant string, subject string, role string) error
// UnassignRole removes subject's assignment to role inside tenant.
// Other roles held by the same subject in the same tenant are left unchanged.
UnassignRole(tenant string, subject string, role string) error
// SubjectInTenant reports whether subject has at least one role assignment in
// tenant. It checks membership, not whether any specific route is authorized.
SubjectInTenant(tenant string, subject string) (bool, error)
// SubjectsInTenant returns subjects with at least one role assignment in
// tenant. It checks membership, not whether any specific route is authorized.
SubjectsInTenant(tenant string) ([]string, error)
// AssignSystemRole assigns subject to a system-level role outside any tenant.
// System roles are intended for cross-tenant framework privileges and should
// not be used for ordinary tenant-local authorization.
AssignSystemRole(subject string, role string) error
// UnassignSystemRole removes subject's assignment to a system-level role.
UnassignSystemRole(subject string, role string) error
// HasSystemRole reports whether subject holds a system-level role.
// This check is separate from Authorize because system roles are not scoped to
// tenant route policies.
HasSystemRole(subject string, role string) (bool, error)
}
RBAC provides tenant-scoped role, permission, and subject assignment operations. When RBAC is disabled or not initialized, the framework may provide a safe no-op implementation whose methods succeed without side effects.
RBAC Model:
- Tenant: Authorization domain for roles, permissions, and assignments
- Subject: Users or entities that need access
- Role: Named collection of permissions
- Object: Protected resources or endpoints
- Action: Operations on resources
type SQLStatement ¶
type SQLStatement struct {
// Query is the parameterized SQL with placeholders.
Query string
// Args contains the values bound to Query.
Args []any
// RenderedSQL is dialect-rendered SQL for logging, inspection, and manual debugging.
RenderedSQL string
}
SQLStatement contains a generated SQL statement in executable and rendered forms.
type SSEBuilder ¶
type SSEBuilder struct {
// contains filtered or unexported fields
}
SSEBuilder provides a fluent interface for building and sending SSE events. It supports chaining methods to configure and send SSE events or streams.
func (*SSEBuilder) Done ¶
func (b *SSEBuilder) Done() error
Done sends a [DONE] marker to indicate the end of an SSE stream. This is commonly used in AI chat completions and similar streaming APIs.
Note: This method should be called AFTER Stream() returns, if your protocol requires a [DONE] marker. Standard SSE streams do not require this marker and will naturally end when the connection closes.
Example:
ctx.SSE().Stream(func(w io.Writer) bool {
// Send data...
return true
})
// Send [DONE] marker to indicate stream completion
_ = ctx.SSE().Done()
Returns:
- error: Any error that occurred during encoding
func (*SSEBuilder) Stream ¶
func (b *SSEBuilder) Stream(fn func(io.Writer) bool)
Stream starts a Server-Sent Events stream. The provided function will be called repeatedly until it returns false. The stream will automatically stop if:
- The function returns false
- The request context is canceled (timeout, client disconnect, etc.)
- An error occurs while writing to the client
Note: This method does NOT automatically send a [DONE] marker when the stream ends. If your protocol requires a [DONE] marker (e.g., AI chat completions), you must manually call Done() after Stream() returns.
Example:
ctx.SSE().Stream(func(w io.Writer) bool {
_ = ctx.Encode(w, types.Event{Data: "chunk"})
return true // Continue streaming
})
// Send [DONE] marker if required by your protocol
_ = ctx.SSE().Done()
func (*SSEBuilder) WithInterval ¶
func (b *SSEBuilder) WithInterval(duration time.Duration) *SSEBuilder
WithInterval sets the time interval between events in a stream. This must be called before Stream() when using interval-based streaming.
Example:
ctx.SSE().WithInterval(1*time.Second).Stream(func(w io.Writer) bool {
_ = ctx.Encode(w, types.Event{Data: "chunk"})
return true
})
type Service ¶
type Service[M Model, REQ Request, RSP Response] interface { Create(*ServiceContext, REQ) (RSP, error) Delete(*ServiceContext, REQ) (RSP, error) Update(*ServiceContext, REQ) (RSP, error) Patch(*ServiceContext, REQ) (RSP, error) List(*ServiceContext, REQ) (RSP, error) Get(*ServiceContext, REQ) (RSP, error) CreateMany(*ServiceContext, REQ) (RSP, error) DeleteMany(*ServiceContext, REQ) (RSP, error) UpdateMany(*ServiceContext, REQ) (RSP, error) PatchMany(*ServiceContext, REQ) (RSP, error) CreateBefore(*ServiceContext, M) error CreateAfter(*ServiceContext, M) error DeleteBefore(*ServiceContext, M) error DeleteAfter(*ServiceContext, M) error UpdateBefore(*ServiceContext, M) error UpdateAfter(*ServiceContext, M) error PatchBefore(*ServiceContext, M) error PatchAfter(*ServiceContext, M) error ListBefore(*ServiceContext, *[]M) error ListAfter(*ServiceContext, *[]M) error GetBefore(*ServiceContext, M) error GetAfter(*ServiceContext, M) error CreateManyBefore(*ServiceContext, ...M) error CreateManyAfter(*ServiceContext, ...M) error DeleteManyBefore(*ServiceContext, ...M) error DeleteManyAfter(*ServiceContext, ...M) error UpdateManyBefore(*ServiceContext, ...M) error UpdateManyAfter(*ServiceContext, ...M) error PatchManyBefore(*ServiceContext, ...M) error PatchManyAfter(*ServiceContext, ...M) error Import(*ServiceContext, io.Reader) ([]M, error) Export(*ServiceContext, ...M) ([]byte, error) Filter(*ServiceContext, M) M FilterRaw(*ServiceContext) string Logger }
Service defines the controller-facing business operation contract for a model. Generated controllers call these methods for CRUD, batch CRUD, lifecycle hooks, import/export, filtering, and logging.
Type Parameters:
- M: Model type that implements Model interface
- REQ: Request type for the current action or resource operation
- RSP: Response type for the current action or resource operation
Custom actions should use action-specific REQ/RSP types instead of reusing types from other endpoints, even when the fields are identical.
type ServiceContext ¶
type ServiceContext struct {
// contains filtered or unexported fields
}
func NewServiceContext ¶
NewServiceContext creates ServiceContext from gin.Context. Including request details, headers, phase, and user information.
You can pass a custom context.Context to propagate span tracing. If ctx is nil, the request context is used when available.
func (*ServiceContext) ClientIP ¶
func (sc *ServiceContext) ClientIP() string
func (*ServiceContext) Data ¶
func (sc *ServiceContext) Data(code int, contentType string, data []byte)
func (*ServiceContext) Done ¶
func (sc *ServiceContext) Done() <-chan struct{}
func (*ServiceContext) Encode ¶
func (sc *ServiceContext) Encode(w io.Writer, event Event) error
Encode writes an SSE event to the given writer. This is a convenience method that wraps sse.Encode.
The event is formatted according to the SSE specification:
- Fields are written in recommended order: id, event, retry, data
- Each field is written as "field: value\n"
- Multiple data fields are concatenated (for multi-line data)
- Events are separated by a blank line (\n\n)
If Data is a complex type (map, struct, slice), it will be JSON-encoded. If Data is a primitive type, it will be converted to string. If Data is nil, no data field will be written.
Example:
err := ctx.Encode(w, types.Event{
Event: "message",
Data: "Hello",
})
Parameters:
- w: Writer to write the event to
- event: SSE event to encode
Returns:
- error: Any error that occurred during encoding
func (*ServiceContext) Err ¶
func (sc *ServiceContext) Err() error
func (*ServiceContext) FormFile ¶
func (sc *ServiceContext) FormFile(name string) (*multipart.FileHeader, error)
func (*ServiceContext) Host ¶
func (sc *ServiceContext) Host() string
func (*ServiceContext) IsHTTPS ¶
func (sc *ServiceContext) IsHTTPS() bool
func (*ServiceContext) Method ¶
func (sc *ServiceContext) Method() string
func (*ServiceContext) Param ¶
func (sc *ServiceContext) Param(key string) string
func (*ServiceContext) Params ¶
func (sc *ServiceContext) Params() map[string]string
func (*ServiceContext) Path ¶
func (sc *ServiceContext) Path() string
func (*ServiceContext) Phase ¶
func (sc *ServiceContext) Phase() consts.Phase
func (*ServiceContext) PostForm ¶
func (sc *ServiceContext) PostForm(key string) string
func (*ServiceContext) Query ¶
func (sc *ServiceContext) Query() url.Values
func (*ServiceContext) RequiresAuth ¶
func (sc *ServiceContext) RequiresAuth() bool
RequiresAuth returns whether the current API requires authentication.
func (*ServiceContext) Route ¶
func (sc *ServiceContext) Route() string
func (*ServiceContext) SSE ¶
func (sc *ServiceContext) SSE() *SSEBuilder
SSE returns a new SSE builder for chaining SSE operations. This provides a fluent interface for sending SSE events and streams.
Example usage:
// Start a stream
ctx.SSE().Stream(func(w io.Writer) bool {
_ = ctx.Encode(w, types.Event{Data: "chunk"})
return true
})
// Stream with interval
ctx.SSE().WithInterval(1*time.Second).Stream(func(w io.Writer) bool {
_ = ctx.Encode(w, types.Event{Data: "chunk"})
return true
})
// Send [DONE] marker
_ = ctx.SSE().Done()
Example (CompleteFlow) ¶
ExampleServiceContext_SSE_completeFlow demonstrates a complete SSE flow using the chainable API. This pattern is commonly used in AI chat completions and similar streaming APIs.
package main
import (
"io"
"github.com/hydroan/gst/types"
)
func main() {
var sc *types.ServiceContext
// Stream data chunks using the chainable API
sc.SSE().Stream(func(w io.Writer) bool {
// Send chat completion chunks
_ = sc.Encode(w, types.Event{
Data: map[string]any{
"content": "Hello",
},
})
// Continue streaming...
return true
})
// Send [DONE] marker to indicate stream completion
// This is required by protocols like OpenAI's chat completion API
_ = sc.SSE().Done()
}
Output:
Example (Done) ¶
ExampleServiceContext_SSE_done demonstrates using the chainable API to send a [DONE] marker.
package main
import (
"github.com/hydroan/gst/types"
)
func main() {
var sc *types.ServiceContext
// Send [DONE] marker using the chainable API
_ = sc.SSE().Done()
}
Output:
Example (Stream) ¶
ExampleServiceContext_SSE_stream demonstrates using the chainable API for streaming.
package main
import (
"io"
"time"
"github.com/hydroan/gst/types"
)
func main() {
var sc *types.ServiceContext
// Stream events using the chainable API
sc.SSE().Stream(func(w io.Writer) bool {
_ = sc.Encode(w, types.Event{
Event: "message",
Data: time.Now().String(),
})
return true
})
}
Output:
Example (StreamWithInterval) ¶
ExampleServiceContext_SSE_streamWithInterval demonstrates using the chainable API for interval-based streaming.
package main
import (
"fmt"
"io"
"time"
"github.com/hydroan/gst/types"
)
func main() {
var sc *types.ServiceContext
// Stream with interval using the chainable API
counter := 0
sc.SSE().WithInterval(1 * time.Second).Stream(func(w io.Writer) bool {
counter++
// Send event
_ = sc.Encode(w, types.Event{
ID: fmt.Sprintf("event-%d", counter),
Event: "message",
Data: map[string]any{
"number": counter,
"message": fmt.Sprintf("Event %d of 3", counter),
},
})
// Return true to continue (will wait 1 second), false to stop
// This will send 3 events: at 0s, 1s, 2s, then stop
return counter < 3
})
// Send [DONE] marker if required by your protocol
_ = sc.SSE().Done()
}
Output:
func (*ServiceContext) SessionID ¶
func (sc *ServiceContext) SessionID() string
func (*ServiceContext) SetCookie ¶
func (sc *ServiceContext) SetCookie(cookie *http.Cookie)
func (*ServiceContext) TenantID ¶
func (sc *ServiceContext) TenantID() string
func (*ServiceContext) TraceID ¶
func (sc *ServiceContext) TraceID() string
func (*ServiceContext) UserAgent ¶
func (sc *ServiceContext) UserAgent() string
func (*ServiceContext) UserID ¶
func (sc *ServiceContext) UserID() string
func (*ServiceContext) Username ¶
func (sc *ServiceContext) Username() string
func (*ServiceContext) Value ¶
func (sc *ServiceContext) Value(key any) any
type StandardLogger ¶
type StandardLogger interface {
Debug(args ...any)
Info(args ...any)
Warn(args ...any)
Error(args ...any)
Fatal(args ...any)
Debugf(format string, args ...any)
Infof(format string, args ...any)
Warnf(format string, args ...any)
Errorf(format string, args ...any)
Fatalf(format string, args ...any)
}
StandardLogger provides plain and printf-style leveled logging methods. Fatal and Fatalf follow the underlying logger's fatal behavior and should terminate the process after writing the log entry.
type StructuredLogger ¶
type StructuredLogger interface {
Debugw(msg string, keysAndValues ...any)
Infow(msg string, keysAndValues ...any)
Warnw(msg string, keysAndValues ...any)
Errorw(msg string, keysAndValues ...any)
Fatalw(msg string, keysAndValues ...any)
}
StructuredLogger provides sugared structured logging with alternating key/value fields. Methods with suffix "w" mean "with fields".
type ZapLogger ¶
type ZapLogger interface {
Debugz(msg string, fields ...zap.Field)
Infoz(msg string, fields ...zap.Field)
Warnz(msg string, fields ...zap.Field)
Errorz(msg string, fields ...zap.Field)
Fatalz(msg string, fields ...zap.Field)
}
ZapLogger provides structured logging with typed zap.Field values. Methods with suffix "z" are the low-allocation typed-field variants.