or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-services.mdauthentication-jwt.mdcore-communications.mdindex.mdinfrastructure.mdrest-client.mdtwiml-generation.mdwebhooks-validation.md

infrastructure.mddocs/

0

# Infrastructure

1

2

Low-level infrastructure including HTTP clients, authentication strategies, credential providers, base classes, and exception handling. These components support the high-level APIs and can be customized for advanced use cases.

3

4

## Capabilities

5

6

### HTTP Client Infrastructure

7

8

Customizable HTTP client system supporting synchronous and asynchronous requests.

9

10

```python { .api }

11

class HttpClient:

12

"""Abstract HTTP client base class"""

13

14

def request(

15

self,

16

method: str,

17

uri: str,

18

data: dict = None,

19

headers: dict = None,

20

auth: tuple = None,

21

timeout: float = None,

22

allow_redirects: bool = None

23

) -> 'Response':

24

"""

25

Make HTTP request.

26

27

Args:

28

method (str): HTTP method ('GET', 'POST', etc.)

29

uri (str): Request URI

30

data (dict): Request body data

31

headers (dict): HTTP headers

32

auth (tuple): Authentication tuple (username, password)

33

timeout (float): Request timeout in seconds

34

allow_redirects (bool): Follow redirects

35

36

Returns:

37

Response: HTTP response object

38

"""

39

40

class TwilioHttpClient(HttpClient):

41

"""Default HTTP client using requests library"""

42

43

def __init__(

44

self,

45

pool_connections: int = 1,

46

pool_maxsize: int = 1,

47

max_retries: int = 3,

48

backoff_factor: float = 0.3,

49

proxy: dict = None,

50

ssl_context: 'SSLContext' = None,

51

timeout: float = 60.0

52

):

53

"""

54

Initialize HTTP client.

55

56

Args:

57

pool_connections (int): Number of connection pools

58

pool_maxsize (int): Max connections per pool

59

max_retries (int): Retry attempts for failed requests

60

backoff_factor (float): Backoff multiplier for retries

61

proxy (dict): Proxy configuration

62

ssl_context (SSLContext): Custom SSL context

63

timeout (float): Default timeout in seconds

64

"""

65

66

class AsyncHttpClient:

67

"""Abstract asynchronous HTTP client"""

68

69

async def request(

70

self,

71

method: str,

72

uri: str,

73

data: dict = None,

74

headers: dict = None,

75

auth: tuple = None,

76

timeout: float = None

77

) -> 'Response':

78

"""Make async HTTP request"""

79

80

class TwilioAsyncHttpClient(AsyncHttpClient):

81

"""Default async HTTP client using aiohttp"""

82

83

def __init__(

84

self,

85

timeout: float = 60.0,

86

pool_connections: int = 100,

87

pool_maxsize: int = 100,

88

ssl_context: 'SSLContext' = None

89

):

90

"""

91

Initialize async HTTP client.

92

93

Args:

94

timeout (float): Default timeout in seconds

95

pool_connections (int): Connection pool size

96

pool_maxsize (int): Maximum pool size

97

ssl_context (SSLContext): Custom SSL context

98

"""

99

100

async def request(

101

self,

102

method: str,

103

uri: str,

104

data: dict = None,

105

headers: dict = None,

106

auth: tuple = None,

107

timeout: float = None

108

) -> 'Response':

109

"""

110

Make async HTTP request.

111

112

Args:

113

method (str): HTTP method

114

uri (str): Request URI

115

data (dict): Request data

116

headers (dict): Request headers

117

auth (tuple): Authentication credentials

118

timeout (float): Request timeout

119

120

Returns:

121

Response: HTTP response object

122

"""

123

124

class Request:

125

"""HTTP request representation"""

126

127

def __init__(

128

self,

129

method: str,

130

uri: str,

131

data: dict = None,

132

headers: dict = None,

133

params: dict = None,

134

auth: tuple = None

135

):

136

"""

137

Args:

138

method (str): HTTP method

139

uri (str): Request URI

140

data (dict): Request body data

141

headers (dict): HTTP headers

142

params (dict): Query parameters

143

auth (tuple): Authentication credentials

144

"""

145

self.method = method

146

self.uri = uri

147

self.data = data

148

self.headers = headers

149

self.params = params

150

self.auth = auth

151

152

class Response:

153

"""HTTP response representation"""

154

155

def __init__(

156

self,

157

status_code: int,

158

text: str,

159

headers: dict = None

160

):

161

"""

162

Args:

163

status_code (int): HTTP status code

164

text (str): Response body text

165

headers (dict): Response headers

166

"""

167

self.status_code = status_code

168

self.text = text

169

self.headers = headers or {}

170

171

@property

172

def ok(self) -> bool:

173

"""True if status code indicates success (200-299)"""

174

return 200 <= self.status_code < 300

175

176

@property

177

def content(self) -> bytes:

178

"""Response body as bytes"""

179

return self.text.encode('utf-8')

180

```

