or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdcore-annotations.mdindex.mdresponses.mdschema-media.mdsecurity.mdservers-tags.md

advanced-features.mddocs/

0

# Advanced Features

1

2

This document covers advanced OpenAPI annotations including extensions, callbacks for asynchronous operations, webhooks, links between operations, and OpenAPI 3.1 enhanced features.

3

4

## Imports

5

6

```java { .api }

7

import io.swagger.v3.oas.annotations.extensions.Extension;

8

import io.swagger.v3.oas.annotations.extensions.Extensions;

9

import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;

10

import io.swagger.v3.oas.annotations.callbacks.Callback;

11

import io.swagger.v3.oas.annotations.callbacks.Callbacks;

12

import io.swagger.v3.oas.annotations.Webhook;

13

import io.swagger.v3.oas.annotations.Webhooks;

14

import io.swagger.v3.oas.annotations.links.Link;

15

import io.swagger.v3.oas.annotations.links.LinkParameter;

16

import io.swagger.v3.oas.annotations.headers.Header;

17

import io.swagger.v3.oas.annotations.OpenAPI31;

18

```

19

20

## Extensions

21

22

OpenAPI extensions allow you to add vendor-specific or custom properties to your API specification using the `x-` prefix convention.

23

24

### Basic Extensions

25

26

```java { .api }

27

@Operation(

28

summary = "Get pet by ID",

29

extensions = {

30

@Extension(name = "x-rate-limit", properties = {

31

@ExtensionProperty(name = "requests", value = "100"),

32

@ExtensionProperty(name = "period", value = "minute")

33

}),

34

@Extension(name = "x-cache-duration", properties = {

35

@ExtensionProperty(name = "seconds", value = "300")

36

})

37

}

38

)

39

@GetMapping("/pets/{id}")

40

public ResponseEntity<Pet> getPetById(@PathVariable Long id) {

41

return ResponseEntity.ok(petService.findById(id));

42

}

43

```

44

45

### Schema Extensions

46

47

```java { .api }

48

@Schema(

49

description = "Pet information with enhanced metadata",

50

extensions = {

51

@Extension(name = "x-data-classification", properties = {

52

@ExtensionProperty(name = "level", value = "public"),

53

@ExtensionProperty(name = "retention", value = "7-years"),

54

@ExtensionProperty(name = "pii", value = "false")

55

}),

56

@Extension(name = "x-validation-rules", properties = {

57

@ExtensionProperty(name = "custom-validator", value = "PetNameValidator"),

58

@ExtensionProperty(name = "business-rules", value = "no-duplicate-names-per-owner")

59

}),

60

@Extension(name = "x-ui-hints", properties = {

61

@ExtensionProperty(name = "display-order", value = "name,category,status,tags"),

62

@ExtensionProperty(name = "required-highlight", value = "true"),

63

@ExtensionProperty(name = "collapse-advanced", value = "true")

64

})

65

}

66

)

67

public class Pet {

68

@Schema(

69

description = "Pet name",

70

extensions = {

71

@Extension(name = "x-input-validation", properties = {

72

@ExtensionProperty(name = "trim-whitespace", value = "true"),

73

@ExtensionProperty(name = "capitalize-first", value = "true")

74

})

75

}

76

)

77

private String name;

78

79

@Schema(

80

description = "Pet status",

81

extensions = {

82

@Extension(name = "x-state-machine", properties = {

83

@ExtensionProperty(name = "transitions", value = "available->pending,pending->sold,sold->available"),

84

@ExtensionProperty(name = "initial-state", value = "available")

85

})

86

}

87

)

88

private String status;

89

}

90

```

91

92

### API-Level Extensions

93

94

