or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

callbacks.mdcore-annotations.mdenums.mdindex.mdlinks.mdresponses.mdschema-media.mdsecurity.mdserver-info.md

links.mddocs/

0

# Links and Operation References

1

2

Define relationships between operations and enable workflow documentation with parameter passing between linked operations. This system provides comprehensive support for documenting API workflows, operation chains, and parameter flow between related endpoints.

3

4

## Capabilities

5

6

### Operation Links

7

8

Defines links between operations to describe workflows and parameter passing patterns.

9

10

```java { .api }

11

/**

12

* Defines link to related operation

13

* Applied to: within response definitions

14

*/

15

@Link(

16

name = "getUserById", // Link name (required)

17

operationRef = "#/paths/~1users~1{userId}/get", // Reference to operation path

18

operationId = "getUserById", // Operation ID reference (preferred)

19

parameters = { // Parameters to pass to linked operation

20

@LinkParameter(name = "userId", expression = "$response.body#/id"),

21

@LinkParameter(name = "include", expression = "$request.query.include")

22

},

23

requestBody = "$response.body#/userDetails", // Request body for linked operation

24

description = "Get the created user details", // Link description

25

server = @Server( // Alternative server for link

26

url = "https://users-api.example.com",

27

description = "User management server"

28

),

29

extensions = {@Extension(...)}, // Custom extensions

30

ref = "#/components/links/GetUserById" // Reference to component link

31

)

32

```

33

34

**Usage Examples:**

35

36

```java

37

// User CRUD workflow links

38

@POST

39

@Path("/users")

40

@Operation(operationId = "createUser", summary = "Create new user")

41

@ApiResponse(

42

responseCode = "201",

43

description = "User created successfully",

44

content = @Content(

45

mediaType = "application/json",

46

schema = @Schema(implementation = User.class)

47

),

48

headers = @Header(

49

name = "Location",

50

description = "URL of created user",

51

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

52

),

53

links = {

54

@Link(

55

name = "GetUser",

56

description = "Retrieve the created user",

57

operationId = "getUserById",

58

parameters = @LinkParameter(name = "id", expression = "$response.body#/id")

59

),

60

@Link(

61

name = "UpdateUser",

62

description = "Update the created user",

63

operationId = "updateUser",

64

parameters = @LinkParameter(name = "id", expression = "$response.body#/id")

65

),

66

@Link(

67

name = "DeleteUser",

68

description = "Delete the created user",

69

operationId = "deleteUser",

70

parameters = @LinkParameter(name = "id", expression = "$response.body#/id")

71

),

72

@Link(

73

name = "GetUserProfile",

74

description = "Get user profile",

75

operationId = "getUserProfile",

76

parameters = @LinkParameter(name = "userId", expression = "$response.body#/id")

77

)

78

}

79

)

80

public Response createUser(@RequestBody CreateUserRequest request) {}

81

82

@GET

83

@Path("/users/{id}")

84

@Operation(operationId = "getUserById", summary = "Get user by ID")

85

@ApiResponse(

86

responseCode = "200",

87

description = "User retrieved successfully",

88

content = @Content(schema = @Schema(implementation = User.class)),

89

links = {

90

@Link(

91

name = "GetUserPosts",

92

description = "Get posts authored by this user",

93

operationId = "getPostsByAuthor",

94

parameters = @LinkParameter(name = "authorId", expression = "$response.body#/id")

95

),

96

@Link(

97

name = "GetUserComments",

98

description = "Get comments by this user",

99

operationId = "getCommentsByUser",

100

parameters = @LinkParameter(name = "userId", expression = "$response.body#/id")

101

),

102

@Link(

103

name = "GetUserFollowers",

104

description = "Get user's followers",

105

operationId = "getUserFollowers",

106

parameters = @LinkParameter(name = "userId", expression = "$response.body#/id")

107

)

108

}

109

)

110

public Response getUserById(@PathParam("id") Long id) {}

111

112

// E-commerce order workflow

113

@POST

114

@Path("/orders")

115

@Operation(operationId = "createOrder", summary = "Create new order")

116

@ApiResponse(

117

responseCode = "201",

118

description = "Order created successfully",

119

content = @Content(schema = @Schema(implementation = Order.class)),

120

links = {

121

@Link(

122

name = "GetOrder",

123

description = "Retrieve the created order",

124

operationId = "getOrderById",

125

parameters = @LinkParameter(name = "orderId", expression = "$response.body#/id")

126

),

127

@Link(

128

name = "PayOrder",

129

description = "Process payment for the order",

130

operationId = "processPayment",

131

parameters = @LinkParameter(name = "orderId", expression = "$response.body#/id"),

132

requestBody = "$response.body#/paymentDetails"

133

),

134

@Link(

135

name = "CancelOrder",

136

description = "Cancel the order if still pending",

137

operationId = "cancelOrder",

138

parameters = @LinkParameter(name = "orderId", expression = "$response.body#/id")

139

),

140

@Link(

141

name = "TrackOrder",

142

description = "Track order shipment status",

143

operationId = "trackOrder",

144

parameters = @LinkParameter(name = "orderId", expression = "$response.body#/id")

145

)

146

}

147

)

148

public Response createOrder(@RequestBody CreateOrderRequest request) {}

149

150

// Payment processing workflow

151

@POST

152

@Path("/payments")

153

@Operation(operationId = "processPayment", summary = "Process payment")

154

@ApiResponse(

155

responseCode = "200",

156

description = "Payment processed",

157

content = @Content(schema = @Schema(implementation = PaymentResult.class)),

158

links = {

159

@Link(

160

name = "GetPaymentStatus",

161

description = "Check payment status",

162

operationId = "getPaymentStatus",

163

parameters = @LinkParameter(name = "paymentId", expression = "$response.body#/paymentId")

164

),

165

@Link(

166

name = "RefundPayment",

167

description = "Refund this payment",

168

operationId = "refundPayment",

169

parameters = @LinkParameter(name = "paymentId", expression = "$response.body#/paymentId")

170

),

171

@Link(

172

name = "GetPaymentReceipt",

173

description = "Download payment receipt",

174

operationId = "downloadReceipt",

175

parameters = @LinkParameter(name = "paymentId", expression = "$response.body#/paymentId")

176

)

177

}

178

)

179

public Response processPayment(@RequestBody PaymentRequest request) {}

180

```

