or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-api.mddocumentation.mdextensions.mdindex.mdmodels.mdparameters.mdresponses.mdsecurity.md

extensions.mddocs/

0

# Extension System

1

2

Annotations for adding custom extensions and examples to Swagger specifications. The extension system allows you to add vendor-specific or custom metadata to any Swagger element, while example annotations provide sample data for better API documentation and testing.

3

4

## Capabilities

5

6

### @Extension Annotation

7

8

Defines custom extensions for Swagger specification elements. Extensions allow you to add vendor-specific or custom metadata that extends beyond the standard Swagger specification. All extension names are automatically prefixed with "x-" to follow OpenAPI conventions.

9

10

```java { .api }

11

/**

12

* Defines custom extensions for Swagger specification

13

* Target: ANNOTATION_TYPE

14

* Retention: RUNTIME

15

*/

16

@Target(ElementType.ANNOTATION_TYPE)

17

@Retention(RetentionPolicy.RUNTIME)

18

@interface Extension {

19

/**

20

* Name of the extension

21

* Will be prefixed with "x-" automatically in the generated specification

22

* Use descriptive names that indicate the extension's purpose

23

*/

24

String name() default "";

25

26

/**

27

* Array of name/value pairs for the extension

28

* Contains the actual extension data as key-value properties

29

* REQUIRED ATTRIBUTE

30

*/

31

ExtensionProperty[] properties();

32

}

33

```

34

35

**Usage Examples:**

36

37

```java

38

// Simple extension with single property

39

@ApiOperation(

40

value = "Get user profile",

41

extensions = {

42

@Extension(

43

name = "code-samples",

44

properties = {

45

@ExtensionProperty(name = "javascript", value = "fetch('/users/123')")

46

}

47

)

48

}

49

)

50

@GET

51

@Path("/{id}")

52

public User getUser(@PathParam("id") Long id) {

53

// implementation

54

}

55

56

// Multiple extensions on model property

57

public class Product {

58

@ApiModelProperty(

59

value = "Product price in cents",

60

example = "1299",

61

extensions = {

62

@Extension(

63

name = "validation",

64

properties = {

65

@ExtensionProperty(name = "min", value = "0"),

66

@ExtensionProperty(name = "max", value = "999999"),

67

@ExtensionProperty(name = "currency", value = "USD")

68

}

69

),

70

@Extension(

71

name = "display",

72

properties = {

73

@ExtensionProperty(name = "format", value = "currency"),

74

@ExtensionProperty(name = "symbol", value = "$")

75

}

76

)

77

}

78

)

79

private Integer price;

80

}

81

82

// Extension with JSON parsing

83

@ApiOperation(

84

value = "Create order",

85

extensions = {

86

@Extension(

87

name = "workflow",

88

properties = {

89

@ExtensionProperty(

90

name = "steps",

91

value = "[\"validate\", \"process\", \"fulfill\", \"notify\"]",

92

parseValue = true // Parse as JSON array

93

)

94

}

95

)

96

}

97

)

98

@POST

99

public Order createOrder(CreateOrderRequest request) {

100

// implementation

101

}

102

103

// Vendor-specific extensions

104

@ApiModelProperty(

105

value = "Customer ID",

106

extensions = {

107

@Extension(

108

name = "amazon-integration",

109

properties = {

110

@ExtensionProperty(name = "marketplace-id", value = "A1PA6795UKMFR9"),

111

@ExtensionProperty(name = "seller-id", value = "A2EXAMPLE123")

112

}

113

),

114

@Extension(

115

name = "analytics",

116

properties = {

117

@ExtensionProperty(name = "track-conversions", value = "true"),

118

@ExtensionProperty(name = "segment", value = "premium-customers")

119

}

120

)

121

}

122

)

123

private String customerId;

124

```

125

126

### @ExtensionProperty Annotation

127

128

Defines name/value pairs within extensions. Each property represents a key-value pair of metadata that gets added to the extension object in the generated Swagger specification.

129

130