```java { .api }

95

@OpenAPIDefinition(

96

info = @Info(

97

title = "Pet Store API with Advanced Features",

98

version = "1.0.0",

99

extensions = {

100

@Extension(name = "x-api-capabilities", properties = {

101

@ExtensionProperty(name = "real-time", value = "webhooks,sse"),

102

@ExtensionProperty(name = "batch-operations", value = "supported"),

103

@ExtensionProperty(name = "async-processing", value = "callbacks")

104

}),

105

@Extension(name = "x-service-level", properties = {

106

@ExtensionProperty(name = "availability", value = "99.9%"),

107

@ExtensionProperty(name = "response-time-p95", value = "200ms"),

108

@ExtensionProperty(name = "throughput", value = "1000-rps")

109

})

110

}

111

),

112

extensions = {

113

@Extension(name = "x-monetization", properties = {

114

@ExtensionProperty(name = "pricing-model", value = "usage-based"),

115

@ExtensionProperty(name = "billing-cycle", value = "monthly"),

116

@ExtensionProperty(name = "free-tier", value = "1000-requests")

117

}),

118

@Extension(name = "x-compliance", properties = {

119

@ExtensionProperty(name = "gdpr", value = "compliant"),

120

@ExtensionProperty(name = "soc2", value = "type-2"),

121

@ExtensionProperty(name = "pci-dss", value = "level-1")

122

})

123

}

124

)

125

```

126

127

### Server Extensions

128

129

```java { .api }

130

@Server(

131

url = "https://api.petstore.io/v1",

132

description = "Production server with enhanced features",

133

extensions = {

134

@Extension(name = "x-server-capabilities", properties = {

135

@ExtensionProperty(name = "websockets", value = "supported"),

136

@ExtensionProperty(name = "server-sent-events", value = "supported"),

137

@ExtensionProperty(name = "graphql", value = "/graphql"),

138

@ExtensionProperty(name = "grpc", value = "api.petstore.io:443")

139

}),

140

@Extension(name = "x-infrastructure", properties = {

141

@ExtensionProperty(name = "provider", value = "aws"),

142

@ExtensionProperty(name = "region", value = "us-east-1"),

143

@ExtensionProperty(name = "load-balancer", value = "application"),

144

@ExtensionProperty(name = "cdn", value = "cloudfront")

145

})

146

}

147

)

148

```

149

150

## Callbacks

151

152

Define callback requests that your API will make to client-provided URLs, typically for asynchronous operations and event notifications.

153

154

### Basic Callback Configuration

155

156

```java { .api }

157

@PostMapping("/pets/{id}/process")

158

@Operation(

159

summary = "Start pet processing",

160

description = "Initiates asynchronous pet processing and calls back when complete",

161

callbacks = @Callback(

162

name = "processingComplete",

163

callbackUrlExpression = "{$request.body#/callbackUrl}",

164

operation = @Operation(

165

method = "POST",

166

summary = "Processing completion notification",

167

requestBody = @RequestBody(

168

description = "Processing results",

169

content = @Content(

170

mediaType = "application/json",

171

schema = @Schema(implementation = ProcessingResult.class)

172

)

173

),

174

responses = {

175

@ApiResponse(

176

responseCode = "200",

177

description = "Callback received successfully"

178

),

179

@ApiResponse(

180

responseCode = "400",

181

description = "Invalid callback data"

182

)

183

}

184

)

185

)

186

)

187

public ResponseEntity<ProcessingRequest> startProcessing(

188

@PathVariable Long id,

189

@RequestBody ProcessingRequest request

190

) {

191

// Start async processing

192

ProcessingRequest response = petService.startProcessing(id, request);

193

return ResponseEntity.accepted().body(response);

194

}

195

```

196

197

### Multiple Callbacks with Different Events

198

199