181

182

### Authentication Strategies

183

184

Pluggable authentication system supporting multiple auth methods.

185

186

```python { .api }

187

class AuthStrategy:

188

"""Base authentication strategy"""

189

190

def get_auth_string(self) -> str:

191

"""

192

Generate authentication string.

193

194

Returns:

195

str: Authentication header value

196

"""

197

raise NotImplementedError

198

199

class TokenAuthStrategy(AuthStrategy):

200

"""Token-based authentication (Basic Auth with Account SID/Auth Token)"""

201

202

def __init__(self, username: str, password: str):

203

"""

204

Args:

205

username (str): Account SID or API Key SID

206

password (str): Auth Token or API Key Secret

207

"""

208

self.username = username

209

self.password = password

210

211

def get_auth_string(self) -> str:

212

"""Generate Basic Auth header value"""

213

214

class NoAuthStrategy(AuthStrategy):

215

"""No authentication strategy"""

216

217

def get_auth_string(self) -> str:

218

"""Return empty auth string"""

219

return ''

220

221

class AuthType:

222

"""Authentication type enumeration"""

223

BASIC = 'basic'

224

TOKEN = 'token'

225

OAUTH = 'oauth'

226

```

227

228

### Credential Providers

229

230

Alternative authentication mechanisms for advanced scenarios.

231

232

```python { .api }

233

class CredentialProvider:

234

"""Base credential provider"""

235

236

def get_headers(self) -> dict:

237

"""

238

Get authentication headers.

239

240

Returns:

241

dict: HTTP headers for authentication

242

"""

243

raise NotImplementedError

244

245

def get_username(self) -> str:

246

"""Get username for basic auth"""

247

raise NotImplementedError

248

249

def get_password(self) -> str:

250

"""Get password for basic auth"""

251

raise NotImplementedError

252

253

class ClientCredentialProvider(CredentialProvider):

254

"""OAuth 2.0 Client Credentials flow provider"""

255

256

def __init__(

257

self,

258

client_id: str,

259

client_secret: str,

260

token_endpoint: str,

261

scopes: list = None

262

):

263

"""

264

Args:

265

client_id (str): OAuth client ID

266

client_secret (str): OAuth client secret

267

token_endpoint (str): Token endpoint URL

268

scopes (list): Requested scopes

269

"""

270

271

class OrgsCredentialProvider(CredentialProvider):

272

"""Organization-based credential provider"""

273

274

def __init__(

275

self,

276

client_id: str,

277

client_secret: str,

278

account_sid: str,

279

orgs_token_endpoint: str = None

280

):

281

"""

282

Args:

283

client_id (str): Client ID

284

client_secret (str): Client secret

285

account_sid (str): Target account SID

286

orgs_token_endpoint (str): Organizations token endpoint

287

"""

288

```

289

290

### Base Resource Classes

291

292