```java { .api }

131

/**

132

* Defines name/value pairs within extensions

133

* Target: ANNOTATION_TYPE

134

* Retention: RUNTIME

135

*/

136

@Target(ElementType.ANNOTATION_TYPE)

137

@Retention(RetentionPolicy.RUNTIME)

138

@interface ExtensionProperty {

139

/**

140

* Property name within the extension

141

* Used as the key in the extension object

142

* REQUIRED ATTRIBUTE

143

*/

144

String name();

145

146

/**

147

* Property value within the extension

148

* Can be any string value or JSON when parseValue is true

149

* REQUIRED ATTRIBUTE

150

*/

151

String value();

152

153

/**

154

* Whether to parse the value as JSON/YAML

155

* When true, the value string is parsed as structured data

156

* When false (default), the value is treated as a literal string

157

*/

158

boolean parseValue() default false;

159

}

160

```

161

162

**Usage Examples:**

163

164

```java

165

// String properties

166

@Extension(

167

name = "security",

168

properties = {

169

@ExtensionProperty(name = "classification", value = "confidential"),

170

@ExtensionProperty(name = "data-owner", value = "finance-team"),

171

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

172

}

173

)

174

175

// Numeric and boolean properties

176

@Extension(

177

name = "rate-limiting",

178

properties = {

179

@ExtensionProperty(name = "requests-per-minute", value = "100"),

180

@ExtensionProperty(name = "burst-limit", value = "20"),

181

@ExtensionProperty(name = "enabled", value = "true")

182

}

183

)

184

185

// JSON object properties

186

@Extension(

187

name = "client-config",

188

properties = {

189

@ExtensionProperty(

190

name = "timeout-settings",

191

value = "{\"connect\": 5000, \"read\": 30000, \"total\": 35000}",

192

parseValue = true

193

),

194

@ExtensionProperty(

195

name = "retry-policy",

196

value = "{\"maxAttempts\": 3, \"backoffMs\": 1000, \"exponential\": true}",

197

parseValue = true

198

)

199

}

200

)

201

202

// Array properties

203

@Extension(

204

name = "allowed-origins",

205

properties = {

206

@ExtensionProperty(

207

name = "domains",

208

value = "[\"https://app.example.com\", \"https://admin.example.com\"]",

209

parseValue = true

210

)

211

}

212

)

213

214

// Complex nested structure

215

@Extension(

216

name = "monitoring",

217

properties = {

218

@ExtensionProperty(

219

name = "metrics",

220

value = "{" +

221

"\"enabled\": true, " +

222

"\"collectors\": [\"prometheus\", \"datadog\"], " +

223

"\"sampling\": {\"rate\": 0.1, \"max-traces\": 1000}" +

224

"}",

225

parseValue = true

226

)

227

}

228

)

229

```

230

231

### @Example Annotation

232

233

Container for multiple example properties, used to provide sample data for request/response bodies. Examples help API consumers understand the expected data format and structure.

234

235

```java { .api }

236

/**

237

* Container for multiple example properties

238

* Target: ANNOTATION_TYPE

239

* Retention: RUNTIME

240

*/

241

@Target(ElementType.ANNOTATION_TYPE)

242

@Retention(RetentionPolicy.RUNTIME)

243

@interface Example {

244

/**

245

* Array of example properties

246

* Each property defines an example for a specific media type

247

* REQUIRED ATTRIBUTE

248

*/

249

ExampleProperty[] value();

250

}

251

```

252

253

**Usage Examples:**

254

255

