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
```