Foundational classes for REST API resource management.

293

294

```python { .api }

295

class ClientBase:

296

"""Base client implementation"""

297

298

def __init__(

299

self,

300

username: str = None,

301

password: str = None,

302

account_sid: str = None,

303

region: str = None,

304

http_client: HttpClient = None,

305

environment: dict = None,

306

edge: str = None

307

): ...

308

309

class Domain:

310

"""Service domain base class"""

311

312

def __init__(self, twilio: ClientBase):

313

self.twilio = twilio

314

self.base_url = None

315

316

def request(

317

self,

318

method: str,

319

uri: str,

320

data: dict = None,

321

headers: dict = None

322

) -> Response:

323

"""Make authenticated request to domain"""

324

325

class Version:

326

"""API version handling"""

327

328

def __init__(self, domain: Domain, version: str = None):

329

self.domain = domain

330

self.version = version

331

332

def request(

333

self,

334

method: str,

335

uri: str,

336

data: dict = None,

337

headers: dict = None

338

) -> Response:

339

"""Make versioned API request"""

340

341

class InstanceResource:

342

"""Individual resource instance"""

343

344

def __init__(self, version: Version, payload: dict, **kwargs):

345

self._version = version

346

self._properties = payload

347

348

def fetch(self) -> 'InstanceResource':

349

"""Fetch latest resource data"""

350

351

def delete(self) -> bool:

352

"""Delete the resource"""

353

354

def update(self, **kwargs) -> 'InstanceResource':

355

"""Update the resource"""

356

357

class ListResource:

358

"""Resource collection"""

359

360

def __init__(self, version: Version):

361

self._version = version

362

363

def create(self, **kwargs) -> InstanceResource:

364

"""Create new resource instance"""

365

366

def list(self, limit: int = None, page_size: int = None) -> Iterator[InstanceResource]:

367

"""List resource instances"""

368

369

def stream(self, limit: int = None, page_size: int = None) -> Iterator[InstanceResource]:

370

"""Stream resource instances"""

371

372

class InstanceContext:

373

"""Resource context for operations"""

374

375

def __init__(self, version: Version, payload: dict, **kwargs):

376

self._version = version

377

self._properties = payload

378

379

def fetch(self) -> InstanceResource:

380

"""Fetch resource instance"""

381

382

def delete(self) -> bool:

383

"""Delete resource"""

384

385

def update(self, **kwargs) -> InstanceResource:

386

"""Update resource"""

387

388

class Page:

389

"""Paginated results container"""

390

391

def __init__(self, version: Version, response: Response):

392

self._version = version

393

self._response = response

394

395

def get_instance(self, payload: dict) -> InstanceResource:

396

"""Convert payload to resource instance"""

397

398

def get_instances(self) -> list:

399

"""Get all instances from page"""

400

401

def next_page_uri(self) -> str:

402

"""Get URI for next page"""

403

404

def previous_page_uri(self) -> str:

405

"""Get URI for previous page"""

406

```

407

408

### Exception Handling

409

410

Comprehensive exception hierarchy for error handling.

411

412

```python { .api }

413

class TwilioException(Exception):

414

"""Base exception for all Twilio errors"""

415

416

def __init__(self, message: str):

417

self.message = message

418

super().__init__(message)

419

420

class TwilioRestException(TwilioException):

421

"""REST API error with detailed information"""

422

423

def __init__(

424

self,

425

status: int,

426

uri: str,

427

message: str = None,

428

code: int = None,

429

method: str = 'GET',

430

details: dict = None

431

):

432

"""

433

Args:

434

status (int): HTTP status code

435

uri (str): Request URI that failed

436

message (str): Error message

437

code (int): Twilio error code

438

method (str): HTTP method

439

details (dict): Additional error details

440

"""

441

self.status = status

442

self.uri = uri

443

self.code = code

444

self.method = method

445

self.details = details or {}

446

self.more_info = f"https://www.twilio.com/docs/errors/{code}" if code else None

447

448

super().__init__(message or f"HTTP {status} error")

449

450

class TwilioHttpException(TwilioException):

451

"""HTTP transport layer error"""

452

453

def __init__(self, message: str):

454

super().__init__(message)

455

```