```java

256

// Examples for request body

257

@ApiOperation(value = "Create user account")

258

@ApiParam(

259

value = "User registration data",

260

examples = @Example({

261

@ExampleProperty(

262

mediaType = "application/json",

263

value = "{" +

264

"\"username\": \"johndoe\"," +

265

"\"email\": \"john@example.com\"," +

266

"\"firstName\": \"John\"," +

267

"\"lastName\": \"Doe\"" +

268

"}"

269

),

270

@ExampleProperty(

271

mediaType = "application/xml",

272

value = "<user>" +

273

"<username>johndoe</username>" +

274

"<email>john@example.com</email>" +

275

"<firstName>John</firstName>" +

276

"<lastName>Doe</lastName>" +

277

"</user>"

278

)

279

})

280

)

281

@POST

282

public User createUser(UserRegistrationRequest request) {

283

// implementation

284

}

285

286

// Response examples

287

@ApiResponse(

288

code = 200,

289

message = "Product details retrieved successfully",

290

response = Product.class,

291

examples = @Example({

292

@ExampleProperty(

293

mediaType = "application/json",

294

value = "{" +

295

"\"id\": 12345," +

296

"\"name\": \"Wireless Headphones\"," +

297

"\"description\": \"High-quality wireless headphones with noise cancellation\"," +

298

"\"price\": 199.99," +

299

"\"category\": \"Electronics\"," +

300

"\"inStock\": true," +

301

"\"tags\": [\"audio\", \"wireless\", \"noise-cancelling\"]" +

302

"}"

303

)

304

})

305

)

306

@GET

307

@Path("/{id}")

308

public Product getProduct(@PathParam("id") Long id) {

309

// implementation

310

}

311

312

// Multiple examples for different scenarios

313

@ApiParam(

314

value = "Order data",

315

examples = @Example({

316

// Minimal order example

317

@ExampleProperty(

318

mediaType = "application/json",

319

value = "{" +

320

"\"customerId\": \"cust_123\"," +

321

"\"items\": [{\"productId\": \"prod_456\", \"quantity\": 1}]" +

322

"}"

323

),

324

// Complete order example with all fields

325

@ExampleProperty(

326

mediaType = "application/json",

327

value = "{" +

328

"\"customerId\": \"cust_123\"," +

329

"\"items\": [" +

330

"{\"productId\": \"prod_456\", \"quantity\": 2, \"price\": 29.99}," +

331

"{\"productId\": \"prod_789\", \"quantity\": 1, \"price\": 15.50}" +

332

"]," +

333

"\"shippingAddress\": {" +

334

"\"street\": \"123 Main St\"," +

335

"\"city\": \"Anytown\"," +

336

"\"zipCode\": \"12345\"," +

337

"\"country\": \"US\"" +

338

"}," +

339

"\"paymentMethod\": \"credit_card\"," +

340

"\"notes\": \"Please leave at front door\"" +

341

"}"

342

)

343

})

344

)

345

@POST

346

@Path("/orders")

347

public Order createOrder(CreateOrderRequest request) {

348

// implementation

349

}

350

```

351

352

### @ExampleProperty Annotation

353

354

Defines media type and example value pairs. Each property associates a specific example with a media type, allowing different examples for different content types.

355

356

```java { .api }

357

/**

358

* Defines media type and example value pairs

359

* Target: ANNOTATION_TYPE

360

* Retention: RUNTIME

361

*/

362

@Target(ElementType.ANNOTATION_TYPE)

363

@Retention(RetentionPolicy.RUNTIME)

364

@interface ExampleProperty {

365

/**

366

* Media type for this example

367

* Specifies the content type this example applies to

368

* Common values: "application/json", "application/xml", "text/plain"

369

*/

370

String mediaType() default "";

371

372

/**

373

* Example value for the specified media type

374

* Should be a valid representation in the specified media type format

375

* REQUIRED ATTRIBUTE

376

*/

377

String value();

378

}

379

```

380

381

**Usage Examples:**

382

383