```java { .api }

200

@PostMapping("/orders")

201

@Operation(

202

summary = "Create order with status notifications",

203

callbacks = {

204

@Callback(

205

name = "orderStatusUpdate",

206

callbackUrlExpression = "{$request.body#/webhooks.statusUpdate}",

207

operation = @Operation(

208

method = "POST",

209

summary = "Order status change notification",

210

requestBody = @RequestBody(

211

content = @Content(

212

mediaType = "application/json",

213

schema = @Schema(implementation = OrderStatusEvent.class)

214

)

215

),

216

responses = @ApiResponse(responseCode = "200", description = "Status update received")

217

)

218

),

219

@Callback(

220

name = "paymentProcessed",

221

callbackUrlExpression = "{$request.body#/webhooks.payment}",

222

operation = @Operation(

223

method = "POST",

224

summary = "Payment processing notification",

225

requestBody = @RequestBody(

226

content = @Content(

227

mediaType = "application/json",

228

schema = @Schema(implementation = PaymentEvent.class)

229

)

230

),

231

responses = @ApiResponse(responseCode = "200", description = "Payment notification received")

232

)

233

),

234

@Callback(

235

name = "deliveryUpdate",

236

callbackUrlExpression = "{$request.body#/webhooks.delivery}",

237

operation = @Operation(

238

method = "POST",

239

summary = "Delivery status notification",

240

requestBody = @RequestBody(

241

content = @Content(

242

mediaType = "application/json",

243

schema = @Schema(implementation = DeliveryEvent.class)

244

)

245

),

246

responses = @ApiResponse(responseCode = "200", description = "Delivery update received")

247

)

248

)

249

}

250

)

251

```

252

253

### Advanced Callback with Authentication

254

255

```java { .api }

256

@PostMapping("/subscriptions")

257

@Operation(

258

summary = "Create webhook subscription",

259

callbacks = @Callback(

260

name = "webhookEvent",

261

callbackUrlExpression = "{$request.body#/targetUrl}",

262

operation = @Operation(

263

method = "POST",

264

summary = "Webhook event notification",

265

description = "Called when subscribed events occur",

266

security = @SecurityRequirement(name = "webhook_signature"),

267

parameters = {

268

@Parameter(

269

name = "X-Webhook-Signature",

270

in = ParameterIn.HEADER,

271

description = "HMAC signature for webhook verification",

272

required = true,

273

schema = @Schema(type = "string")

274

),

275

@Parameter(

276

name = "X-Event-Type",

277

in = ParameterIn.HEADER,

278

description = "Type of event being delivered",

279

required = true,

280

schema = @Schema(type = "string", allowableValues = {

281

"pet.created", "pet.updated", "pet.deleted",

282

"order.placed", "order.shipped", "order.delivered"

283

})

284

),

285

@Parameter(

286

name = "X-Delivery-ID",

287

in = ParameterIn.HEADER,

288

description = "Unique delivery attempt identifier",

289

required = true,

290

schema = @Schema(type = "string", format = "uuid")

291

)

292

},

293

requestBody = @RequestBody(

294

description = "Event payload",

295

content = @Content(

296

mediaType = "application/json",

297

schema = @Schema(implementation = WebhookEvent.class),

298

examples = {

299

@ExampleObject(

300

name = "petCreated",

301

summary = "Pet created event",

302

value = """

303

{

304

"eventType": "pet.created",

305

"timestamp": "2024-01-15T10:30:00Z",

306

"data": {

307

"id": 123,

308

"name": "Fluffy",

309

"status": "available"

310

}

311

}

312

"""

313

)

314

}

315

)

316

),

317

responses = {

318

@ApiResponse(

319

responseCode = "200",

320

description = "Webhook processed successfully"

321

),

322

@ApiResponse(

323

responseCode = "400",

324

description = "Invalid webhook payload"

325

),

326

@ApiResponse(

327

responseCode = "401",

328

description = "Invalid webhook signature"

329

)

330

}

331

)

332

)

333

)

334

```

335

336

## Webhooks

337

338

Document webhook endpoints that clients can implement to receive notifications from your API.

339

340

### Basic Webhook Definition

341

342