181

182

### Link Parameters

183

184

Defines parameters passed between linked operations using expression language.

185

186

```java { .api }

187

/**

188

* Defines parameter for linked operation

189

* Applied to: within Link annotations

190

*/

191

@LinkParameter(

192

name = "userId", // Parameter name (required)

193

expression = "$response.body#/id" // Expression to get parameter value (required)

194

)

195

```

196

197

**Expression Types and Examples:**

198

199

```java

200

// Response body field access

201

@LinkParameter(name = "userId", expression = "$response.body#/id")

202

@LinkParameter(name = "email", expression = "$response.body#/user/email")

203

@LinkParameter(name = "status", expression = "$response.body#/status")

204

205

// Response header values

206

@LinkParameter(name = "etag", expression = "$response.header.ETag")

207

@LinkParameter(name = "location", expression = "$response.header.Location")

208

@LinkParameter(name = "contentType", expression = "$response.header.Content-Type")

209

210

// Request parameter forwarding

211

@LinkParameter(name = "include", expression = "$request.query.include")

212

@LinkParameter(name = "version", expression = "$request.path.version")

213

@LinkParameter(name = "clientId", expression = "$request.header.X-Client-ID")

214

215

// Static/constant values

216

@LinkParameter(name = "format", expression = "json")

217

@LinkParameter(name = "version", expression = "v2")

218

@LinkParameter(name = "scope", expression = "read")

219

220

// Complex JSON path expressions

221

@LinkParameter(name = "addressId", expression = "$response.body#/customer/defaultAddress/id")

222

@LinkParameter(name = "productIds", expression = "$response.body#/items[*]/productId")

223

@LinkParameter(name = "totalAmount", expression = "$response.body#/order/totals/grandTotal")

224

```

225

226

**Advanced Parameter Examples:**

227

228

