or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdclient-management.mddatabase-operations.mdedge-functions.mdindex.mdrealtime-subscriptions.mdstorage-operations.md

edge-functions.mddocs/

0

# Edge Functions

1

2

Serverless function invocation and management for running custom server-side logic at the edge. Provides seamless integration with Supabase Edge Functions for executing TypeScript/JavaScript code with automatic scaling and global distribution.

3

4

## Capabilities

5

6

### Functions Client Access

7

8

Access the edge functions client through the main Supabase client instance.

9

10

```python { .api }

11

@property

12

def functions(self) -> SyncFunctionsClient | AsyncFunctionsClient:

13

"""

14

Functions client providing edge function invocation capabilities.

15

16

Returns:

17

Functions client instance (sync or async) with methods for:

18

- Function invocation with custom parameters

19

- Request/response handling with proper error management

20

- Integration with authentication context

21

- Custom headers and configuration options

22

"""

23

```

24

25

### Function Invocation

26

27

Execute edge functions with parameters, custom headers, and response handling.

28

29

```python { .api }

30

def invoke(

31

self,

32

function_name: str,

33

invoke_options: dict = None

34

) -> FunctionsResponse:

35

"""

36

Invoke an edge function by name.

37

38

Parameters:

39

- function_name: Name of the edge function to invoke

40

- invoke_options: Invocation options including body, headers, method, etc.

41

42

Returns:

43

FunctionsResponse with data, headers, status, and error information

44

45

Raises:

46

FunctionsHttpError: If HTTP request fails

47

FunctionsRelayError: If function relay fails

48

FunctionsError: For general function errors

49

50

Note: For async clients, this method is async

51

"""

52

```

53

54

**Usage Examples:**

55

56

```python

57

# Basic function invocation

58

response = supabase.functions.invoke("hello-world")

59

print(f"Response: {response.data}")

60

61

# Function with parameters

62

response = supabase.functions.invoke("greeting", {

63

"body": {"name": "Alice", "language": "en"}

64

})

65

print(f"Greeting: {response.data}")

66

67

# Function with custom headers

68

response = supabase.functions.invoke("protected-function", {

69

"headers": {

70

"Authorization": f"Bearer {user_token}",

71

"Content-Type": "application/json"

72

},

73

"body": {"action": "get_user_data"}

74

})

75

76

# POST request with JSON data

77

response = supabase.functions.invoke("process-data", {

78

"method": "POST",

79

"headers": {"Content-Type": "application/json"},

80

"body": {

81

"data": [1, 2, 3, 4, 5],

82

"operation": "sum",

83

"metadata": {"source": "python-client"}

84

}

85

})

86

87

# Handle response data

88

if response.data:

89

result = response.data

90

print(f"Processing result: {result}")

91

else:

92

print(f"Function failed: {response.error}")

93

94

# Async function invocation

95

async def call_async_function():

96

client = await create_async_client(url, key)

97

response = await client.functions.invoke("async-processor", {

98

"body": {"items": ["a", "b", "c"]}

99

})

100

return response.data

101

```

102

103

### Response Handling

104

105

Process function responses, handle errors, and extract data from function execution results.

106

107

```python { .api }

108

# FunctionsResponse attributes (from supabase_functions)

109

class FunctionsResponse:

110

"""Response from edge function invocation."""

111

112

data: Any

113

"""Function response data (parsed JSON or raw text)"""

114

115

error: Optional[str]

116

"""Error message if function execution failed"""

117

118

status: int

119

"""HTTP status code from function response"""

120

121

headers: Dict[str, str]

122

"""Response headers from function"""

123

```

124

125

**Usage Examples:**

126

127