```java

384

// JSON examples

385

@ExampleProperty(

386

mediaType = "application/json",

387

value = "{\"message\": \"Hello, World!\"}"

388

)

389

390

// XML examples

391

@ExampleProperty(

392

mediaType = "application/xml",

393

value = "<message>Hello, World!</message>"

394

)

395

396

// Plain text examples

397

@ExampleProperty(

398

mediaType = "text/plain",

399

value = "Hello, World!"

400

)

401

402

// CSV examples

403

@ExampleProperty(

404

mediaType = "text/csv",

405

value = "id,name,email\n1,John Doe,john@example.com\n2,Jane Smith,jane@example.com"

406

)

407

408

// Complex JSON structures

409

@ExampleProperty(

410

mediaType = "application/json",

411

value = "{" +

412

"\"user\": {" +

413

"\"id\": 123," +

414

"\"profile\": {" +

415

"\"name\": \"John Doe\"," +

416

"\"preferences\": {" +

417

"\"theme\": \"dark\"," +

418

"\"notifications\": true," +

419

"\"languages\": [\"en\", \"es\"]" +

420

"}" +

421

"}" +

422

"}," +

423

"\"metadata\": {" +

424

"\"created\": \"2023-01-15T10:30:00Z\"," +

425

"\"lastUpdated\": \"2023-12-01T14:22:33Z\"" +

426

"}" +

427

"}"

428

)

429

430

// Error response examples

431

@ExampleProperty(

432

mediaType = "application/json",

433

value = "{" +

434

"\"error\": {" +

435

"\"code\": \"VALIDATION_FAILED\"," +

436

"\"message\": \"The request contains invalid data\"," +

437

"\"details\": [" +

438

"{\"field\": \"email\", \"message\": \"Invalid email format\"}," +

439

"{\"field\": \"age\", \"message\": \"Age must be between 13 and 120\"}" +

440

"]" +

441

"}" +

442

"}"

443

)

444

```

445

446

### Complete Integration Example

447

448

Here's a comprehensive example showing how all extension and example annotations work together:

449

450