```java

229

// Pagination workflow

230

@GET

231

@Path("/users")

232

@Operation(operationId = "listUsers", summary = "List users with pagination")

233

@ApiResponse(

234

responseCode = "200",

235

description = "User list retrieved",

236

content = @Content(schema = @Schema(implementation = UserList.class)),

237

headers = {

238

@Header(name = "X-Total-Count", schema = @Schema(type = "integer")),

239

@Header(name = "X-Page-Number", schema = @Schema(type = "integer")),

240

@Header(name = "Link", schema = @Schema(type = "string"))

241

},

242

links = {

243

@Link(

244

name = "NextPage",

245

description = "Get next page of users",

246

operationId = "listUsers",

247

parameters = {

248

@LinkParameter(name = "page", expression = "$response.header.X-Page-Number + 1"),

249

@LinkParameter(name = "size", expression = "$request.query.size"),

250

@LinkParameter(name = "sort", expression = "$request.query.sort")

251

}

252

),

253

@Link(

254

name = "PreviousPage",

255

description = "Get previous page of users",

256

operationId = "listUsers",

257

parameters = {

258

@LinkParameter(name = "page", expression = "$response.header.X-Page-Number - 1"),

259

@LinkParameter(name = "size", expression = "$request.query.size")

260

}

261

),

262

@Link(

263

name = "FirstPage",

264

description = "Get first page",

265

operationId = "listUsers",

266

parameters = {

267

@LinkParameter(name = "page", expression = "1"),

268

@LinkParameter(name = "size", expression = "$request.query.size")

269

}

270

)

271

}

272

)

273

public Response listUsers(

274

@QueryParam("page") Integer page,

275

@QueryParam("size") Integer size,

276

@QueryParam("sort") String sort

277

) {}

278

279

// File upload and processing workflow

280

@POST

281

@Path("/files/upload")

282

@Operation(operationId = "uploadFile", summary = "Upload file")

283

@ApiResponse(

284

responseCode = "201",

285

description = "File uploaded successfully",

286

content = @Content(schema = @Schema(implementation = FileUploadResult.class)),

287

links = {

288

@Link(

289

name = "ProcessFile",

290

description = "Start processing the uploaded file",

291

operationId = "processFile",

292

parameters = @LinkParameter(name = "fileId", expression = "$response.body#/fileId"),

293

requestBody = "$response.body#/processingOptions"

294

),

295

@Link(

296

name = "DownloadFile",

297

description = "Download the uploaded file",

298

operationId = "downloadFile",

299

parameters = @LinkParameter(name = "fileId", expression = "$response.body#/fileId")

300

),

301

@Link(

302

name = "GetFileMetadata",

303

description = "Get file metadata and status",

304

operationId = "getFileMetadata",

305

parameters = @LinkParameter(name = "fileId", expression = "$response.body#/fileId")

306

),

307

@Link(

308

name = "DeleteFile",

309

description = "Delete the uploaded file",

310

operationId = "deleteFile",

311

parameters = @LinkParameter(name = "fileId", expression = "$response.body#/fileId")

312

)

313

}

314

)

315

public Response uploadFile(

316

@FormParam("file") InputStream file,

317

@FormParam("metadata") FileMetadata metadata

318

) {}

319

```

320

321

### Links Container

322

323

Container for multiple link definitions in responses.

324

325

```java { .api }

326

/**

327

* Container for multiple Link annotations

328

*/

329

@Links({

330

@Link(name = "self", operationId = "getUserById", parameters = @LinkParameter(name = "id", expression = "$response.body#/id")),

331

@Link(name = "edit", operationId = "updateUser", parameters = @LinkParameter(name = "id", expression = "$response.body#/id")),

332

@Link(name = "delete", operationId = "deleteUser", parameters = @LinkParameter(name = "id", expression = "$response.body#/id"))

333

})

334

```

335

336

## Advanced Workflow Patterns

337

338

### Multi-Step Workflows

339

340

