resolvespec

package
v1.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 30, 2025 License: MIT Imports: 23 Imported by: 0

README

ResolveSpec - Body-Based REST API

ResolveSpec provides a REST API where query options are passed in the JSON request body. This approach offers GraphQL-like flexibility while maintaining RESTful principles, making it ideal for complex queries and operations.

Features

  • Body-Based Querying: All query options passed via JSON request body
  • Lifecycle Hooks: Before/after hooks for create, read, update, delete operations
  • Cursor Pagination: Efficient cursor-based pagination with complex sorting
  • Offset Pagination: Traditional limit/offset pagination support
  • Advanced Filtering: Multiple operators, AND/OR logic, and custom SQL
  • Relationship Preloading: Load related entities with custom column selection and filters
  • Recursive CRUD: Automatically handle nested object graphs with foreign key resolution
  • Computed Columns: Define virtual columns with SQL expressions
  • Database-Agnostic: Works with GORM, Bun, or custom database adapters
  • Router-Agnostic: Integrates with any HTTP router through standard interfaces
  • Type-Safe: Strong type validation and conversion

Quick Start

Setup with GORM
import "github.com/bitechdev/ResolveSpec/pkg/resolvespec"
import "github.com/gorilla/mux"

// Create handler
handler := resolvespec.NewHandlerWithGORM(db)

// IMPORTANT: Register models BEFORE setting up routes
handler.registry.RegisterModel("core.users", &User{})
handler.registry.RegisterModel("core.posts", &Post{})

// Setup routes
router := mux.NewRouter()
resolvespec.SetupMuxRoutes(router, handler, nil)

// Start server
http.ListenAndServe(":8080", router)
Setup with Bun ORM
import "github.com/bitechdev/ResolveSpec/pkg/resolvespec"
import "github.com/uptrace/bun"

// Create handler with Bun
handler := resolvespec.NewHandlerWithBun(bunDB)

// Register models
handler.registry.RegisterModel("core.users", &User{})

// Setup routes (same as GORM)
router := mux.NewRouter()
resolvespec.SetupMuxRoutes(router, handler, nil)

Basic Usage

Simple Read Request
POST /core/users HTTP/1.1
Content-Type: application/json

{
  "operation": "read",
  "options": {
    "columns": ["id", "name", "email"],
    "filters": [
      {
        "column": "status",
        "operator": "eq",
        "value": "active"
      }
    ],
    "sort": [
      {
        "column": "created_at",
        "direction": "desc"
      }
    ],
    "limit": 10,
    "offset": 0
  }
}
With Preloading
POST /core/users HTTP/1.1
Content-Type: application/json

{
  "operation": "read",
  "options": {
    "columns": ["id", "name", "email"],
    "preload": [
      {
        "relation": "posts",
        "columns": ["id", "title", "created_at"],
        "filters": [
          {
            "column": "status",
            "operator": "eq",
            "value": "published"
          }
        ]
      }
    ],
    "limit": 10
  }
}

Request Structure

Request Format
{
  "operation": "read|create|update|delete",
  "data": {
    // For create/update operations
  },
  "options": {
    "columns": [...],
    "preload": [...],
    "filters": [...],
    "sort": [...],
    "limit": number,
    "offset": number,
    "cursor_forward": "string",
    "cursor_backward": "string",
    "customOperators": [...],
    "computedColumns": [...]
  }
}
Operations
Operation Description Requires Data Requires ID
read Fetch records No Optional (single record)
create Create new record(s) Yes No
update Update existing record(s) Yes Yes (in URL)
delete Delete record(s) No Yes (in URL)
Options Fields
Field Type Description Example
columns []string Columns to select ["id", "name", "email"]
preload []PreloadConfig Relations to load See Preloading
filters []Filter Filter conditions See Filtering
sort []Sort Sort criteria [{"column": "created_at", "direction": "desc"}]
limit int Max records to return 50
offset int Number of records to skip 100
cursor_forward string Cursor for next page "12345"
cursor_backward string Cursor for previous page "12300"
customOperators []CustomOperator Custom SQL conditions See Custom Operators
computedColumns []ComputedColumn Virtual columns See Computed Columns

Filtering