```java { .api }

343

@Webhook(

344

name = "petUpdated",

345

operation = @Operation(

346

method = "POST",

347

summary = "Pet update notification",

348

description = "Called when a pet's information is updated",

349

requestBody = @RequestBody(

350

description = "Pet update event data",

351

content = @Content(

352

mediaType = "application/json",

353

schema = @Schema(implementation = PetUpdateEvent.class)

354

)

355

),

356

responses = {

357

@ApiResponse(responseCode = "200", description = "Webhook acknowledged"),

358

@ApiResponse(responseCode = "410", description = "Webhook endpoint no longer exists")

359

}

360

)

361

)

362

```

363

364

### Multiple Webhook Events

365

366

```java { .api }

367

@Webhooks({

368

@Webhook(

369

name = "petLifecycle",

370

operation = @Operation(

371

summary = "Pet lifecycle events",

372

description = "Notifications for pet creation, updates, and deletion",

373

requestBody = @RequestBody(

374

content = @Content(

375

mediaType = "application/json",

376

schema = @Schema(implementation = PetLifecycleEvent.class),

377

examples = {

378

@ExampleObject(

379

name = "created",

380

summary = "Pet created",

381

value = """

382

{

383

"event": "pet.created",

384

"timestamp": "2024-01-15T10:30:00Z",

385

"pet": {

386

"id": 123,

387

"name": "New Pet",

388

"status": "available"

389

}

390

}

391

"""

392

),

393

@ExampleObject(

394

name = "updated",

395

summary = "Pet updated",

396

value = """

397

{

398

"event": "pet.updated",

399

"timestamp": "2024-01-15T10:35:00Z",

400

"pet": {

401

"id": 123,

402

"name": "Updated Pet",

403

"status": "sold"

404

},

405

"changes": ["name", "status"]

406

}

407

"""

408

)

409

}

410

)

411

)

412

)

413

),

414

@Webhook(

415

name = "orderStatus",

416

operation = @Operation(

417

summary = "Order status changes",

418

description = "Notifications when order status changes",

419

requestBody = @RequestBody(

420

content = @Content(

421

mediaType = "application/json",

422

schema = @Schema(implementation = OrderStatusEvent.class)

423

)

424

)

425

)

426

),

427

@Webhook(

428

name = "inventoryAlert",

429

operation = @Operation(

430

summary = "Inventory level alerts",

431

description = "Notifications when inventory reaches threshold levels",

432

requestBody = @RequestBody(

433

content = @Content(

434

mediaType = "application/json",

435

schema = @Schema(implementation = InventoryAlert.class)

436

)

437

)

438

)

439

)

440

})

441

```

442

443

### Webhook with Security and Headers

444

445

```java { .api }

446

@Webhook(

447

name = "secureWebhook",

448

operation = @Operation(

449

summary = "Secure webhook with authentication",

450

description = "Webhook with signature verification and custom headers",

451

parameters = {

452

@Parameter(

453

name = "X-Webhook-Signature",

454

in = ParameterIn.HEADER,

455

required = true,

456

description = "HMAC-SHA256 signature of the payload",

457

schema = @Schema(type = "string"),

458

example = "sha256=a8b7c6d5e4f3g2h1..."

459

),

460

@Parameter(

461

name = "X-Event-ID",

462

in = ParameterIn.HEADER,

463

required = true,

464

description = "Unique event identifier for deduplication",

465

schema = @Schema(type = "string", format = "uuid")

466

),

467

@Parameter(

468

name = "X-Retry-Count",

469

in = ParameterIn.HEADER,

470

required = false,

471

description = "Number of delivery attempts (starts at 0)",

472

schema = @Schema(type = "integer", minimum = "0", maximum = "5")

473

)

474

},

475

requestBody = @RequestBody(

476

description = "Signed webhook payload",

477

content = @Content(

478

mediaType = "application/json",

479

schema = @Schema(implementation = SecureWebhookEvent.class)

480

)

481

),

482

responses = {

483

@ApiResponse(

484

responseCode = "200",

485

description = "Webhook processed successfully"

486

),

487

@ApiResponse(

488

responseCode = "401",

489

description = "Invalid signature",

490

content = @Content(

491

mediaType = "application/json",

492

schema = @Schema(implementation = WebhookError.class)

493

)

494

),

495

@ApiResponse(

496

responseCode = "409",

497

description = "Duplicate event (already processed)"

498

),

499

@ApiResponse(

500

responseCode = "422",

501

description = "Valid signature but invalid payload"

502

)

503

}

504

)

505

)

506

```