```java

341

// Customer onboarding workflow

342

@POST

343

@Path("/customers/onboard")

344

@Operation(operationId = "startOnboarding", summary = "Start customer onboarding")

345

@ApiResponse(

346

responseCode = "201",

347

description = "Onboarding process started",

348

content = @Content(schema = @Schema(implementation = OnboardingSession.class)),

349

links = {

350

@Link(

351

name = "VerifyIdentity",

352

description = "Verify customer identity",

353

operationId = "verifyIdentity",

354

parameters = @LinkParameter(name = "sessionId", expression = "$response.body#/sessionId")

355

),

356

@Link(

357

name = "UploadDocuments",

358

description = "Upload verification documents",

359

operationId = "uploadDocuments",

360

parameters = @LinkParameter(name = "sessionId", expression = "$response.body#/sessionId")

361

),

362

@Link(

363

name = "CheckOnboardingStatus",

364

description = "Check onboarding progress",

365

operationId = "getOnboardingStatus",

366

parameters = @LinkParameter(name = "sessionId", expression = "$response.body#/sessionId")

367

)

368

}

369

)

370

public Response startOnboarding(@RequestBody OnboardingRequest request) {}

371

372

@PUT

373

@Path("/customers/onboard/{sessionId}/verify")

374

@Operation(operationId = "verifyIdentity", summary = "Verify customer identity")

375

@ApiResponse(

376

responseCode = "200",

377

description = "Identity verification completed",

378

content = @Content(schema = @Schema(implementation = VerificationResult.class)),

379

links = {

380

@Link(

381

name = "SetupAccount",

382

description = "Set up customer account after verification",

383

operationId = "setupAccount",

384

parameters = @LinkParameter(name = "customerId", expression = "$response.body#/customerId"),

385

requestBody = "$response.body#/accountDetails"

386

),

387

@Link(

388

name = "ActivateServices",

389

description = "Activate customer services",

390

operationId = "activateServices",

391

parameters = @LinkParameter(name = "customerId", expression = "$response.body#/customerId")

392

)

393

}

394

)

395

public Response verifyIdentity(@PathParam("sessionId") String sessionId, @RequestBody IdentityData data) {}

396

```

397

398

### Conditional Links

399

400

```java

401

@GET

402

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

403

@Operation(operationId = "getOrder", summary = "Get order details")

404

@ApiResponse(

405

responseCode = "200",

406

description = "Order details",

407

content = @Content(schema = @Schema(implementation = Order.class)),

408

links = {

409

@Link(

410

name = "PayOrder",

411

description = "Pay for order (only available for unpaid orders)",

412

operationId = "processPayment",

413

parameters = @LinkParameter(name = "orderId", expression = "$response.body#/id"),

414

extensions = @Extension(

415

name = "x-link-condition",

416

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

417

)

418

),

419

@Link(

420

name = "CancelOrder",

421

description = "Cancel order (only available for pending orders)",

422

operationId = "cancelOrder",

423

parameters = @LinkParameter(name = "orderId", expression = "$response.body#/id"),

424

extensions = @Extension(

425

name = "x-link-condition",

426

properties = @ExtensionProperty(name = "when", value = "$response.body#/status in ['pending', 'processing']")

427

)

428

),

429

@Link(

430

name = "TrackShipment",

431

description = "Track shipment (only available for shipped orders)",

432

operationId = "trackShipment",

433

parameters = @LinkParameter(name = "trackingNumber", expression = "$response.body#/tracking/number"),

434

extensions = @Extension(

435

name = "x-link-condition",

436

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

437

)

438

),

439

@Link(

440

name = "RequestRefund",

441

description = "Request refund (only available for completed orders)",

442

operationId = "requestRefund",

443

parameters = @LinkParameter(name = "orderId", expression = "$response.body#/id"),

444

extensions = @Extension(

445

name = "x-link-condition",

446

properties = @ExtensionProperty(name = "when", value = "$response.body#/status == 'completed'")

447

)

448

)

449

}

450

)

451

public Response getOrder(@PathParam("id") Long orderId) {}

452

```

453

454

### Error Recovery Links

455

456

