or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

exceptions-utilities.mdfiltering.mdindex.mdpagination.mdrelations.mdrenderers-parsers.mdserializers.mdviews.md

exceptions-utilities.mddocs/

0

# Exception Handling and Utilities

1

2

JSON:API compliant error formatting, field name formatting utilities, resource type management, and settings configuration for customizing JSON:API behavior.

3

4

## Capabilities

5

6

### Exception Handling

7

8

#### exception_handler

9

10

Main exception handler that converts Django REST framework errors to JSON:API format.

11

12

```python { .api }

13

def exception_handler(exc, context):

14

"""

15

JSON:API compliant exception handler.

16

17

Converts Django REST framework exceptions to JSON:API error format

18

with proper error objects containing status, detail, and source information.

19

20

Args:

21

exc: Exception instance

22

context: Exception context with view and request information

23

24

Returns:

25

Response: JSON:API formatted error response or None

26

"""

27

```

28

29

Usage example:

30

31

```python

32

# settings.py

33

REST_FRAMEWORK = {

34

'EXCEPTION_HANDLER': 'rest_framework_json_api.exceptions.exception_handler',

35

}

36

37

# Validation errors become:

38

# {

39

# "errors": [{

40

# "status": "400",

41

# "detail": "This field is required.",

42

# "source": {"pointer": "/data/attributes/title"}

43

# }]

44

# }

45

46

# Permission errors become:

47

# {

48

# "errors": [{

49

# "status": "403",

50

# "detail": "You do not have permission to perform this action."

51

# }]

52

# }

53

```

54

55

#### rendered_with_json_api

56

57

Utility function to check if a view uses JSON:API renderer.

58

59

```python { .api }

60

def rendered_with_json_api(view):

61

"""

62

Check if view is rendered with JSON:API renderer.

63

64

Args:

65

view: View instance

66

67

Returns:

68

bool: True if view uses JSONRenderer

69

"""

70

```

71

72

#### Conflict

73

74

HTTP 409 Conflict exception for JSON:API responses.

75

76

```python { .api }

77

class Conflict(exceptions.APIException):

78

"""

79

HTTP 409 Conflict exception.

80

81

Used for resource conflicts in JSON:API applications.

82

"""

83

84

status_code = 409

85

default_detail = "Conflict."

86

```

87

88

Usage example:

89

90

```python

91

from rest_framework_json_api.exceptions import Conflict

92

93

def update_article(self, instance, validated_data):

94

if instance.locked:

95

raise Conflict("Article is locked and cannot be modified.")

96

return super().update(instance, validated_data)

97

```

98

99

### Utilities

100

101

#### Resource Name and Type Management

102

103

```python { .api }

104

def get_resource_name(context, expand_polymorphic_types=False):

105

"""

106

Get resource name from view context.

107

108

Args:

109

context: Serializer context with view and request

110

expand_polymorphic_types: Whether to expand polymorphic types

111

112

Returns:

113

str or list: Resource name or list of polymorphic types

114

"""

115

116

def get_resource_type_from_model(model):

117

"""

118

Get resource type from Django model.

119

120

Args:

121

model: Django model class

122

123

Returns:

124

str: Resource type name

125

"""

126

127

def get_resource_type_from_serializer(serializer):

128

"""

129

Get resource type from serializer.

130

131

Args:

132

serializer: Serializer instance or class

133

134

Returns:

135

str: Resource type name

136

"""

137

138

def get_resource_type_from_instance(instance):

139

"""

140

Get resource type from model instance.

141

142

Args:

143

instance: Django model instance

144

145

Returns:

146

str: Resource type name

147

"""

148

149

def get_resource_type_from_queryset(queryset):

150

"""

151

Get resource type from QuerySet.

152

153

Args:

154

queryset: Django QuerySet

155

156

Returns:

157

str: Resource type name

158

"""

159

```

160

161

#### Field Name Formatting

162

163

```python { .api }

164

def format_field_names(obj, format_type=None):

165

"""

166

Format all field names in an object.

167

168

Args:

169

obj: Dict or object with field names to format

170

format_type: Format type override

171

172

Returns:

173

dict: Object with formatted field names

174

"""

175

176

def format_field_name(value, format_type=None):

177

"""

178

Format a single field name.

179

180

Args:

181

value: Field name to format

182

format_type: Format type override

183

184

Returns:

185

str: Formatted field name

186

"""

187

188

def undo_format_field_names(obj):

189

"""

190

Reverse field name formatting.

191

192

Args:

193

obj: Dict with formatted field names

194

195

Returns:

196

dict: Object with original field names

197

"""

198

199

def undo_format_field_name(value):

200

"""

201

Reverse format a single field name.

202

203

Args:

204

value: Formatted field name

205

206

Returns:

207

str: Original field name

208

"""

209

```