507

508

### Webhook Attributes

509

510

```java { .api }

511

public @interface Webhook {

512

String name(); // Required - Name of the webhook

513

Operation operation(); // Required - Operation definition for the webhook

514

}

515

516

public @interface Webhooks {

517

Webhook[] value() default {}; // Array of Webhook annotations

518

}

519

```

520

521

## Links

522

523

Define relationships between operations, allowing clients to navigate from one operation's response to related operations.

524

525

### Basic Operation Links

526

527

```java { .api }

528

@PostMapping("/pets")

529

@ApiResponse(

530

responseCode = "201",

531

description = "Pet created successfully",

532

content = @Content(

533

mediaType = "application/json",

534

schema = @Schema(implementation = Pet.class)

535

),

536

links = {

537

@Link(

538

name = "GetPetById",

539

description = "Retrieve the newly created pet",

540

operationId = "getPetById",

541

parameters = @LinkParameter(

542

name = "id",

543

expression = "$response.body#/id"

544

)

545

),

546

@Link(

547

name = "UpdatePet",

548

description = "Update the newly created pet",

549

operationId = "updatePet",

550

parameters = @LinkParameter(

551

name = "id",

552

expression = "$response.body#/id"

553

)

554

),

555

@Link(

556

name = "DeletePet",

557

description = "Delete the newly created pet",

558

operationId = "deletePet",

559

parameters = @LinkParameter(

560

name = "id",

561

expression = "$response.body#/id"

562

)

563

)

564

}

565

)

566

public ResponseEntity<Pet> createPet(@RequestBody Pet pet) {

567

Pet createdPet = petService.create(pet);

568

return ResponseEntity.status(HttpStatus.CREATED).body(createdPet);

569

}

570

```

571

572

### Complex Links with Multiple Parameters

573

574

```java { .api }

575

@GetMapping("/users/{userId}/pets")

576

@ApiResponse(

577

responseCode = "200",

578

description = "User's pets retrieved",

579

content = @Content(

580

mediaType = "application/json",

581

schema = @Schema(implementation = PetListResponse.class)

582

),

583

links = {

584

@Link(

585

name = "GetUserProfile",

586

description = "Get full user profile",

587

operationId = "getUserById",

588

parameters = @LinkParameter(

589

name = "id",

590

expression = "$request.path.userId"

591

)

592

),

593

@Link(

594

name = "CreatePetForUser",

595

description = "Create a new pet for this user",

596

operationId = "createPetForUser",

597

parameters = {

598

@LinkParameter(

599

name = "userId",

600

expression = "$request.path.userId"

601

)

602

}

603

),

604

@Link(

605

name = "GetPetDetails",

606

description = "Get details for any pet in the list",

607

operationId = "getPetById",

608

parameters = @LinkParameter(

609

name = "id",

610

expression = "$response.body#/pets/*/id"

611

)

612

),

613

@Link(

614

name = "GetUserOrders",

615

description = "Get orders placed by this user",

616

operationId = "getUserOrders",

617

parameters = @LinkParameter(

618

name = "userId",

619

expression = "$request.path.userId"

620

)

621

)

622

}

623

)

624

```

625

626

### Conditional Links with Extensions

627

628