456

457

### Utility Classes

458

459

Helper classes for parameter handling and data serialization.

460

461

```python { .api }

462

class Values:

463

"""Parameter value container with special handling"""

464

465

def __init__(self, data: dict = None):

466

self._data = data or {}

467

468

def __getitem__(self, key: str):

469

return self._data.get(key)

470

471

def __setitem__(self, key: str, value):

472

if value is not None:

473

self._data[key] = value

474

475

def of(self, data: dict) -> 'Values':

476

"""Create Values instance from dict"""

477

return Values(data)

478

479

# Serialization utilities

480

def serialize_object(obj) -> str:

481

"""Serialize object to string representation"""

482

483

def serialize_list_object(obj_list: list, separator: str = ',') -> str:

484

"""Serialize list of objects to string"""

485

486

def deserialize_rfc2822_datetime(date_string: str) -> datetime:

487

"""Parse RFC2822 formatted datetime string"""

488

489

def deserialize_iso8601_datetime(date_string: str) -> datetime:

490

"""Parse ISO8601 formatted datetime string"""

491

492

def deserialize_integer(value: str) -> int:

493

"""Parse string to integer"""

494

495

def deserialize_decimal(value: str) -> Decimal:

496

"""Parse string to decimal"""

497

498

def deserialize_boolean(value: str) -> bool:

499

"""Parse string to boolean"""

500

501

def prefixed_collapsible_map(data: dict, prefix: str) -> dict:

502

"""Convert prefixed dictionary to collapsible format"""

503

504

def map_properties(data: dict) -> dict:

505

"""Map dictionary properties for API serialization"""

506

```

507

508

## Custom HTTP Client Example

509

510

```python

511

from twilio.http.http_client import HttpClient

512

from twilio.http.response import Response

513

import requests

514

515

class CustomHttpClient(HttpClient):

516

"""Custom HTTP client with additional logging"""

517

518

def __init__(self, timeout=60, retries=3):

519

self.timeout = timeout

520

self.retries = retries

521

self.session = requests.Session()

522

523

def request(self, method, uri, data=None, headers=None, auth=None, **kwargs):

524

print(f"Making {method} request to {uri}")

525

526

response = self.session.request(

527

method=method,

528

url=uri,

529

data=data,

530

headers=headers,

531

auth=auth,

532

timeout=self.timeout,

533

**kwargs

534

)

535

536

print(f"Response status: {response.status_code}")

537

538

return Response(

539

status_code=response.status_code,

540

text=response.text,

541

headers=dict(response.headers)

542

)

543

544

# Use custom client

545

from twilio.rest import Client

546

547

custom_client = CustomHttpClient(timeout=30)

548

client = Client(

549

'ACxxxxx',

550

'auth_token',

551

http_client=custom_client

552

)

553

```

554

555

## Error Handling Patterns

556

557

```python

558

from twilio.base.exceptions import TwilioRestException, TwilioException

559

560

try:

561

message = client.messages.create(

562

body="Test message",

563

from_="+15551234567",

564

to="invalid_number"

565

)

566

except TwilioRestException as e:

567

print(f"Twilio API Error:")

568

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

569

print(f" Code: {e.code}")

570

print(f" Message: {e.message}")

571

print(f" URI: {e.uri}")

572

print(f" More info: {e.more_info}")

573

574

# Handle specific error codes

575

if e.code == 21211:

576

print("Invalid 'To' phone number")

577

elif e.code == 21608:

578

print("Number not owned by account")

579

580

except TwilioException as e:

581

print(f"General Twilio error: {e.message}")

582

except Exception as e:

583

print(f"Unexpected error: {str(e)}")

584

```