```python

128

# Comprehensive response handling

129

response = supabase.functions.invoke("data-processor", {

130

"body": {"input": "test data"}

131

})

132

133

# Check response status

134

if response.status == 200:

135

print("Function executed successfully")

136

data = response.data

137

print(f"Result: {data}")

138

elif response.status == 400:

139

print(f"Bad request: {response.error}")

140

elif response.status == 500:

141

print(f"Function error: {response.error}")

142

else:

143

print(f"Unexpected status {response.status}: {response.error}")

144

145

# Access response headers

146

print(f"Content-Type: {response.headers.get('content-type')}")

147

print(f"Execution time: {response.headers.get('x-execution-time')}")

148

149

# Handle different response types

150

def process_function_response(response):

151

"""Process function response based on content type"""

152

content_type = response.headers.get('content-type', '')

153

154

if 'application/json' in content_type:

155

# JSON response

156

return response.data

157

elif 'text/plain' in content_type:

158

# Text response

159

return str(response.data)

160

elif 'application/octet-stream' in content_type:

161

# Binary response

162

return response.data # Raw bytes

163

else:

164

# Unknown content type

165

return response.data

166

167

# Example with file processing function

168

response = supabase.functions.invoke("image-resize", {

169

"body": {"image_url": "https://example.com/image.jpg", "width": 300},

170

"headers": {"Accept": "application/json"}

171

})

172

173

if response.status == 200:

174

result = response.data

175

print(f"Resized image URL: {result['resized_url']}")

176

print(f"Original size: {result['original_size']}")

177

print(f"New size: {result['new_size']}")

178

```

179

180

### Authentication Integration

181

182

Invoke functions with user authentication context and handle auth-dependent operations.

183

184

```python { .api }

185

# Functions automatically inherit auth context from client

186

# No explicit API methods, but functions receive user context

187

```

188

189

**Usage Examples:**

190

191

```python

192

# Functions automatically receive user auth context

193

# The user's JWT token is automatically passed to functions

194

195

# Get current user session

196

session = supabase.auth.get_session()

197

if session:

198

# Function will receive authenticated user context

199

response = supabase.functions.invoke("user-profile", {

200

"body": {"operation": "get_preferences"}

201

})

202

203

user_data = response.data

204

print(f"User preferences: {user_data}")

205

else:

206

print("User not authenticated")

207

208

# Functions can access user data through auth context

209

response = supabase.functions.invoke("protected-operation", {

210

"body": {"action": "update_profile", "data": {"theme": "dark"}}

211

})

212

213

# Function can use auth to authorize operations

214

if response.status == 401:

215

print("Authentication required")

216

elif response.status == 403:

217

print("Insufficient permissions")

218

elif response.status == 200:

219

print(f"Operation successful: {response.data}")

220

221

# Example: User-specific data processing

222

def process_user_data(operation, data):

223

"""Process user data through edge function"""

224

# Check if user is authenticated

225

session = supabase.auth.get_session()

226

if not session:

227

raise Exception("Authentication required")

228

229

response = supabase.functions.invoke("user-data-processor", {

230

"body": {

231

"operation": operation,

232

"data": data,

233

"user_id": session.user.id # Explicit user ID

234

}

235

})

236

237

if response.status != 200:

238

raise Exception(f"Function failed: {response.error}")

239

240

return response.data

241

242

# Usage

243

try:

244

result = process_user_data("calculate_stats", {"period": "monthly"})

245

print(f"Stats: {result}")

246

except Exception as e:

247

print(f"Error: {e}")

248

```

249

250

### Custom Headers and Configuration

251

252

Send custom headers, configure request options, and handle different HTTP methods.

253

254

```python { .api }

255

# Invoke options configuration

256

invoke_options = {

257

"method": str, # HTTP method (GET, POST, PUT, etc.)

258

"headers": Dict[str, str], # Custom request headers

259

"body": Any, # Request body (JSON serializable)

260

"region": str, # Function region (optional)

261

"timeout": int # Request timeout in milliseconds

262

}

263

```

264

265

**Usage Examples:**

266

267