```java { .api }

629

@GetMapping("/orders/{id}")

630

@ApiResponse(

631

responseCode = "200",

632

description = "Order details",

633

content = @Content(

634

mediaType = "application/json",

635

schema = @Schema(implementation = Order.class)

636

),

637

links = {

638

@Link(

639

name = "CancelOrder",

640

description = "Cancel this order (if cancellable)",

641

operationId = "cancelOrder",

642

parameters = @LinkParameter(

643

name = "id",

644

expression = "$response.body#/id"

645

),

646

extensions = {

647

@Extension(name = "x-conditional", properties = {

648

@ExtensionProperty(name = "condition", value = "$response.body#/status == 'pending'"),

649

@ExtensionProperty(name = "description", value = "Only available for pending orders")

650

})

651

}

652

),

653

@Link(

654

name = "TrackShipment",

655

description = "Track order shipment",

656

operationId = "getShipmentTracking",

657

parameters = @LinkParameter(

658

name = "trackingNumber",

659

expression = "$response.body#/trackingNumber"

660

),

661

extensions = {

662

@Extension(name = "x-conditional", properties = {

663

@ExtensionProperty(name = "condition", value = "$response.body#/status == 'shipped'"),

664

@ExtensionProperty(name = "description", value = "Only available for shipped orders")

665

})

666

}

667

),

668

@Link(

669

name = "RequestReturn",

670

description = "Request return for delivered order",

671

operationId = "createReturnRequest",

672

parameters = @LinkParameter(

673

name = "orderId",

674

expression = "$response.body#/id"

675

),

676

extensions = {

677

@Extension(name = "x-conditional", properties = {

678

@ExtensionProperty(name = "condition", value = "$response.body#/status == 'delivered'"),

679

@ExtensionProperty(name = "timeLimit", value = "30 days from delivery")

680

})

681

}

682

)

683

}

684

)

685

```

686

687

## OpenAPI 3.1 Features

688

689

Leverage enhanced OpenAPI 3.1 capabilities including improved JSON Schema support, conditional schemas, and enhanced validation.

690

691

### OpenAPI 3.1 Marker Usage

692

693

```java { .api }

694

@Schema(

695

description = "Enhanced pet schema with OpenAPI 3.1 features",

696

types = {"object", "null"}, // Multiple types

697

$id = "https://api.petstore.io/schemas/pet.json",

698

$schema = "https://json-schema.org/draft/2020-12/schema"

699

)

700

@OpenAPI31 // Marker for OpenAPI 3.1 specific features

701

public class EnhancedPet {

702

703

@Schema(

704

description = "Pet identifier with enhanced validation",

705

types = {"integer", "string"}, // Can be either integer or string ID

706

pattern = "^(\\d+|[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})$"

707

)

708

@OpenAPI31

709

private String id;

710

711

@Schema(

712

description = "Pet metadata with conditional requirements",

713

_if = @Schema(

714

properties = @SchemaProperty(

715

name = "type",

716

schema = @Schema(allowableValues = "premium")

717

)

718

),

719

_then = @Schema(

720

required = {"certification", "insurance"},

721

properties = {

722

@SchemaProperty(

723

name = "certification",

724

schema = @Schema(type = "string", minLength = 1)

725

),

726

@SchemaProperty(

727

name = "insurance",

728

schema = @Schema(type = "object", required = {"provider", "policyNumber"})

729

)

730

}

731

)

732

)

733

@OpenAPI31

734

private Map<String, Object> metadata;

735

736

@Schema(

737

description = "Pet images with enhanced array validation",

738

prefixItems = {

739

@Schema(description = "Primary image", format = "uri"),

740

@Schema(description = "Thumbnail image", format = "uri")

741

},

742

minContains = 1,

743

maxContains = 3,

744

contains = @Schema(

745

description = "Must contain at least one high-resolution image",

746

properties = @SchemaProperty(

747

name = "resolution",

748

schema = @Schema(allowableValues = "high")

749

)

750

)

751

)

752

@OpenAPI31

753

private List<PetImage> images;

754

}

755

```