210

211

Usage example:

212

213

```python

214

# With JSON_API_FORMAT_FIELD_NAMES = True

215

format_field_name('created_at') # Returns 'created-at'

216

format_field_name('author_name') # Returns 'author-name'

217

218

undo_format_field_name('created-at') # Returns 'created_at'

219

undo_format_field_name('author-name') # Returns 'author_name'

220

```

221

222

#### Resource and Serializer Utilities

223

224

```python { .api }

225

def get_serializer_fields(serializer):

226

"""

227

Get fields from serializer, handling both regular and list serializers.

228

229

Args:

230

serializer: Serializer instance

231

232

Returns:

233

dict or None: Serializer fields

234

"""

235

236

def get_included_resources(request, serializer_class):

237

"""

238

Parse include parameter from request.

239

240

Args:

241

request: HTTP request object

242

serializer_class: Serializer class

243

244

Returns:

245

list: List of include paths

246

"""

247

248

def get_resource_id(resource_instance):

249

"""

250

Get resource ID from instance.

251

252

Args:

253

resource_instance: Model instance

254

255

Returns:

256

str: Resource ID

257

"""

258

```

259

260

#### Error Formatting

261

262

```python { .api }

263

def format_errors(data):

264

"""

265

Format errors in JSON:API format.

266

267

Args:

268

data: Error data to format

269

270

Returns:

271

dict: JSON:API formatted errors

272

"""

273

274

def format_drf_errors(response, context, exc):

275

"""

276

Format Django REST framework errors as JSON:API errors.

277

278

Args:

279

response: DRF error response

280

context: Exception context

281

exc: Exception instance

282

283

Returns:

284

Response: JSON:API formatted error response

285

"""

286

```

287

288

#### Hyperlink Support

289

290

```python { .api }

291

class Hyperlink:

292

"""

293

Hyperlink representation for JSON:API links.

294

295

Represents hyperlinks in JSON:API responses with href and meta.

296

"""

297

298

def __init__(self, href, meta=None):

299

"""

300

Initialize hyperlink.

301

302

Args:

303

href: Link URL

304

meta: Optional link metadata

305

"""

306

self.href = href

307

self.meta = meta

308

```

309

310

### Metadata

311

312

#### JSONAPIMetadata

313

314

JSON:API metadata implementation for OPTIONS requests.

315

316

```python { .api }

317

class JSONAPIMetadata(SimpleMetadata):

318

"""

319

JSON:API metadata implementation for OPTIONS responses.

320

321

Provides field information and relationship metadata

322

in a JSON:API compatible format.

323

"""

324

325

type_lookup = {

326

# Field type mappings for metadata

327

}

328

329

relation_type_lookup = {

330

# Relationship type mappings

331

}

332

333

def determine_metadata(self, request, view):

334

"""

335

Generate metadata for view.

336

337

Args:

338

request: HTTP request

339

view: View instance

340

341

Returns:

342

dict: Metadata information

343

"""

344

```

345

346

### Settings

347

348

#### JSONAPISettings

349

350

Settings management class for JSON:API configuration.

351

352

```python { .api }

353

class JSONAPISettings:

354

"""

355

Settings object for JSON:API configuration.

356

357

Allows JSON:API settings to be accessed as properties

358

with fallback to defaults.

359

"""

360

361

def __init__(self, user_settings=None, defaults=None):

362

"""

363

Initialize settings.

364

365

Args:

366

user_settings: User-defined settings

367

defaults: Default settings

368

"""

369

370

def __getattr__(self, attr):

371

"""

372

Get setting value with fallback to default.

373

374

Args:

375

attr: Setting name

376

377

Returns:

378

Setting value

379

380

Raises:

381

AttributeError: If setting is invalid

382

"""

383

```

384

385

#### Settings Instance

386

387

```python { .api }

388

json_api_settings = JSONAPISettings()

389

"""Global JSON:API settings instance."""

390

391

def reload_json_api_settings(*args, **kwargs):

392

"""

393

Reload JSON:API settings when Django settings change.

394

395

Connected to Django's setting_changed signal.

396

"""

397

```

398

399

### Configuration Options

400

401

Available JSON:API settings:

402

403

```python

404

# settings.py

405

JSON_API_FORMAT_FIELD_NAMES = True # Convert snake_case to kebab-case

406

JSON_API_FORMAT_TYPES = True # Format resource type names

407

JSON_API_FORMAT_RELATED_LINKS = True # Format related link segments

408

JSON_API_PLURALIZE_TYPES = True # Pluralize resource type names

409

JSON_API_UNIFORM_EXCEPTIONS = True # Use JSON:API errors everywhere

410

```

411

412

#### FORMAT_FIELD_NAMES

413

414

```python

415

# When True:

416

# Model field: created_at -> JSON:API: "created-at"

417

# Model field: author_name -> JSON:API: "author-name"

418

419

# When False:

420

# Model field: created_at -> JSON:API: "created_at"

421

# Model field: author_name -> JSON:API: "author_name"

422

```

423

424

#### FORMAT_TYPES

425

426

```python

427

# When True:

428

# Model: BlogPost -> Resource type: "blog-posts"

429

# Model: UserProfile -> Resource type: "user-profiles"

430

431

# When False:

432

# Model: BlogPost -> Resource type: "BlogPost"

433

# Model: UserProfile -> Resource type: "UserProfile"

434

```

435

436

#### PLURALIZE_TYPES

437

438

```python

439

# When True:

440

# Model: Article -> Resource type: "articles"

441

# Model: Category -> Resource type: "categories"

442

443

# When False:

444

# Model: Article -> Resource type: "article"

445

# Model: Category -> Resource type: "category"

446

```

447

448

#### UNIFORM_EXCEPTIONS

449

450

```python

451

# When True: All views use JSON:API error format

452

# When False: Only JSON:API views use JSON:API error format

453

```

454

455

## Error Response Format

456

457

JSON:API error responses follow this structure:

458

459

```python

460

{

461

"errors": [

462

{

463

"id": "unique-error-id", # Optional

464

"status": "400", # HTTP status code

465

"code": "validation_error", # Application-specific error code

466

"title": "Validation Error", # Human-readable title

467

"detail": "This field is required.", # Detailed error message

468

"source": { # Error source information

469

"pointer": "/data/attributes/title", # JSON Pointer to error location

470

"parameter": "filter[invalid]" # Query parameter that caused error

471

},

472

"meta": { # Additional metadata

473

"field": "title"

474

}

475

}

476

]

477

}

478

```

479

480

## Common Error Examples

481

482

### Validation Errors

483

484

```python

485

# Field validation error

486

{

487

"errors": [{

488

"status": "400",

489

"detail": "This field is required.",

490

"source": {"pointer": "/data/attributes/title"}

491

}]

492

}

493

494

# Relationship validation error

495

{

496

"errors": [{

497

"status": "400",

498

"detail": "Invalid pk \"999\" - object does not exist.",

499

"source": {"pointer": "/data/relationships/author"}

500

}]

501

}

502

```

503

504

### Authentication/Permission Errors

505

506

```python

507

# Authentication required

508

{

509

"errors": [{

510

"status": "401",

511

"detail": "Authentication credentials were not provided."

512

}]

513

}

514

515

# Permission denied

516

{

517

"errors": [{

518

"status": "403",

519

"detail": "You do not have permission to perform this action."

520

}]

521

}

522

```

523

524

### Not Found Errors

525

526

```python

527

{

528

"errors": [{

529

"status": "404",

530

"detail": "Not found."

531

}]

532

}

533

```

534

535

## Types

536

537

```python { .api }

538

from rest_framework_json_api.exceptions import (

539

exception_handler,

540

rendered_with_json_api,

541

Conflict

542

)

543

544

from rest_framework_json_api.utils import (

545

get_resource_name,

546

get_resource_type_from_model,

547

get_resource_type_from_serializer,

548

get_resource_type_from_instance,

549

format_field_names,

550

format_field_name,

551

undo_format_field_names,

552

undo_format_field_name,

553

get_serializer_fields,

554

get_included_resources,

555

format_errors,

556

format_drf_errors,

557

Hyperlink

558

)

559

560

from rest_framework_json_api.metadata import JSONAPIMetadata

561

from rest_framework_json_api.settings import (

562

JSONAPISettings,

563

json_api_settings,

564

reload_json_api_settings

565

)

566

```