Available Operators
Operator Description Example
eq Equal {"column": "status", "operator": "eq", "value": "active"}
neq Not Equal {"column": "status", "operator": "neq", "value": "deleted"}
gt Greater Than {"column": "age", "operator": "gt", "value": 18}
gte Greater Than or Equal {"column": "age", "operator": "gte", "value": 18}
lt Less Than {"column": "price", "operator": "lt", "value": 100}
lte Less Than or Equal {"column": "price", "operator": "lte", "value": 100}
like LIKE pattern {"column": "name", "operator": "like", "value": "%john%"}
ilike Case-insensitive LIKE {"column": "email", "operator": "ilike", "value": "%@example.com"}
in IN clause {"column": "status", "operator": "in", "value": ["active", "pending"]}
contains Contains string {"column": "description", "operator": "contains", "value": "important"}
startswith Starts with string {"column": "name", "operator": "startswith", "value": "John"}
endswith Ends with string {"column": "email", "operator": "endswith", "value": "@example.com"}
between Between (exclusive) {"column": "age", "operator": "between", "value": [18, 65]}
betweeninclusive Between (inclusive) {"column": "price", "operator": "betweeninclusive", "value": [10, 100]}
empty IS NULL or empty {"column": "deleted_at", "operator": "empty"}
notempty IS NOT NULL {"column": "email", "operator": "notempty"}
Complex Filtering Example
{
  "operation": "read",
  "options": {
    "filters": [
      {
        "column": "status",
        "operator": "eq",
        "value": "active"
      },
      {
        "column": "age",
        "operator": "gte",
        "value": 18
      },
      {
        "column": "email",
        "operator": "ilike",
        "value": "%@company.com"
      }
    ]
  }
}

Preloading

Load related entities with custom configuration:

{
  "operation": "read",
  "options": {
    "columns": ["id", "name", "email"],
    "preload": [
      {
        "relation": "posts",
        "columns": ["id", "title", "created_at"],
        "filters": [
          {
            "column": "status",
            "operator": "eq",
            "value": "published"
          }
        ],
        "sort": [
          {
            "column": "created_at",
            "direction": "desc"
          }
        ],
        "limit": 5
      },
      {
        "relation": "profile",
        "columns": ["bio", "website"]
      }
    ]
  }
}

Cursor Pagination

Efficient pagination for large datasets:

First Request (No Cursor)
{
  "operation": "read",
  "options": {
    "sort": [
      {
        "column": "created_at",
        "direction": "desc"
      },
      {
        "column": "id",
        "direction": "asc"
      }
    ],
    "limit": 50
  }
}
Next Page (Forward Cursor)
{
  "operation": "read",
  "options": {
    "sort": [
      {
        "column": "created_at",
        "direction": "desc"
      },
      {
        "column": "id",
        "direction": "asc"
      }
    ],
    "limit": 50,
    "cursor_forward": "12345"
  }
}
Previous Page (Backward Cursor)
{
  "operation": "read",
  "options": {
    "sort": [
      {
        "column": "created_at",
        "direction": "desc"
      },
      {
        "column": "id",
        "direction": "asc"
      }
    ],
    "limit": 50,
    "cursor_backward": "12300"
  }
}

Benefits over offset pagination:

  • Consistent results when data changes
  • Better performance for large offsets
  • Prevents "skipped" or duplicate records
  • Works with complex sort expressions

Recursive CRUD Operations

Automatically handle nested object graphs with intelligent foreign key resolution.

Creating Nested Objects
{
  "operation": "create",
  "data": {
    "name": "John Doe",
    "email": "john@example.com",
    "posts": [
      {
        "title": "My First Post",
        "content": "Hello World",
        "tags": [
          {"name": "tech"},
          {"name": "programming"}
        ]
      },
      {
        "title": "Second Post",
        "content": "More content"
      }
    ],
    "profile": {
      "bio": "Software Developer",
      "website": "https://example.com"
    }
  }
}
Per-Record Operation Control with _request

Control individual operations for each nested record:

{
  "operation": "update",
  "data": {
    "name": "John Updated",
    "posts": [
      {
        "_request": "insert",
        "title": "New Post",
        "content": "Fresh content"
      },
      {
        "_request": "update",
        "id": 456,
        "title": "Updated Post Title"
      },
      {
        "_request": "delete",
        "id": 789
      }
    ]
  }
}

Supported _request values:

  • insert - Create a new related record
  • update - Update an existing related record
  • delete - Delete a related record
  • upsert - Create if doesn't exist, update if exists

How It Works:

  1. Automatic foreign key resolution - parent IDs propagate to children
  2. Recursive processing - handles nested relationships at any depth
  3. Transaction safety - all operations execute atomically
  4. Relationship detection - automatically detects belongsTo, hasMany, hasOne, many2many
  5. Flexible operations - mix create, update, and delete in one request