```java

451

@Api(tags = "orders")

452

@Path("/orders")

453

public class OrderController {

454

455

@ApiOperation(

456

value = "Create a new order",

457

notes = "Creates a new order with the provided details. Supports both simple and complex order structures.",

458

response = Order.class,

459

code = 201,

460

extensions = {

461

@Extension(

462

name = "workflow",

463

properties = {

464

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

465

@ExtensionProperty(name = "estimated-duration", value = "2-5 seconds"),

466

@ExtensionProperty(

467

name = "steps",

468

value = "[\"validate\", \"inventory-check\", \"payment-process\", \"fulfill\"]",

469

parseValue = true

470

)

471

}

472

),

473

@Extension(

474

name = "rate-limiting",

475

properties = {

476

@ExtensionProperty(name = "per-minute", value = "10"),

477

@ExtensionProperty(name = "per-hour", value = "100"),

478

@ExtensionProperty(name = "burst-allowance", value = "5")

479

}

480

)

481

}

482

)

483

@ApiResponses({

484

@ApiResponse(

485

code = 201,

486

message = "Order created successfully",

487

response = Order.class,

488

examples = @Example({

489

@ExampleProperty(

490

mediaType = "application/json",

491

value = "{" +

492

"\"id\": \"ord_1234567890\"," +

493

"\"status\": \"pending\"," +

494

"\"customerId\": \"cust_123\"," +

495

"\"total\": 75.48," +

496

"\"currency\": \"USD\"," +

497

"\"createdAt\": \"2023-12-01T10:30:00Z\"," +

498

"\"items\": [" +

499

"{\"productId\": \"prod_456\", \"quantity\": 2, \"unitPrice\": 29.99}," +

500

"{\"productId\": \"prod_789\", \"quantity\": 1, \"unitPrice\": 15.50}" +

501

"]" +

502

"}"

503

)

504

})

505

),

506

@ApiResponse(

507

code = 400,

508

message = "Invalid order data",

509

examples = @Example({

510

@ExampleProperty(

511

mediaType = "application/json",

512

value = "{" +

513

"\"error\": {" +

514

"\"code\": \"INVALID_ORDER_DATA\"," +

515

"\"message\": \"The order contains invalid information\"," +

516

"\"details\": [" +

517

"{\"field\": \"customerId\", \"message\": \"Customer ID is required\"}," +

518

"{\"field\": \"items[0].quantity\", \"message\": \"Quantity must be positive\"}" +

519

"]" +

520

"}" +

521

"}"

522

)

523

})

524

)

525

})

526

@POST

527

public Response createOrder(

528

@ApiParam(

529

value = "Order creation request",

530

required = true,

531

examples = @Example({

532

// Simple order example

533

@ExampleProperty(

534

mediaType = "application/json",

535

value = "{" +

536

"\"customerId\": \"cust_123\"," +

537

"\"items\": [" +

538

"{\"productId\": \"prod_456\", \"quantity\": 1}" +

539

"]" +

540

"}"

541

),

542

// Complex order example

543

@ExampleProperty(

544

mediaType = "application/json",

545

value = "{" +

546

"\"customerId\": \"cust_123\"," +

547

"\"items\": [" +

548

"{\"productId\": \"prod_456\", \"quantity\": 2}," +

549

"{\"productId\": \"prod_789\", \"quantity\": 1}" +

550

"]," +

551

"\"shippingAddress\": {" +

552

"\"name\": \"John Doe\"," +

553

"\"street\": \"123 Main St\"," +

554

"\"city\": \"Springfield\"," +

555

"\"state\": \"IL\"," +

556

"\"zipCode\": \"62701\"," +

557

"\"country\": \"US\"" +

558

"}," +

559

"\"billingAddress\": {" +

560

"\"name\": \"John Doe\"," +

561

"\"street\": \"123 Main St\"," +

562

"\"city\": \"Springfield\"," +

563

"\"state\": \"IL\"," +

564

"\"zipCode\": \"62701\"," +

565

"\"country\": \"US\"" +

566

"}," +

567

"\"paymentMethod\": {" +

568

"\"type\": \"credit_card\"," +

569

"\"cardToken\": \"tok_1234567890\"" +

570

"}," +

571

"\"specialInstructions\": \"Please call before delivery\"," +

572

"\"giftMessage\": \"Happy Birthday!\"," +

573

"\"expedited\": false" +

574

"}"

575

),

576

// XML format example

577

@ExampleProperty(

578

mediaType = "application/xml",

579

value = "<order>" +

580

"<customerId>cust_123</customerId>" +

581

"<items>" +

582

"<item>" +

583

"<productId>prod_456</productId>" +

584

"<quantity>1</quantity>" +

585

"</item>" +

586

"</items>" +

587

"</order>"

588

)

589

})

590

)

591

CreateOrderRequest orderRequest

592

) {

593

// implementation

594

return Response.status(201).build();

595

}

596

}

597

598

// Model with extensions and examples

599

@ApiModel(description = "Order creation request")

600

public class CreateOrderRequest {

601

602

@ApiModelProperty(

603

value = "Customer identifier",

604

required = true,

605

example = "cust_123",

606

extensions = {

607

@Extension(

608

name = "validation",

609

properties = {

610

@ExtensionProperty(name = "pattern", value = "^cust_[a-zA-Z0-9]{3,20}$"),

611

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

612

}

613

),

614

@Extension(

615

name = "database",

616

properties = {

617

@ExtensionProperty(name = "table", value = "customers"),

618

@ExtensionProperty(name = "foreign-key", value = "id")

619

}

620

)

621

}

622

)

623

private String customerId;

624

625

@ApiModelProperty(

626

value = "List of items to order",

627

required = true,

628

extensions = {

629

@Extension(

630

name = "constraints",

631

properties = {

632

@ExtensionProperty(name = "min-items", value = "1"),

633

@ExtensionProperty(name = "max-items", value = "50")

634

}

635

)

636

}

637

)

638

private List<OrderItem> items;

639

640

// getters and setters

641

}

642

```

643

644

### Best Practices

645

646

1. **Use meaningful extension names** - Choose descriptive names that clearly indicate the extension's purpose

647

2. **Follow naming conventions** - Use lowercase with hyphens for consistency (e.g., "rate-limiting", "custom-validation")

648

3. **Leverage parseValue for structured data** - Use JSON parsing for complex configuration or nested objects

649

4. **Provide examples for all media types** - Include examples for each supported content type (JSON, XML, etc.)

650

5. **Keep examples realistic** - Use representative data that reflects actual API usage

651

6. **Document extension purposes** - Include comments explaining what each extension accomplishes

652

7. **Validate extension values** - Ensure extension values are valid for their intended use

653

8. **Use extensions sparingly** - Only add extensions when they provide genuine value to API consumers

654

9. **Maintain consistent structure** - Use similar patterns across related extensions

655

10. **Include error examples** - Provide examples of error responses to help with error handling

656

11. **Version your extensions** - Consider versioning when extensions change over time

657

12. **Test generated specifications** - Verify that extensions appear correctly in the generated Swagger/OpenAPI spec