```python

268

# Custom headers for API integration

269

response = supabase.functions.invoke("external-api-proxy", {

270

"method": "POST",

271

"headers": {

272

"Content-Type": "application/json",

273

"X-API-Key": "external-service-key",

274

"User-Agent": "MyApp/1.0"

275

},

276

"body": {

277

"endpoint": "https://api.external.com/data",

278

"params": {"limit": 100}

279

}

280

})

281

282

# Different HTTP methods

283

# GET request

284

get_response = supabase.functions.invoke("data-fetcher", {

285

"method": "GET",

286

"headers": {"Accept": "application/json"}

287

})

288

289

# POST request with form data

290

post_response = supabase.functions.invoke("form-processor", {

291

"method": "POST",

292

"headers": {"Content-Type": "application/x-www-form-urlencoded"},

293

"body": "name=John&email=john@example.com"

294

})

295

296

# PUT request for updates

297

put_response = supabase.functions.invoke("resource-updater", {

298

"method": "PUT",

299

"headers": {"Content-Type": "application/json"},

300

"body": {"id": 123, "name": "Updated Name"}

301

})

302

303

# DELETE request

304

delete_response = supabase.functions.invoke("resource-deleter", {

305

"method": "DELETE",

306

"headers": {"Accept": "application/json"},

307

"body": {"id": 123}

308

})

309

310

# Configure timeout for long-running functions

311

response = supabase.functions.invoke("data-processor", {

312

"body": {"large_dataset": data},

313

"timeout": 60000 # 60 seconds

314

})

315

316

# Regional function invocation

317

response = supabase.functions.invoke("region-specific", {

318

"region": "us-east-1",

319

"body": {"data": "region-specific-data"}

320

})

321

```

322

323

### Batch Operations and Utilities

324

325

Handle multiple function calls, batch operations, and utility patterns.

326

327

**Usage Examples:**

328

329

```python

330

# Batch function calls

331

async def batch_invoke_functions(functions_data):

332

"""Invoke multiple functions concurrently (async)"""

333

client = await create_async_client(url, key)

334

335

tasks = []

336

for func_name, options in functions_data.items():

337

task = client.functions.invoke(func_name, options)

338

tasks.append(task)

339

340

results = await asyncio.gather(*tasks, return_exceptions=True)

341

342

response_map = {}

343

for i, (func_name, _) in enumerate(functions_data.items()):

344

response_map[func_name] = results[i]

345

346

return response_map

347

348

# Batch processing example

349

batch_data = {

350

"process-images": {

351

"body": {"images": ["img1.jpg", "img2.jpg"]}

352

},

353

"send-notifications": {

354

"body": {"users": ["user1", "user2"], "message": "Hello"}

355

},

356

"update-analytics": {

357

"body": {"events": ["login", "purchase"]}

358

}

359

}

360

361

# async batch execution

362

results = await batch_invoke_functions(batch_data)

363

for func_name, response in results.items():

364

if isinstance(response, Exception):

365

print(f"{func_name} failed: {response}")

366

else:

367

print(f"{func_name} result: {response.data}")

368

369

# Synchronous batch with error handling

370

def batch_invoke_sync(function_calls):

371

"""Invoke multiple functions synchronously with error handling"""

372

results = {}

373

374

for func_name, options in function_calls.items():

375

try:

376

response = supabase.functions.invoke(func_name, options)

377

results[func_name] = {

378

"success": True,

379

"data": response.data,

380

"status": response.status

381

}

382

except Exception as e:

383

results[func_name] = {

384

"success": False,

385

"error": str(e),

386

"status": None

387

}

388

389

return results

390

391

# Pipeline processing

392

def function_pipeline(data, pipeline_steps):

393

"""Process data through a pipeline of functions"""

394

current_data = data

395

396

for step in pipeline_steps:

397

func_name = step["function"]

398

params = step.get("params", {})

399

400

response = supabase.functions.invoke(func_name, {

401

"body": {**params, "input": current_data}

402

})

403

404

if response.status != 200:

405

raise Exception(f"Pipeline failed at {func_name}: {response.error}")

406

407

current_data = response.data

408

409

return current_data

410

411

# Usage

412

pipeline = [

413

{"function": "validate-data", "params": {"schema": "user_data"}},

414

{"function": "transform-data", "params": {"format": "normalized"}},

415

{"function": "enrich-data", "params": {"source": "external_api"}},

416

{"function": "store-data", "params": {"table": "processed_users"}}

417

]

418

419

try:

420

result = function_pipeline(user_input_data, pipeline)

421

print(f"Pipeline result: {result}")

422

except Exception as e:

423

print(f"Pipeline failed: {e}")

424

```