Computed Columns

Define virtual columns using SQL expressions:

{
  "operation": "read",
  "options": {
    "columns": ["id", "first_name", "last_name"],
    "computedColumns": [
      {
        "name": "full_name",
        "expression": "CONCAT(first_name, ' ', last_name)"
      },
      {
        "name": "age_years",
        "expression": "EXTRACT(YEAR FROM AGE(birth_date))"
      }
    ]
  }
}

Custom Operators

Add custom SQL conditions when needed:

{
  "operation": "read",
  "options": {
    "customOperators": [
      {
        "condition": "LOWER(email) LIKE ?",
        "values": ["%@example.com"]
      },
      {
        "condition": "created_at > NOW() - INTERVAL '7 days'"
      }
    ]
  }
}

Lifecycle Hooks

Register hooks for all CRUD operations:

import "github.com/bitechdev/ResolveSpec/pkg/resolvespec"

// Create handler
handler := resolvespec.NewHandlerWithGORM(db)

// Register a before-read hook (e.g., for authorization)
handler.Hooks().Register(resolvespec.BeforeRead, func(ctx *resolvespec.HookContext) error {
    // Check permissions
    if !userHasPermission(ctx.Context, ctx.Entity) {
        return fmt.Errorf("unauthorized access to %s", ctx.Entity)
    }

    // Modify query options
    if ctx.Options.Limit == nil || *ctx.Options.Limit > 100 {
        ctx.Options.Limit = ptr(100) // Enforce max limit
    }

    return nil
})

// Register an after-read hook (e.g., for data transformation)
handler.Hooks().Register(resolvespec.AfterRead, func(ctx *resolvespec.HookContext) error {
    // Transform or filter results
    if users, ok := ctx.Result.([]User); ok {
        for i := range users {
            users[i].Email = maskEmail(users[i].Email)
        }
    }
    return nil
})

// Register a before-create hook (e.g., for validation)
handler.Hooks().Register(resolvespec.BeforeCreate, func(ctx *resolvespec.HookContext) error {
    // Validate data
    if user, ok := ctx.Data.(*User); ok {
        if user.Email == "" {
            return fmt.Errorf("email is required")
        }
        // Add timestamps
        user.CreatedAt = time.Now()
    }
    return nil
})

Available Hook Types:

  • BeforeRead, AfterRead
  • BeforeCreate, AfterCreate
  • BeforeUpdate, AfterUpdate
  • BeforeDelete, AfterDelete

HookContext provides:

  • Context: Request context
  • Handler: Access to handler, database, and registry
  • Schema, Entity, TableName: Request info
  • Model: The registered model type
  • Options: Parsed request options (filters, sorting, etc.)
  • ID: Record ID (for single-record operations)
  • Data: Request data (for create/update)
  • Result: Operation result (for after hooks)
  • Writer: Response writer (allows hooks to modify response)

Model Registration

type User struct {
    ID        uint      `json:"id" gorm:"primaryKey"`
    Name      string    `json:"name"`
    Email     string    `json:"email"`
    Status    string    `json:"status"`
    CreatedAt time.Time `json:"created_at"`
    Posts     []Post    `json:"posts,omitempty" gorm:"foreignKey:UserID"`
    Profile   *Profile  `json:"profile,omitempty" gorm:"foreignKey:UserID"`
}

type Post struct {
    ID        uint      `json:"id" gorm:"primaryKey"`
    UserID    uint      `json:"user_id"`
    Title     string    `json:"title"`
    Content   string    `json:"content"`
    Status    string    `json:"status"`
    CreatedAt time.Time `json:"created_at"`
    Tags      []Tag     `json:"tags,omitempty" gorm:"many2many:post_tags"`
}

// Schema.Table format
handler.registry.RegisterModel("core.users", &User{})
handler.registry.RegisterModel("core.posts", &Post{})

Complete Example

package main