756

757

### Conditional Schema Validation

758

759

```java { .api }

760

@Schema(

761

description = "Payment method with conditional validation",

762

discriminatorProperty = "type"

763

)

764

@OpenAPI31

765

public class PaymentMethod {

766

767

@Schema(description = "Payment type")

768

private String type;

769

770

@Schema(

771

description = "Payment details with type-specific validation",

772

_if = @Schema(

773

properties = @SchemaProperty(

774

name = "type",

775

schema = @Schema(allowableValues = "credit_card")

776

)

777

),

778

_then = @Schema(

779

required = {"cardNumber", "expiryDate", "cvv"},

780

properties = {

781

@SchemaProperty(

782

name = "cardNumber",

783

schema = @Schema(type = "string", pattern = "^[0-9]{13,19}$")

784

),

785

@SchemaProperty(

786

name = "expiryDate",

787

schema = @Schema(type = "string", pattern = "^(0[1-9]|1[0-2])\\/[0-9]{2}$")

788

),

789

@SchemaProperty(

790

name = "cvv",

791

schema = @Schema(type = "string", pattern = "^[0-9]{3,4}$")

792

)

793

}

794

),

795

_else = @Schema(

796

_if = @Schema(

797

properties = @SchemaProperty(

798

name = "type",

799

schema = @Schema(allowableValues = "paypal")

800

)

801

),

802

_then = @Schema(

803

required = {"paypalEmail"},

804

properties = @SchemaProperty(

805

name = "paypalEmail",

806

schema = @Schema(type = "string", format = "email")

807

)

808

),

809

_else = @Schema(

810

_if = @Schema(

811

properties = @SchemaProperty(

812

name = "type",

813

schema = @Schema(allowableValues = "bank_transfer")

814

)

815

),

816

_then = @Schema(

817

required = {"accountNumber", "routingNumber"},

818

properties = {

819

@SchemaProperty(

820

name = "accountNumber",

821

schema = @Schema(type = "string", minLength = 8, maxLength = 17)

822

),

823

@SchemaProperty(

824

name = "routingNumber",

825

schema = @Schema(type = "string", pattern = "^[0-9]{9}$")

826

)

827

}

828

)

829

)

830

)

831

)

832

@OpenAPI31

833

private Map<String, Object> details;

834

}

835

```

836

837

### Enhanced Composition with OpenAPI 3.1

838

839

```java { .api }

840

@Content(

841

mediaType = "application/json",

842

oneOf = {

843

@Schema(implementation = StandardUser.class),

844

@Schema(implementation = PremiumUser.class),

845

@Schema(implementation = EnterpriseUser.class)

846

},

847

unevaluatedProperties = @Schema(

848

description = "Additional properties not covered by oneOf schemas",

849

additionalProperties = Schema.AdditionalPropertiesValue.FALSE

850

)

851

)

852

@OpenAPI31

853

public class UserResponse {

854

// Base user properties that apply to all user types

855

}

856

857

@Schema(

858

description = "Dynamic configuration with pattern properties",

859

patternProperties = {

860

@PatternProperty(

861

pattern = "^feature_[a-z]+$",

862

schema = @Schema(

863

type = "object",

864

properties = {

865

@SchemaProperty(name = "enabled", schema = @Schema(type = "boolean")),

866

@SchemaProperty(name = "config", schema = @Schema(type = "object"))

867

}

868

)

869

),

870

@PatternProperty(

871

pattern = "^metric_[a-z_]+$",

872

schema = @Schema(

873

type = "number",

874

minimum = "0"

875

)

876

)

877

},

878

unevaluatedProperties = @Schema(additionalProperties = Schema.AdditionalPropertiesValue.FALSE)

879

)

880

@OpenAPI31

881

public class DynamicConfiguration {

882

// Static configuration properties

883

@Schema(description = "Configuration version")

884

private String version;

885

886

@Schema(description = "Last updated timestamp")

887

private Instant updatedAt;

888

889

// Dynamic properties validated by pattern properties

890

}

891

```

892

893

### Content Encoding and Media Type (OpenAPI 3.1)

894

895

```java { .api }

896

@Schema(

897

description = "File data with encoding information",

898

contentEncoding = "base64",

899

contentMediaType = "image/jpeg",

900

type = "string"

901

)

902

@OpenAPI31

903

public class EncodedFileData {

904

905

@Schema(

906

description = "Base64 encoded image data",

907

contentEncoding = "base64",

908

contentMediaType = "image/jpeg"

909

)

910

private String imageData;

911

912

@Schema(

913

description = "Compressed text data",

914

contentEncoding = "gzip",

915

contentMediaType = "text/plain"

916

)

917

private String compressedText;

918

919

@Schema(

920

description = "Binary file data",

921

contentEncoding = "binary",

922

contentMediaType = "application/octet-stream"

923

)

924

private String binaryData;

925

}

926

```

927

928

## Complete Advanced Features Example

929

930

```java { .api }

931

@RestController

932

@OpenAPIDefinition(

933

info = @Info(

934

title = "Advanced Pet Store API",

935

version = "3.1.0",

936

extensions = {

937

@Extension(name = "x-api-features", properties = {

938

@ExtensionProperty(name = "webhooks", value = "supported"),

939

@ExtensionProperty(name = "callbacks", value = "supported"),

940

@ExtensionProperty(name = "openapi-version", value = "3.1")

941

})

942

}

943

)

944

)

945

@Webhooks({

946

@Webhook(

947

name = "petStatusChanged",

948

operation = @Operation(

949

summary = "Pet status change notification",

950

requestBody = @RequestBody(

951

content = @Content(

952

mediaType = "application/json",

953

schema = @Schema(implementation = PetStatusEvent.class)

954

)

955

)

956

)

957

)

958

})

959

public class AdvancedPetStoreController {

960

961

@PostMapping("/pets/async-process")

962

@Operation(

963

summary = "Start asynchronous pet processing",

964

extensions = {

965

@Extension(name = "x-processing-type", properties = {

966

@ExtensionProperty(name = "type", value = "asynchronous"),

967

@ExtensionProperty(name = "estimated-duration", value = "5-10 minutes")

968

})

969

},

970

callbacks = @Callback(

971

name = "processingComplete",

972

callbackUrlExpression = "{$request.body#/callbackUrl}",

973

operation = @Operation(

974

method = "POST",

975

summary = "Processing completion callback",

976

requestBody = @RequestBody(

977

content = @Content(

978

mediaType = "application/json",

979

schema = @Schema(implementation = ProcessingResult.class)

980

)

981

)

982

)

983

)

984

)

985

@ApiResponse(

986

responseCode = "202",

987

description = "Processing started",

988

content = @Content(

989

schema = @Schema(implementation = ProcessingRequest.class)

990

),

991

links = {

992

@Link(

993

name = "CheckStatus",

994

operationId = "getProcessingStatus",

995

parameters = @LinkParameter(

996

name = "processId",

997

expression = "$response.body#/processId"

998

)

999

),

1000

@Link(

1001

name = "CancelProcessing",

1002

operationId = "cancelProcessing",

1003

parameters = @LinkParameter(

1004

name = "processId",

1005

expression = "$response.body#/processId"

1006

)

1007

)

1008

}

1009

)

1010

public ResponseEntity<ProcessingRequest> startAsyncProcessing(

1011

@RequestBody @OpenAPI31 AsyncProcessingRequest request

1012

) {

1013

ProcessingRequest result = petService.startAsyncProcessing(request);

1014

return ResponseEntity.accepted().body(result);

1015

}

1016

}

1017

```