๐ WOWSQL Go SDK
Official Go SDK for WOWSQL - MySQL Backend-as-a-Service with S3 Storage.

โจ Features
Database Features
- ๐๏ธ Full CRUD operations (Create, Read, Update, Delete)
- ๐ Advanced filtering (eq, neq, gt, gte, lt, lte, like, isNull, in, notIn, between, notBetween)
- ๐ Logical operators (AND, OR)
- ๐ GROUP BY and aggregate functions (COUNT, SUM, AVG, MAX, MIN)
- ๐ฏ HAVING clause for filtering aggregated results
- ๐ Multiple ORDER BY columns
- ๐
Date/time functions in SELECT and filters
- ๐งฎ Expressions in SELECT (e.g., "COUNT(*)", "DATE(created_at) as date")
- ๐ Pagination (limit, offset)
- ๐ Sorting (orderBy)
- ๐ฏ Fluent query builder API
- ๐ Type-safe queries
- ๐ Raw SQL queries
- ๐ Table schema introspection
- ๐ก๏ธ Comprehensive error handling
Storage Features
- ๐ฆ S3-compatible storage for file management
- โฌ๏ธ File upload with automatic quota validation
- โฌ๏ธ File download (presigned URLs)
- ๐ File listing with metadata
- ๐๏ธ File deletion (single and batch)
- ๐ Storage quota management
- ๐ Multi-region S3 support
- ๐ก๏ธ Client-side limit enforcement
๐ฆ Installation
## ๐ Quick Start
### Database Operations
```go
package main
import (
"fmt"
"log"
"github.com/wowsql/wowsql-go/WOWSQL"
)
func main() {
// Initialize client
client := WOWSQL.NewClient(
"https://your-project.wowsql.com",
"your-api-key",
)
// Query data
users, err := client.Table("users").
Select("id", "name", "email").
Eq("status", "active").
Limit(10).
Execute()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d users\n", users.Count)
for _, user := range users.Data {
fmt.Printf("%s - %s\n", user["name"], user["email"])
}
}
Storage Operations
package main
import (
"fmt"
"log"
"os"
"github.com/wowsql/wowsql-go/WOWSQL"
)
func main() {
// Initialize storage client
storage := WOWSQL.NewStorageClient(
"https://your-project.wowsql.com",
"your-api-key",
)
// Upload file
fileData, _ := os.ReadFile("document.pdf")
result, err := storage.Upload(
fileData,
"uploads/document.pdf",
"application/pdf",
nil,
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Uploaded: %s\n", result.URL)
// Check quota
quota, err := storage.GetQuota()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Storage used: %.2fGB / %.2fGB\n",
quota.StorageUsedGB,
quota.StorageQuotaGB)
}
Project Authentication
package main
import (
"fmt"
"log"
"github.com/wowsql/wowsql-go/WOWSQL"
)
func main() {
auth := WOWSQL.NewAuthClient(WOWSQL.AuthConfig{
ProjectURL: "https://your-project.wowsql.com",
APIKey: "your-anon-key", // Use anon key for client-side, service key for server-side
})
// Sign up an end user
result, err := auth.SignUp("user@example.com", "SuperSecret123",
WOWSQL.WithFullName("End User"))
if err != nil {
log.Fatal(err)
}
fmt.Println("User ID:", result.User.ID)
fmt.Println("Access token:", result.Session.AccessToken)
// Fetch the same user via stored session token
user, err := auth.GetUser(result.Session.AccessToken)
if err != nil {
log.Fatal(err)
}
fmt.Println("Email verified:", user.EmailVerified)
// OAuth Authentication
oauthResp, err := auth.GetOAuthAuthorizationURL("github", "https://app.example.com/auth/callback")
if err != nil {
log.Fatal(err)
}
fmt.Println("Send user to:", oauthResp.AuthorizationURL)
// After callback, exchange code for tokens
redirectURI := "https://app.example.com/auth/callback"
oauthResult, err := auth.ExchangeOAuthCallback("github", "authorization_code", &redirectURI)
if err != nil {
log.Fatal(err)
}
fmt.Println("OAuth user:", oauthResult.User.Email)
// Password Reset
forgotResult, err := auth.ForgotPassword("user@example.com")
if err != nil {
log.Fatal(err)
}
fmt.Println(forgotResult["message"])
resetResult, err := auth.ResetPassword("reset_token", "newSecurePassword123")
if err != nil {
log.Fatal(err)
}
fmt.Println(resetResult["message"])
}
๐ Usage Examples
Select Queries
client := WOWSQL.NewClient(
"https://your-project.wowsql.com",
"your-api-key",
)
// Select all columns
all, err := client.Table("users").Select("*").Execute()
// Select specific columns
users, err := client.Table("users").
Select("id", "name", "email").
Execute()
// With filters
active, err := client.Table("users").
Select("*").
Eq("status", "active").
Gt("age", 18).
Execute()
// With ordering
recent, err := client.Table("users").
Select("*").
OrderBy("created_at", WOWSQL.SortDesc).
Limit(10).
Execute()
// With pagination
page1, err := client.Table("users").
Select("*").
Limit(20).
Offset(0).
Execute()
// Pattern matching
gmailUsers, err := client.Table("users").
Select("*").
Like("email", "%@gmail.com").
Execute()
// Get first result
user, err := client.Table("users").
Eq("email", "john@example.com").
First()
if user != nil {
fmt.Printf("Found user: %s\n", user["name"])
}
Insert Data
// Insert single record
result, err := client.Table("users").Insert(map[string]interface{}{
"name": "John Doe",
"email": "john@example.com",
"age": 30,
"status": "active",
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("New user ID: %v\n", result.ID)
Update Data
// Update by ID
result, err := client.Table("users").UpdateByID(1, map[string]interface{}{
"name": "Jane Smith",
"age": 26,
})
fmt.Printf("Updated %d row(s)\n", result.AffectedRows)
// Update with conditions
updated, err := client.Table("users").
Where().
Eq("status", "inactive").
Update(map[string]interface{}{
"status": "active",
})
Delete Data
// Delete by ID
result, err := client.Table("users").DeleteByID(1)
fmt.Printf("Deleted %d row(s)\n", result.AffectedRows)
// Delete with conditions
deleted, err := client.Table("users").
Where().
Eq("status", "deleted").
Delete()
Filter Operators
// Equal
.Eq("status", "active")
// Not equal
.Neq("status", "deleted")
// Greater than
.Gt("age", 18)
// Greater than or equal
.Gte("age", 18)
// Less than
.Lt("age", 65)
// Less than or equal
.Lte("age", 65)
// Pattern matching (SQL LIKE)
.Like("email", "%@gmail.com")
// Is null
.IsNull("deleted_at")
// IN operator
.In("category", []interface{}{"electronics", "books", "clothing"})
// NOT IN operator
.NotIn("status", []interface{}{"deleted", "archived"})
// BETWEEN operator
.Between("price", 10, 100)
// NOT BETWEEN operator
.NotBetween("age", 18, 65)
// OR logical operator
.Or("category", "eq", "electronics")
Advanced Query Features
GROUP BY and Aggregates
GROUP BY supports both simple column names and SQL expressions with functions. All expressions are validated for security.
Basic GROUP BY
// Group by single column
result, err := client.Table("products").
Select("category", "COUNT(*) as count", "AVG(price) as avg_price").
GroupBy("category").
Execute()
// Group by multiple columns
result, err := client.Table("sales").
Select("region", "category", "SUM(amount) as total").
GroupBy("region", "category").
Execute()
GROUP BY with Date/Time Functions
// Group by date
result, err := client.Table("orders").
Select("DATE(created_at) as date", "COUNT(*) as orders", "SUM(total) as revenue").
GroupBy("DATE(created_at)").
OrderBy("date", WOWSQL.SortDesc).
Execute()
// Group by year and month
result, err := client.Table("orders").
Select("YEAR(created_at) as year", "MONTH(created_at) as month", "SUM(total) as revenue").
GroupBy("YEAR(created_at)", "MONTH(created_at)").
Execute()
Supported Functions in GROUP BY
Date/Time: DATE(), YEAR(), MONTH(), DAY(), WEEK(), QUARTER(), HOUR(), MINUTE(), SECOND(), DATE_FORMAT(), DATE_ADD(), DATE_SUB(), DATEDIFF(), NOW(), CURRENT_TIMESTAMP(), etc.
String: CONCAT(), SUBSTRING(), LEFT(), RIGHT(), UPPER(), LOWER(), LENGTH(), TRIM(), etc.
Mathematical: ROUND(), CEIL(), FLOOR(), ABS(), POW(), SQRT(), MOD(), etc.
HAVING Clause
HAVING filters aggregated results after GROUP BY. Supports aggregate functions and comparison operators.
// Filter aggregated results
result, err := client.Table("products").
Select("category", "COUNT(*) as count").
GroupBy("category").
Having("COUNT(*)", "gt", 10).
Execute()
// Multiple HAVING conditions
result, err := client.Table("orders").
Select("DATE(created_at) as date", "SUM(total) as revenue").
GroupBy("DATE(created_at)").
Having("SUM(total)", "gt", 1000).
Having("COUNT(*)", "gte", 5).
Execute()
// HAVING with different aggregate functions
result, err := client.Table("products").
Select("category", "AVG(price) as avg_price", "COUNT(*) as count").
GroupBy("category").
Having("AVG(price)", "gt", 100).
Having("COUNT(*)", "gte", 5).
Execute()
Supported HAVING Operators: eq, neq, gt, gte, lt, lte
Supported Aggregate Functions: COUNT(*), SUM(), AVG(), MAX(), MIN(), GROUP_CONCAT(), STDDEV(), VARIANCE()
Multiple ORDER BY
// Order by multiple columns
result, err := client.Table("products").
Select("*").
OrderByMultiple([]WOWSQL.OrderByItem{
{Column: "category", Direction: WOWSQL.SortAsc},
{Column: "price", Direction: WOWSQL.SortDesc},
{Column: "created_at", Direction: WOWSQL.SortDesc},
}).
Execute()
Date/Time Functions
// Filter by date range using functions
result, err := client.Table("orders").
Select("*").
Filter("created_at", "gte", "DATE_SUB(NOW(), INTERVAL 7 DAY)").
Execute()
// Group by date
result, err := client.Table("orders").
Select("DATE(created_at) as date", "COUNT(*) as count").
GroupBy("DATE(created_at)").
Execute()
Storage Operations
storage := WOWSQL.NewStorageClient(
"https://your-project.wowsql.com",
"your-api-key",
)
// Upload file from bytes
fileData, _ := os.ReadFile("document.pdf")
uploadResult, err := storage.Upload(
fileData,
"uploads/2024/document.pdf",
"application/pdf",
nil,
)
fmt.Printf("Uploaded: %s\n", uploadResult.URL)
// Check if file exists
exists, err := storage.FileExists("uploads/document.pdf")
if exists {
fmt.Println("File exists!")
}
// Get file information
info, err := storage.GetFileInfo("uploads/document.pdf")
fmt.Printf("Size: %d bytes\n", info.Size)
fmt.Printf("Modified: %s\n", info.LastModified)
// List files with prefix
files, err := storage.ListFiles("uploads/2024/", 0)
for _, file := range files {
fmt.Printf("%s: %d bytes\n", file.Key, file.Size)
}
// Download file (get presigned URL)
url, err := storage.Download("uploads/document.pdf", 3600)
fmt.Printf("Download URL: %s\n", url)
// URL is valid for 1 hour
// Delete single file
err = storage.DeleteFile("uploads/old-file.pdf")
// Delete multiple files
err = storage.DeleteFiles([]string{
"uploads/file1.pdf",
"uploads/file2.pdf",
"uploads/file3.pdf",
})
// Check quota
quota, err := storage.GetQuota()
fmt.Printf("Used: %.2f GB\n", quota.StorageUsedGB)
fmt.Printf("Available: %.2f GB\n", quota.StorageAvailableGB)
fmt.Printf("Usage: %.1f%%\n", quota.UsagePercentage)
// Check if enough storage before upload
if quota.StorageAvailableBytes < int64(len(fileData)) {
fmt.Println("Not enough storage!")
} else {
storage.Upload(fileData, "uploads/large-file.zip", "", nil)
}
Error Handling
import (
"errors"
"github.com/wowsql/wowsql-go/WOWSQL"
)
users, err := client.Table("users").Select("*").Execute()
if err != nil {
var authErr *WOWSQL.AuthenticationError
var notFoundErr *WOWSQL.NotFoundError
var rateLimitErr *WOWSQL.RateLimitError
var networkErr *WOWSQL.NetworkError
switch {
case errors.As(err, &authErr):
fmt.Printf("Authentication error: %s\n", authErr.Message)
case errors.As(err, ¬FoundErr):
fmt.Printf("Not found: %s\n", notFoundErr.Message)
case errors.As(err, &rateLimitErr):
fmt.Printf("Rate limit exceeded: %s\n", rateLimitErr.Message)
case errors.As(err, &networkErr):
fmt.Printf("Network error: %s\n", err)
default:
fmt.Printf("Error: %s\n", err)
}
}
// Storage errors
_, err = storage.Upload(fileData, "uploads/file.pdf", "", nil)
if err != nil {
var limitErr *WOWSQL.StorageLimitExceededError
var storageErr *WOWSQL.StorageError
switch {
case errors.As(err, &limitErr):
fmt.Printf("Storage full: %s\n", limitErr.Message)
fmt.Printf("Required: %d bytes\n", limitErr.RequiredBytes)
fmt.Printf("Available: %d bytes\n", limitErr.AvailableBytes)
case errors.As(err, &storageErr):
fmt.Printf("Storage error: %s\n", storageErr.Message)
}
}
Utility Methods
// List all tables
tables, err := client.ListTables()
fmt.Printf("Tables: %v\n", tables)
// Get table schema
schema, err := client.GetTableSchema("users")
fmt.Printf("Columns: %d\n", len(schema.Columns))
for _, column := range schema.Columns {
fmt.Printf(" - %s (%s)\n", column.Name, column.Type)
}
// Raw SQL query
results, err := client.Query("SELECT COUNT(*) as count FROM users WHERE age > 18")
if len(results) > 0 {
fmt.Printf("Adult users: %v\n", results[0]["count"])
}
// Check API health
health, err := client.Health()
fmt.Printf("Status: %v\n", health["status"])
๐ง Configuration
Custom Timeout
import "time"
// Database client with custom timeout
client := WOWSQL.NewClientWithTimeout(
"https://your-project.wowsql.com",
"your-api-key",
60 * time.Second, // 60 seconds
)
// Storage client with custom timeout
storage := WOWSQL.NewStorageClientWithOptions(
"https://your-project.wowsql.com",
"your-api-key",
120 * time.Second, // 2 minutes for large files
true, // auto check quota
)
Auto Quota Check
// Disable automatic quota checking
storage := WOWSQL.NewStorageClientWithOptions(
"https://your-project.wowsql.com",
"your-api-key",
60 * time.Second,
false, // disable auto-check
)
// Manually check quota
quota, err := storage.GetQuota()
if quota.StorageAvailableBytes > int64(len(fileData)) {
checkQuota := false
storage.Upload(fileData, "uploads/file.pdf", "", &checkQuota)
}
๐ API Keys
WOWSQL uses different API keys for different operations. Understanding which key to use is crucial for proper authentication.
Key Types Overview
๐ Unified Authentication
โจ One Project = One Set of Keys for ALL Operations
WOWSQL uses unified authentication - the same API keys work for both database operations AND authentication operations.
| Operation Type |
Recommended Key |
Alternative Key |
Used By |
| Database Operations (CRUD) |
Service Role Key (wowsql_service_...) |
Anonymous Key (wowsql_anon_...) |
WOWSQLClient |
| Authentication Operations (OAuth, sign-in) |
Anonymous Key (wowsql_anon_...) |
Service Role Key (wowsql_service_...) |
ProjectAuthClient |
Where to Find Your Keys
All keys are found in: WOWSQL Dashboard โ Settings โ API Keys or Authentication โ PROJECT KEYS
-
Anonymous Key (wowsql_anon_...) โจ Unified Key
- Location: "Anonymous Key (Public)"
- Used for:
- โ
Client-side auth operations (signup, login, OAuth)
- โ
Public/client-side database operations with limited permissions
- Safe to expose in frontend code (browser, mobile apps)
-
Service Role Key (wowsql_service_...) โจ Unified Key
- Location: "Service Role Key (keep secret)"
- Used for:
- โ
Server-side auth operations (admin, full access)
- โ
Server-side database operations (full access, bypass RLS)
- NEVER expose in frontend code - server-side only!
Database Operations
Use Service Role Key or Anonymous Key for database operations:
package main
import "github.com/wowsql/wowsql-go/WOWSQL"
// Using Service Role Key (recommended for server-side, full access)
client := WOWSQL.NewClient(
"https://your-project.wowsql.com",
"wowsql_service_your-service-key-here", // Service Role Key
)
// Using Anonymous Key (for public/client-side access with limited permissions)
client := WOWSQL.NewClient(
"https://your-project.wowsql.com",
"wowsql_anon_your-anon-key-here", // Anonymous Key
)
// Query data
users, err := client.Table("users").Execute()
Authentication Operations
โจ UNIFIED AUTHENTICATION: Use the same keys as database operations!
package main
import "github.com/wowsql/wowsql-go/WOWSQL"
// Using Anonymous Key (recommended for client-side auth operations)
auth := WOWSQL.NewAuthClient(WOWSQL.AuthConfig{
ProjectURL: "https://your-project.wowsql.com",
APIKey: "wowsql_anon_your-anon-key-here", // Same key as database operations!
})
// Using Service Role Key (for server-side auth operations)
auth := WOWSQL.NewAuthClient(WOWSQL.AuthConfig{
ProjectURL: "https://your-project.wowsql.com",
APIKey: "wowsql_service_your-service-key-here", // Same key as database operations!
})
// OAuth authentication
oauthResp, err := auth.GetOAuthAuthorizationURL("github", "https://app.example.com/auth/callback")
Note: The PublicAPIKey parameter is deprecated but still works for backward compatibility. Use APIKey instead.
Environment Variables
Best practice: Use environment variables for API keys:
package main
import (
"os"
"github.com/wowsql/wowsql-go/WOWSQL"
)
// UNIFIED AUTHENTICATION: Same keys for both operations!
// Database operations - Service Role Key
dbClient := WOWSQL.NewClient(
os.Getenv("WOWSQL_PROJECT_URL"),
os.Getenv("WOWSQL_SERVICE_ROLE_KEY"), // or WOWSQL_ANON_KEY
)
// Authentication operations - Use the SAME key!
authClient := WOWSQL.NewAuthClient(WOWSQL.AuthConfig{
ProjectURL: os.Getenv("WOWSQL_PROJECT_URL"),
APIKey: os.Getenv("WOWSQL_ANON_KEY"), // Same key for client-side auth
// Or use WOWSQL_SERVICE_ROLE_KEY for server-side auth
})
Key Usage Summary
โจ UNIFIED AUTHENTICATION:
WOWSQLClient โ Uses Service Role Key or Anonymous Key for database operations
ProjectAuthClient โ Uses Anonymous Key (client-side) or Service Role Key (server-side) for authentication operations
- Same keys work for both database AND authentication operations! ๐
- Anonymous Key (
wowsql_anon_...) โ Client-side operations (auth + database)
- Service Role Key (
wowsql_service_...) โ Server-side operations (auth + database)
Security Best Practices
- Never expose Service Role Key in client-side code or public repositories
- Use Anonymous Key for client-side authentication flows (same key as database operations)
- Use Anonymous Key for public database access with limited permissions
- Store keys in environment variables, never hardcode them
- Rotate keys regularly if compromised
๐ง Schema Management
Programmatically manage your database schema with the WOWSQLSchema client.
โ ๏ธ IMPORTANT: Schema operations require a Service Role Key (service_*). Anonymous keys will return a 403 Forbidden error.
Quick Start
package main
import "github.com/wowsql/wowsql-go/WOWSQL"
func main() {
// Initialize schema client with SERVICE ROLE KEY
schema := WOWSQL.NewSchemaClient(
"https://your-project.wowsql.com",
"service_xyz789...", // โ ๏ธ Backend only! Never expose!
)
}
Create Table
// Create a new table
trueVal := true
err := schema.CreateTable(WOWSQL.CreateTableRequest{
TableName: "products",
Columns: []WOWSQL.ColumnDefinition{
{Name: "id", Type: "INT", AutoIncrement: &trueVal},
{Name: "name", Type: "VARCHAR(255)", NotNull: &trueVal},
{Name: "price", Type: "DECIMAL(10,2)", NotNull: &trueVal},
{Name: "category", Type: "VARCHAR(100)"},
{Name: "created_at", Type: "TIMESTAMP", Default: WOWSQL.strPtr("CURRENT_TIMESTAMP")},
},
PrimaryKey: WOWSQL.strPtr("id"),
Indexes: []WOWSQL.IndexDefinition{
{Name: "idx_category", Columns: []string{"category"}},
{Name: "idx_price", Columns: []string{"price"}},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Table created successfully!")
Alter Table
// Add a new column
err := schema.AlterTable(WOWSQL.AlterTableRequest{
TableName: "products",
AddColumns: []WOWSQL.ColumnDefinition{
{Name: "stock_quantity", Type: "INT", Default: WOWSQL.strPtr("0")},
},
})
// Modify an existing column
err = schema.AlterTable(WOWSQL.AlterTableRequest{
TableName: "products",
ModifyColumns: []WOWSQL.ColumnDefinition{
{Name: "price", Type: "DECIMAL(12,2)"}, // Increase precision
},
})
// Drop a column
err = schema.AlterTable(WOWSQL.AlterTableRequest{
TableName: "products",
DropColumns: []string{"category"},
})
// Rename a column
err = schema.AlterTable(WOWSQL.AlterTableRequest{
TableName: "products",
RenameColumns: []WOWSQL.RenameColumn{
{OldName: "name", NewName: "product_name"},
},
})
Drop Table
// Drop a table
err := schema.DropTable("old_table", false)
// Drop with CASCADE (removes dependent objects)
err = schema.DropTable("products", true)
Execute Raw SQL
// Execute custom schema SQL
err := schema.ExecuteSQL(`
CREATE INDEX idx_product_name
ON products(product_name);
`)
// Add a foreign key constraint
err = schema.ExecuteSQL(`
ALTER TABLE orders
ADD CONSTRAINT fk_product
FOREIGN KEY (product_id)
REFERENCES products(id);
`)
Security & Best Practices
โ
DO:
- Use service role keys only in backend/server code
- Store service keys in environment variables
- Use anonymous keys for client-side data operations
- Test schema changes in development first
โ DON'T:
- Never expose service role keys in client code
- Never commit service keys to version control
- Don't use anonymous keys for schema operations (will fail)
Example: Backend Migration Script
package main
import (
"fmt"
"log"
"os"
"github.com/wowsql/wowsql-go/WOWSQL"
)
func runMigration() error {
schema := WOWSQL.NewSchemaClient(
os.Getenv("WOWSQL_PROJECT_URL"),
os.Getenv("WOWSQL_SERVICE_KEY"), // From env var
)
// Create users table
trueVal := true
err := schema.CreateTable(WOWSQL.CreateTableRequest{
TableName: "users",
Columns: []WOWSQL.ColumnDefinition{
{Name: "id", Type: "INT", AutoIncrement: &trueVal},
{Name: "email", Type: "VARCHAR(255)", Unique: &trueVal, NotNull: &trueVal},
{Name: "name", Type: "VARCHAR(255)", NotNull: &trueVal},
{Name: "created_at", Type: "TIMESTAMP", Default: WOWSQL.strPtr("CURRENT_TIMESTAMP")},
},
PrimaryKey: WOWSQL.strPtr("id"),
Indexes: []WOWSQL.IndexDefinition{
{Name: "idx_email", Columns: []string{"email"}},
},
})
if err != nil {
return fmt.Errorf("migration failed: %w", err)
}
fmt.Println("Migration completed!")
return nil
}
func main() {
if err := runMigration(); err != nil {
log.Fatal(err)
}
}
Error Handling
import (
"errors"
"github.com/wowsql/wowsql-go/WOWSQL"
)
schema := WOWSQL.NewSchemaClient(
"https://your-project.wowsql.com",
"service_xyz...",
)
err := schema.CreateTable(WOWSQL.CreateTableRequest{
TableName: "test",
Columns: []WOWSQL.ColumnDefinition{
{Name: "id", Type: "INT"},
},
})
if err != nil {
var permErr *WOWSQL.PermissionError
if errors.As(err, &permErr) {
fmt.Printf("Permission denied: %s\n", permErr.Message)
fmt.Println("Make sure you're using a SERVICE ROLE KEY, not an anonymous key!")
} else {
fmt.Printf("Error: %s\n", err)
}
}
Troubleshooting
Error: "Invalid API key for project"
- Ensure you're using the correct key type for the operation
- Database operations require Service Role Key or Anonymous Key
- Authentication operations require Anonymous Key (client-side) or Service Role Key (server-side)
- Verify the key is copied correctly (no extra spaces)
Error: "Authentication failed"
- Check that you're using the correct key: Anonymous Key for client-side, Service Role Key for server-side
- Verify the project URL matches your dashboard
- Ensure the key hasn't been revoked or expired
๐ Requirements
๐ Links
๐ License
MIT License - see LICENSE file for details.
๐ค Contributing
Contributions are welcome! Please open an issue or submit a pull request.
๐ Support
Made with โค๏ธ by the WOWSQL Team