import (
    "log"
    "net/http"

    "github.com/bitechdev/ResolveSpec/pkg/resolvespec"
    "github.com/gorilla/mux"
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

type User struct {
    ID     uint   `json:"id" gorm:"primaryKey"`
    Name   string `json:"name"`
    Email  string `json:"email"`
    Status string `json:"status"`
    Posts  []Post `json:"posts,omitempty" gorm:"foreignKey:UserID"`
}

type Post struct {
    ID      uint   `json:"id" gorm:"primaryKey"`
    UserID  uint   `json:"user_id"`
    Title   string `json:"title"`
    Content string `json:"content"`
    Status  string `json:"status"`
}

func main() {
    // Connect to database
    db, err := gorm.Open(postgres.Open("your-connection-string"), &gorm.Config{})
    if err != nil {
        log.Fatal(err)
    }

    // Create handler
    handler := resolvespec.NewHandlerWithGORM(db)

    // Register models
    handler.registry.RegisterModel("core.users", &User{})
    handler.registry.RegisterModel("core.posts", &Post{})

    // Add hooks
    handler.Hooks().Register(resolvespec.BeforeRead, func(ctx *resolvespec.HookContext) error {
        log.Printf("Reading %s", ctx.Entity)
        return nil
    })

    // Setup routes
    router := mux.NewRouter()
    resolvespec.SetupMuxRoutes(router, handler, nil)

    // Start server
    log.Println("Server starting on :8080")
    log.Fatal(http.ListenAndServe(":8080", router))
}

Testing

ResolveSpec is designed for testability:

import (
    "bytes"
    "encoding/json"
    "net/http/httptest"
    "testing"
)

func TestUserRead(t *testing.T) {
    handler := resolvespec.NewHandlerWithGORM(testDB)
    handler.registry.RegisterModel("core.users", &User{})

    reqBody := map[string]interface{}{
        "operation": "read",
        "options": map[string]interface{}{
            "columns": []string{"id", "name"},
            "limit":   10,
        },
    }

    body, _ := json.Marshal(reqBody)
    req := httptest.NewRequest("POST", "/core/users", bytes.NewReader(body))
    rec := httptest.NewRecorder()

    // Test your handler...
}

Router Integration

Gorilla Mux
router := mux.NewRouter()
resolvespec.SetupMuxRoutes(router, handler, nil)
BunRouter
router := bunrouter.New()
resolvespec.SetupBunRouterWithResolveSpec(router, handler)
Custom Routers
// Implement custom integration using common.Request and common.ResponseWriter
router.POST("/:schema/:entity", func(w http.ResponseWriter, r *http.Request) {
    params := extractParams(r) // Your param extraction logic
    reqAdapter := router.NewHTTPRequest(r)
    respAdapter := router.NewHTTPResponseWriter(w)
    handler.Handle(respAdapter, reqAdapter, params)
})

Response Format

Success Response
{
  "success": true,
  "data": [...],
  "metadata": {
    "total": 100,
    "filtered": 50,
    "limit": 10,
    "offset": 0
  }
}
Error Response
{
  "success": false,
  "error": {
    "code": "validation_error",
    "message": "Invalid request",
    "details": "..."
  }
}

See Also

License

This package is part of ResolveSpec and is licensed under the MIT License.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ExampleBunRouterWithBunDB

func ExampleBunRouterWithBunDB(bunDB *bun.DB)

ExampleBunRouterWithBunDB shows the full uptrace stack (bunrouter + Bun ORM)

func ExampleWithBun

func ExampleWithBun(bunDB *bun.DB)

ExampleWithBun shows how to switch to Bun ORM

func ExampleWithBunRouter

func ExampleWithBunRouter(bunDB *bun.DB)

ExampleWithBunRouter shows how to use bunrouter from uptrace

func ExampleWithGORM

func ExampleWithGORM(db *gorm.DB)

ExampleWithGORM shows how to use ResolveSpec with GORM

func GetCursorFilter added in v0.0.80

func GetCursorFilter(
	tableName string,
	pkName string,
	modelColumns []string,
	options common.RequestOptions,
) (string, error)

GetCursorFilter generates a SQL `EXISTS` subquery for cursor-based pagination. It uses the current request's sort and cursor values.

Parameters:

  • tableName: name of the main table (e.g. "posts")
  • pkName: primary key column (e.g. "id")
  • modelColumns: optional list of valid main-table columns (for validation). Pass nil to skip.
  • options: the request options containing sort and cursor information

Returns SQL snippet to embed in WHERE clause.

func GetEntity

func GetEntity(ctx context.Context) string

GetEntity retrieves entity from context

func GetModel

func GetModel(ctx context.Context) interface{}

GetModel retrieves model from context

func GetModelPtr

func GetModelPtr(ctx context.Context) interface{}

GetModelPtr retrieves model pointer from context

func GetSchema

func GetSchema(ctx context.Context) string

GetSchema retrieves schema from context

func GetTableName

func GetTableName(ctx context.Context) string

GetTableName retrieves table name from context

func NewStandardBunRouter

func NewStandardBunRouter() *router.StandardBunRouterAdapter

NewStandardBunRouter creates a router with standard BunRouter handlers

func NewStandardMuxRouter

func NewStandardMuxRouter() *router.StandardMuxAdapter

NewStandardMuxRouter creates a router with standard Mux HTTP handlers

func RegisterSecurityHooks added in v0.0.67

func RegisterSecurityHooks(handler *Handler, securityList *security.SecurityList)

RegisterSecurityHooks registers all security-related hooks with the handler

func SetupBunRouterRoutes

func SetupBunRouterRoutes(bunRouter *router.StandardBunRouterAdapter, handler *Handler)

SetupBunRouterRoutes sets up bunrouter routes for the ResolveSpec API

func SetupMuxRoutes

func SetupMuxRoutes(muxRouter *mux.Router, handler *Handler, authMiddleware MiddlewareFunc)

SetupMuxRoutes sets up routes for the ResolveSpec API with Mux authMiddleware is optional - if provided, routes will be protected with the middleware Example: SetupMuxRoutes(router, handler, func(h http.Handler) http.Handler { return security.NewAuthHandler(securityList, h) })

func WithEntity

func WithEntity(ctx context.Context, entity string) context.Context

WithEntity adds entity to context

func WithModel

func WithModel(ctx context.Context, model interface{}) context.Context

WithModel adds model to context

func WithModelPtr

func WithModelPtr(ctx context.Context, modelPtr interface{}) context.Context

WithModelPtr adds model pointer to context

func WithRequestData

func WithRequestData(ctx context.Context, schema, entity, tableName string, model, modelPtr interface{}) context.Context

WithRequestData adds all request-scoped data to context at once

func WithSchema

func WithSchema(ctx context.Context, schema string) context.Context

WithSchema adds schema to context

func WithTableName

func WithTableName(ctx context.Context, tableName string) context.Context

WithTableName adds table name to context

Types

type CursorDirection added in v0.0.80

type CursorDirection int

CursorDirection defines pagination direction

const (
	CursorForward  CursorDirection = 1
	CursorBackward CursorDirection = -1
)

type FallbackHandler added in v0.0.69

type FallbackHandler func(w common.ResponseWriter, r common.Request, params map[string]string)

FallbackHandler is a function that handles requests when no model is found It receives the same parameters as the Handle method

type GormTableCRUDRequest

type GormTableCRUDRequest struct {
	Request *string `json:"_request"`
}

func (GormTableCRUDRequest) GetRequest

func (r GormTableCRUDRequest) GetRequest() string

func (*GormTableCRUDRequest) SetRequest

func (r *GormTableCRUDRequest) SetRequest(request string)

type GormTableNameInterface

type GormTableNameInterface interface {
	TableName() string
}

Legacy interfaces for backward compatibility

type GormTableSchemaInterface

type GormTableSchemaInterface interface {
	TableSchema() string
}

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

Handler handles API requests using database and model abstractions

func NewHandler

func NewHandler(db common.Database, registry common.ModelRegistry) *Handler

NewHandler creates a new API handler with database and registry abstractions

func NewHandlerWithBun

func NewHandlerWithBun(db *bun.DB) *Handler

NewHandlerWithBun creates a new Handler with Bun adapter

func NewHandlerWithGORM

func NewHandlerWithGORM(db *gorm.DB) *Handler

NewHandlerWithGORM creates a new Handler with GORM adapter

func (*Handler) GetDatabase added in v0.0.65

func (h *Handler) GetDatabase() common.Database

GetDatabase returns the underlying database connection Implements common.SpecHandler interface

func (*Handler) GetRelationshipInfo added in v0.0.20

func (h *Handler) GetRelationshipInfo(modelType reflect.Type, relationName string) *common.RelationshipInfo

GetRelationshipInfo implements common.RelationshipInfoProvider interface

func (*Handler) Handle

func (h *Handler) Handle(w common.ResponseWriter, r common.Request, params map[string]string)

Handle processes API requests through router-agnostic interface

func (*Handler) HandleGet

func (h *Handler) HandleGet(w common.ResponseWriter, r common.Request, params map[string]string)

HandleGet processes GET requests for metadata

func (*Handler) HandleOpenAPI added in v0.0.87

func (h *Handler) HandleOpenAPI(w common.ResponseWriter, r common.Request)

HandleOpenAPI generates and returns the OpenAPI specification

func (*Handler) Hooks added in v0.0.67

func (h *Handler) Hooks() *HookRegistry

Hooks returns the hook registry for this handler Use this to register custom hooks for operations

func (*Handler) RegisterModel

func (h *Handler) RegisterModel(schema, name string, model interface{}) error

RegisterModel allows registering models at runtime

func (*Handler) SetFallbackHandler added in v0.0.69

func (h *Handler) SetFallbackHandler(fallback FallbackHandler)

SetFallbackHandler sets a fallback handler to be called when no model is found If not set, the handler will simply return (pass through to next route)

func (*Handler) SetOpenAPIGenerator added in v0.0.87

func (h *Handler) SetOpenAPIGenerator(generator func() (string, error))

SetOpenAPIGenerator sets the OpenAPI generator function

type HookContext added in v0.0.67

type HookContext struct {
	Context context.Context
	Handler *Handler // Reference to the handler for accessing database, registry, etc.
	Schema  string
	Entity  string
	Model   interface{}
	Options common.RequestOptions
	Writer  common.ResponseWriter
	Request common.Request

	// Operation-specific fields
	ID     string
	Data   interface{} // For create/update operations
	Result interface{} // For after hooks
	Error  error       // For after hooks

	// Query chain - allows hooks to modify the query before execution
	Query common.SelectQuery

	// Allow hooks to abort the operation
	Abort        bool   // If set to true, the operation will be aborted
	AbortMessage string // Message to return if aborted
	AbortCode    int    // HTTP status code if aborted

	// Tx provides access to the database/transaction for executing additional SQL
	// This allows hooks to run custom queries in addition to the main Query chain
	Tx common.Database
}

HookContext contains all the data available to a hook

type HookFunc added in v0.0.67

type HookFunc func(*HookContext) error

HookFunc is the signature for hook functions It receives a HookContext and can modify it or return an error If an error is returned, the operation will be aborted

type HookRegistry added in v0.0.67

type HookRegistry struct {
	// contains filtered or unexported fields
}

HookRegistry manages all registered hooks

func NewHookRegistry added in v0.0.67

func NewHookRegistry() *HookRegistry

NewHookRegistry creates a new hook registry

func (*HookRegistry) Clear added in v0.0.67

func (r *HookRegistry) Clear(hookType HookType)

Clear removes all hooks for the specified type

func (*HookRegistry) ClearAll added in v0.0.67

func (r *HookRegistry) ClearAll()

ClearAll removes all registered hooks

func (*HookRegistry) Count added in v0.0.67

func (r *HookRegistry) Count(hookType HookType) int

Count returns the number of hooks registered for a specific type

func (*HookRegistry) Execute added in v0.0.67

func (r *HookRegistry) Execute(hookType HookType, ctx *HookContext) error

Execute runs all hooks for the specified type in order If any hook returns an error, execution stops and the error is returned

func (*HookRegistry) GetAllHookTypes added in v0.0.67

func (r *HookRegistry) GetAllHookTypes() []HookType

GetAllHookTypes returns all hook types that have registered hooks

func (*HookRegistry) HasHooks added in v0.0.67

func (r *HookRegistry) HasHooks(hookType HookType) bool

HasHooks returns true if there are any hooks registered for the specified type

func (*HookRegistry) Register added in v0.0.67

func (r *HookRegistry) Register(hookType HookType, hook HookFunc)

Register adds a new hook for the specified hook type

func (*HookRegistry) RegisterMultiple added in v0.0.67

func (r *HookRegistry) RegisterMultiple(hookTypes []HookType, hook HookFunc)

RegisterMultiple registers a hook for multiple hook types

type HookType added in v0.0.67

type HookType string

HookType defines the type of hook to execute

const (
	// Read operation hooks
	BeforeRead HookType = "before_read"
	AfterRead  HookType = "after_read"

	// Create operation hooks
	BeforeCreate HookType = "before_create"
	AfterCreate  HookType = "after_create"

	// Update operation hooks
	BeforeUpdate HookType = "before_update"
	AfterUpdate  HookType = "after_update"

	// Delete operation hooks
	BeforeDelete HookType = "before_delete"
	AfterDelete  HookType = "after_delete"

	// Scan/Execute operation hooks (for query building)
	BeforeScan HookType = "before_scan"
)

type MiddlewareFunc added in v0.0.65

type MiddlewareFunc func(http.Handler) http.Handler

MiddlewareFunc is a function that wraps an http.Handler with additional functionality

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL