# ResolveSpec Integration Guide

## Overview

ResolveSpec is a flexible REST API framework that provides GraphQL-like capabilities while maintaining REST simplicity. It offers two approaches:
1. **ResolveSpec** - Body-based API with JSON request options
2. **RestHeadSpec** - Header-based API where query options are passed via HTTP headers

For WhatsHooked, we'll use both approaches to provide maximum flexibility.

## Installation

```bash
go get github.com/bitechdev/ResolveSpec
```

## Core Concepts

### Models
Models are Go structs that represent database tables. Use GORM tags for database mapping.

```go
type User struct {
    ID        string    `gorm:"primaryKey" json:"id"`
    Name      string    `gorm:"not null" json:"name"`
    Email     string    `gorm:"uniqueIndex;not null" json:"email"`
    CreatedAt time.Time `json:"created_at"`
    UpdatedAt time.Time `json:"updated_at"`
}
```

### Registry
The registry maps schema.table names to Go models.

```go
handler := resolvespec.NewHandlerWithGORM(db)
handler.Registry.RegisterModel("public.users", &User{})
handler.Registry.RegisterModel("public.hooks", &Hook{})
```

### Routing
ResolveSpec generates routes automatically for registered models:
- `/public/users` - Collection endpoints
- `/public/users/:id` - Individual resource endpoints

## ResolveSpec (Body-Based)

Request format:
```json
POST /public/users
{
  "operation": "read|create|update|delete",
  "data": {
    // For create/update operations
  },
  "options": {
    "columns": ["id", "name", "email"],
    "filters": [
      {"column": "status", "operator": "eq", "value": "active"}
    ],
    "preload": ["hooks:id,url,events"],
    "sort": ["-created_at", "+name"],
    "limit": 50,
    "offset": 0
  }
}
```

### Setup with Gorilla Mux

```go
import (
    "github.com/gorilla/mux"
    "github.com/bitechdev/ResolveSpec/pkg/resolvespec"
)

func SetupResolveSpec(db *gorm.DB) *mux.Router {
    handler := resolvespec.NewHandlerWithGORM(db)
    
    // Register models
    handler.Registry.RegisterModel("public.users", &User{})
    handler.Registry.RegisterModel("public.hooks", &Hook{})
    
    // Setup routes
    router := mux.NewRouter()
    resolvespec.SetupMuxRoutes(router, handler, nil)
    
    return router
}
```

## RestHeadSpec (Header-Based)

Request format:
```http
GET /public/users HTTP/1.1
X-Select-Fields: id,name,email
X-FieldFilter-Status: active
X-Preload: hooks:id,url,events
X-Sort: -created_at,+name
X-Limit: 50
X-Offset: 0
X-DetailApi: true
```

### Setup with Gorilla Mux

```go
import (
    "github.com/gorilla/mux"
    "github.com/bitechdev/ResolveSpec/pkg/restheadspec"
)

func SetupRestHeadSpec(db *gorm.DB) *mux.Router {
    handler := restheadspec.NewHandlerWithGORM(db)
    
    // Register models
    handler.Registry.RegisterModel("public.users", &User{})
    handler.Registry.RegisterModel("public.hooks", &Hook{})
    
    // Setup routes
    router := mux.NewRouter()
    restheadspec.SetupMuxRoutes(router, handler, nil)
    
    return router
}
```

## Lifecycle Hooks (RestHeadSpec)

Add hooks for authentication, validation, and audit logging:

```go
handler.OnBeforeRead(func(ctx context.Context, req *restheadspec.Request) error {
    // Check permissions
    userID := ctx.Value("user_id").(string)
    if !canRead(userID, req.Schema, req.Entity) {
        return fmt.Errorf("unauthorized")
    }
    return nil
})

handler.OnAfterCreate(func(ctx context.Context, req *restheadspec.Request, result interface{}) error {
    // Audit log
    log.Info().
        Str("user_id", ctx.Value("user_id").(string)).
        Str("entity", req.Entity).
        Msg("Created record")
    return nil
})
```

## Authentication Integration

```go
// Middleware to extract user from JWT
func AuthMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("Authorization")
        user, err := ValidateToken(token)
        if err != nil {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        
        ctx := context.WithValue(r.Context(), "user_id", user.ID)
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

// Apply to routes
router.Use(AuthMiddleware)
```

## Filtering

### Field Filters (RestHeadSpec)
```http
X-FieldFilter-Status: active
X-FieldFilter-Age: 18
```

### Search Operators (RestHeadSpec)
```http
X-SearchOp-Gte-Age: 18
X-SearchOp-Like-Name: john
```

### Body Filters (ResolveSpec)
```json
{
  "options": {
    "filters": [
      {"column": "status", "operator": "eq", "value": "active"},
      {"column": "age", "operator": "gte", "value": 18},
      {"column": "name", "operator": "like", "value": "john%"}
    ]
  }
}
```

## Pagination

### Offset-Based
```http
X-Limit: 50
X-Offset: 100
```

### Cursor-Based (RestHeadSpec)
```http
X-Cursor: eyJpZCI6IjEyMyIsImNyZWF0ZWRfYXQiOiIyMDI0LTAxLTAxIn0=
X-Limit: 50
```

## Preloading Relationships

Load related entities with custom columns:

```http
X-Preload: hooks:id,url,events,posts:id,title
```

```json
{
  "options": {
    "preload": ["hooks:id,url,events", "posts:id,title"]
  }
}
```

## Sorting

```http
X-Sort: -created_at,+name
```

Prefix with `-` for descending, `+` for ascending.

## Response Formats (RestHeadSpec)

### Simple Format (default)
```http
X-DetailApi: false
```
Returns: `[{...}, {...}]`

### Detailed Format
```http
X-DetailApi: true
```
Returns:
```json
{
  "data": [{...}, {...}],
  "meta": {
    "total": 100,
    "limit": 50,
    "offset": 0,
    "cursor": "..."
  }
}
```

## CORS Configuration

```go
corsConfig := &common.CORSConfig{
    AllowedOrigins: []string{"*"},
    AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
    AllowedHeaders: []string{"*"},
    ExposedHeaders: []string{"X-Total-Count", "X-Cursor"},
}

restheadspec.SetupMuxRoutes(router, handler, corsConfig)
```

## Error Handling

ResolveSpec returns standard HTTP error codes:
- 200: Success
- 400: Bad Request
- 401: Unauthorized
- 404: Not Found
- 500: Internal Server Error

Error response format:
```json
{
  "error": "error message",
  "details": "additional context"
}
```

## Best Practices

1. **Register models before routes**: Always register all models before calling SetupMuxRoutes
2. **Use lifecycle hooks**: Implement authentication and validation in hooks
3. **Schema naming**: Use `schema.table` format consistently
4. **Transactions**: Use database transactions for multi-record operations
5. **Validation**: Validate input in OnBeforeCreate/OnBeforeUpdate hooks
6. **Audit logging**: Use OnAfter* hooks for audit trails
7. **Performance**: Use preloading instead of N+1 queries
8. **Security**: Implement row-level security in hooks
9. **Rate limiting**: Add rate limiting middleware
10. **Monitoring**: Log all operations for monitoring

## Common Patterns

### User Filtering (Multi-tenancy)
```go
handler.OnBeforeRead(func(ctx context.Context, req *restheadspec.Request) error {
    userID := ctx.Value("user_id").(string)
    
    // Add user_id filter
    req.Options.Filters = append(req.Options.Filters, Filter{
        Column: "user_id",
        Operator: "eq",
        Value: userID,
    })
    
    return nil
})
```

### Soft Deletes
```go
handler.OnBeforeDelete(func(ctx context.Context, req *restheadspec.Request) error {
    // Convert to update with deleted_at
    req.Operation = "update"
    req.Data = map[string]interface{}{
        "deleted_at": time.Now(),
    }
    return nil
})
```

### Validation
```go
handler.OnBeforeCreate(func(ctx context.Context, req *restheadspec.Request) error {
    user := req.Data.(*User)
    
    if user.Email == "" {
        return fmt.Errorf("email is required")
    }
    
    if !isValidEmail(user.Email) {
        return fmt.Errorf("invalid email format")
    }
    
    return nil
})
```

## References

- Official Docs: https://github.com/bitechdev/ResolveSpec
- ResolveSpec README: /pkg/resolvespec/README.md
- RestHeadSpec README: /pkg/restheadspec/README.md