425

426

### Error Handling and Debugging

427

428

Handle function errors, debug issues, and implement retry logic.

429

430

```python { .api }

431

# Functions exceptions (from supabase_functions)

432

class FunctionsError(Exception):

433

"""Base class for functions errors"""

434

435

class FunctionsHttpError(Exception):

436

"""HTTP request errors when invoking functions"""

437

438

class FunctionsRelayError(Exception):

439

"""Function relay and communication errors"""

440

```

441

442

**Error Handling Examples:**

443

444

```python

445

from supabase_functions.errors import FunctionsError, FunctionsHttpError, FunctionsRelayError

446

447

# Comprehensive error handling

448

def invoke_with_retry(func_name, options, max_retries=3):

449

"""Invoke function with retry logic"""

450

for attempt in range(max_retries):

451

try:

452

response = supabase.functions.invoke(func_name, options)

453

454

# Check for successful response

455

if response.status == 200:

456

return response

457

elif response.status >= 500:

458

# Server error - retry

459

if attempt < max_retries - 1:

460

print(f"Server error (attempt {attempt + 1}), retrying...")

461

time.sleep(2 ** attempt) # Exponential backoff

462

continue

463

else:

464

raise Exception(f"Server error after {max_retries} attempts")

465

else:

466

# Client error - don't retry

467

raise Exception(f"Client error {response.status}: {response.error}")

468

469

except FunctionsHttpError as e:

470

# Network/HTTP error - retry

471

if attempt < max_retries - 1:

472

print(f"HTTP error (attempt {attempt + 1}): {e}")

473

time.sleep(2 ** attempt)

474

continue

475

else:

476

raise Exception(f"HTTP error after {max_retries} attempts: {e}")

477

478

except FunctionsRelayError as e:

479

# Relay error - retry

480

if attempt < max_retries - 1:

481

print(f"Relay error (attempt {attempt + 1}): {e}")

482

time.sleep(2 ** attempt)

483

continue

484

else:

485

raise Exception(f"Relay error after {max_retries} attempts: {e}")

486

487

except FunctionsError as e:

488

# General function error - don't retry

489

raise Exception(f"Function error: {e}")

490

491

# Error categorization and handling

492

def handle_function_error(response):

493

"""Categorize and handle function errors"""

494

status = response.status

495

error = response.error

496

497

if status == 400:

498

return {"type": "client_error", "message": "Invalid request", "retry": False}

499

elif status == 401:

500

return {"type": "auth_error", "message": "Authentication required", "retry": False}

501

elif status == 403:

502

return {"type": "permission_error", "message": "Insufficient permissions", "retry": False}

503

elif status == 404:

504

return {"type": "not_found", "message": "Function not found", "retry": False}

505

elif status == 429:

506

return {"type": "rate_limit", "message": "Rate limit exceeded", "retry": True}

507

elif status >= 500:

508

return {"type": "server_error", "message": "Server error", "retry": True}

509

else:

510

return {"type": "unknown", "message": error, "retry": False}

511

512

# Usage with error handling

513

try:

514

response = invoke_with_retry("unreliable-function", {

515

"body": {"data": "test"}

516

})

517

print(f"Success: {response.data}")

518

519

except Exception as e:

520

print(f"Function invocation failed: {e}")

521

522

# Debugging and logging

523

def invoke_with_logging(func_name, options):

524

"""Invoke function with detailed logging"""

525

print(f"Invoking function: {func_name}")

526

print(f"Options: {options}")

527

528

start_time = time.time()

529

530

try:

531

response = supabase.functions.invoke(func_name, options)

532

533

duration = time.time() - start_time

534

print(f"Function completed in {duration:.2f}s")

535

print(f"Status: {response.status}")

536

print(f"Headers: {response.headers}")

537

538

if response.status == 200:

539

print(f"Response data: {response.data}")

540

else:

541

print(f"Error: {response.error}")

542

543

return response

544

545

except Exception as e:

546

duration = time.time() - start_time

547

print(f"Function failed after {duration:.2f}s: {e}")

548

raise

549

550

# Function health check

551

def check_function_health(func_name):

552

"""Check if function is healthy and responsive"""

553

try:

554

response = supabase.functions.invoke(func_name, {

555

"method": "GET",

556

"timeout": 5000 # 5 second timeout

557

})

558

559

return {

560

"healthy": response.status == 200,

561

"status": response.status,

562

"response_time": response.headers.get("x-execution-time"),

563

"error": response.error if response.status != 200 else None

564

}

565

except Exception as e:

566

return {

567

"healthy": False,

568

"status": None,

569

"response_time": None,

570

"error": str(e)

571

}

572

573

# Monitor function performance

574

health = check_function_health("critical-function")

575

if health["healthy"]:

576

print(f"Function is healthy (response time: {health['response_time']})")

577

else:

578

print(f"Function is unhealthy: {health['error']}")

579

```

580

581

### Performance and Best Practices

582

583

```python

584

# Optimize function calls for performance and reliability

585

586

# 1. Use appropriate timeouts

587

short_timeout_response = supabase.functions.invoke("quick-function", {

588

"body": {"data": "test"},

589

"timeout": 5000 # 5 seconds for quick operations

590

})

591

592

long_timeout_response = supabase.functions.invoke("heavy-processing", {

593

"body": {"large_dataset": data},

594

"timeout": 120000 # 2 minutes for heavy processing

595

})

596

597

# 2. Minimize payload size

598

# Good: Send only necessary data

599

response = supabase.functions.invoke("processor", {

600

"body": {"ids": [1, 2, 3], "operation": "summarize"}

601

})

602

603

# Avoid: Sending large unnecessary data

604

# response = supabase.functions.invoke("processor", {

605

# "body": {"full_records": large_dataset, "operation": "summarize"}

606

# })

607

608

# 3. Use appropriate error handling

609

def robust_function_call(func_name, data):

610

"""Make robust function calls with proper error handling"""

611

try:

612

response = supabase.functions.invoke(func_name, {

613

"body": data,

614

"timeout": 30000

615

})

616

617

if response.status == 200:

618

return {"success": True, "data": response.data}

619

else:

620

return {"success": False, "error": response.error, "status": response.status}

621

622

except Exception as e:

623

return {"success": False, "error": str(e), "status": None}

624

625

# 4. Cache function results when appropriate

626

function_cache = {}

627

628

def cached_function_call(func_name, cache_key, data):

629

"""Cache function results to avoid redundant calls"""

630

if cache_key in function_cache:

631

return function_cache[cache_key]

632

633

result = robust_function_call(func_name, data)

634

if result["success"]:

635

function_cache[cache_key] = result

636

637

return result

638

639

# 5. Async batch processing for multiple independent calls

640

async def process_items_concurrently(items):

641

"""Process multiple items concurrently using functions"""

642

client = await create_async_client(url, key)

643

644

tasks = []

645

for item in items:

646

task = client.functions.invoke("item-processor", {

647

"body": {"item": item}

648

})

649

tasks.append(task)

650

651

responses = await asyncio.gather(*tasks, return_exceptions=True)

652

653

results = []

654

for i, response in enumerate(responses):

655

if isinstance(response, Exception):

656

results.append({"item": items[i], "success": False, "error": str(response)})

657

else:

658

results.append({"item": items[i], "success": True, "data": response.data})

659

660

return results

661

```