```java

457

@POST

458

@Path("/data/import")

459

@Operation(operationId = "importData", summary = "Import data")

460

@ApiResponses({

461

@ApiResponse(

462

responseCode = "200",

463

description = "Import successful",

464

content = @Content(schema = @Schema(implementation = ImportResult.class)),

465

links = {

466

@Link(

467

name = "GetImportStatus",

468

description = "Get detailed import status",

469

operationId = "getImportStatus",

470

parameters = @LinkParameter(name = "importId", expression = "$response.body#/importId")

471

),

472

@Link(

473

name = "DownloadReport",

474

description = "Download import report",

475

operationId = "downloadImportReport",

476

parameters = @LinkParameter(name = "importId", expression = "$response.body#/importId")

477

)

478

}

479

),

480

@ApiResponse(

481

responseCode = "400",

482

description = "Import failed with validation errors",

483

content = @Content(schema = @Schema(implementation = ImportError.class)),

484

links = {

485

@Link(

486

name = "GetErrorDetails",

487

description = "Get detailed error information",

488

operationId = "getImportErrors",

489

parameters = @LinkParameter(name = "importId", expression = "$response.body#/importId")

490

),

491

@Link(

492

name = "RetryImport",

493

description = "Retry import with corrected data",

494

operationId = "retryImport",

495

parameters = @LinkParameter(name = "importId", expression = "$response.body#/importId")

496

),

497

@Link(

498

name = "DownloadErrorReport",

499

description = "Download error report with line numbers",

500

operationId = "downloadErrorReport",

501

parameters = @LinkParameter(name = "importId", expression = "$response.body#/importId")

502

)

503

}

504

)

505

})

506

public Response importData(@RequestBody ImportRequest request) {}

507

```

508

509

### Cross-Service Links

510

511

```java

512

@POST

513

@Path("/users")

514

@Operation(operationId = "createUser", summary = "Create user")

515

@ApiResponse(

516

responseCode = "201",

517

description = "User created",

518

content = @Content(schema = @Schema(implementation = User.class)),

519

links = {

520

@Link(

521

name = "CreateUserProfile",

522

description = "Create user profile in profile service",

523

operationId = "createProfile",

524

parameters = @LinkParameter(name = "userId", expression = "$response.body#/id"),

525

server = @Server(

526

url = "https://profiles-api.example.com",

527

description = "Profile management service"

528

)

529

),

530

@Link(

531

name = "SetupNotifications",

532

description = "Set up user notifications",

533

operationId = "setupNotifications",

534

parameters = @LinkParameter(name = "userId", expression = "$response.body#/id"),

535

server = @Server(

536

url = "https://notifications-api.example.com",

537

description = "Notification service"

538

)

539

),

540

@Link(

541

name = "InitializeWallet",

542

description = "Initialize user wallet",

543

operationId = "initializeWallet",

544

parameters = @LinkParameter(name = "userId", expression = "$response.body#/id"),

545

server = @Server(

546

url = "https://wallet-api.example.com",

547

description = "Wallet service"

548

)

549

)

550

}

551

)

552

public Response createUser(@RequestBody CreateUserRequest request) {}

553

```

554

555

## Link Metadata and Extensions

556

557

### Link Documentation Extensions

558

559

```java

560

@Link(

561

name = "complexWorkflow",

562

description = "Initiate complex multi-step workflow",

563

operationId = "startWorkflow",

564

parameters = @LinkParameter(name = "entityId", expression = "$response.body#/id"),

565

extensions = {

566

@Extension(

567

name = "x-link-metadata",

568

properties = {

569

@ExtensionProperty(name = "category", value = "workflow"),

570

@ExtensionProperty(name = "complexity", value = "high"),

571

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

572

@ExtensionProperty(name = "requires-approval", value = "true")

573

}

574

),

575

@Extension(

576

name = "x-link-permissions",

577

properties = {

578

@ExtensionProperty(name = "required-roles", value = "[\"admin\", \"workflow-manager\"]"),

579

@ExtensionProperty(name = "required-scopes", value = "[\"workflow:execute\"]")

580

}

581

)

582

}

583

)

584

```

585

586

### Performance and Caching Links

587

588

```java

589

@Link(

590

name = "optimizedDataAccess",

591

description = "Access data with caching optimization",

592

operationId = "getCachedData",

593

parameters = {

594

@LinkParameter(name = "id", expression = "$response.body#/id"),

595

@LinkParameter(name = "cacheKey", expression = "$response.body#/cacheKey")

596

},

597

extensions = {

598

@Extension(

599

name = "x-caching",

600

properties = {

601

@ExtensionProperty(name = "ttl", value = "3600"),

602

@ExtensionProperty(name = "cache-strategy", value = "read-through"),

603

@ExtensionProperty(name = "cache-tags", value = "[\"user-data\", \"profile\"]")

604

}

605

)

606

}

607

)

608

```