0
# HTTP Annotations
1
2
Declarative annotations for building REST APIs with automatic HTTP request generation, parameter binding, and response handling. These annotations enable method-based service client interfaces that are processed by RestProxy.
3
4
## Capabilities
5
6
### HTTP Method Annotations
7
8
Annotations for specifying HTTP methods and request paths for service interface methods.
9
10
```java { .api }
11
/**
12
* HTTP GET method annotation.
13
*/
14
@Target(ElementType.METHOD)
15
@Retention(RetentionPolicy.RUNTIME)
16
@interface Get {
17
/**
18
* Get the relative path for the annotated method's GET URL.
19
* @return The relative path for the annotated method's GET URL
20
*/
21
String value();
22
}
23
24
/**
25
* HTTP POST method annotation.
26
*/
27
@Target(ElementType.METHOD)
28
@Retention(RetentionPolicy.RUNTIME)
29
@interface Post {
30
/**
31
* Get the relative path for the annotated method's POST URL.
32
* @return The relative path for the annotated method's POST URL
33
*/
34
String value();
35
}
36
37
/**
38
* HTTP PUT method annotation.
39
*/
40
@Target(ElementType.METHOD)
41
@Retention(RetentionPolicy.RUNTIME)
42
@interface Put {
43
/**
44
* Get the relative path for the annotated method's PUT URL.
45
* @return The relative path for the annotated method's PUT URL
46
*/
47
String value();
48
}
49
50
/**
51
* HTTP PATCH method annotation.
52
*/
53
@Target(ElementType.METHOD)
54
@Retention(RetentionPolicy.RUNTIME)
55
@interface Patch {
56
/**
57
* Get the relative path for the annotated method's PATCH URL.
58
* @return The relative path for the annotated method's PATCH URL
59
*/
60
String value();
61
}
62
63
/**
64
* HTTP DELETE method annotation.
65
*/
66
@Target(ElementType.METHOD)
67
@Retention(RetentionPolicy.RUNTIME)
68
@interface Delete {
69
/**
70
* Get the relative path for the annotated method's DELETE URL.
71
* @return The relative path for the annotated method's DELETE URL
72
*/
73
String value();
74
}
75
76
/**
77
* HTTP HEAD method annotation.
78
*/
79
@Target(ElementType.METHOD)
80
@Retention(RetentionPolicy.RUNTIME)
81
@interface Head {
82
/**
83
* Get the relative path for the annotated method's HEAD URL.
84
* @return The relative path for the annotated method's HEAD URL
85
*/
86
String value();
87
}
88
89
/**
90
* HTTP OPTIONS method annotation.
91
*/
92
@Target(ElementType.METHOD)
93
@Retention(RetentionPolicy.RUNTIME)
94
@interface Options {
95
/**
96
* Get the relative path for the annotated method's OPTIONS URL.
97
* @return The relative path for the annotated method's OPTIONS URL
98
*/
99
String value();
100
}
101
```
102
103
### Parameter Binding Annotations
104
105
Annotations for binding method parameters to different parts of HTTP requests.
106
107
```java { .api }
108
/**
109
* Annotation to annotate a parameter to be substituted into a path segment in a REST endpoint URL.
110
*/
111
@Target(ElementType.PARAMETER)
112
@Retention(RetentionPolicy.RUNTIME)
113
@interface PathParam {
114
/**
115
* The name of the variable in the endpoint URI template which will be replaced with the value of the parameter annotated with this annotation.
116
* @return The name of the variable in the endpoint URI template
117
*/
118
String value();
119
120
/**
121
* A value true for this argument indicates that value of {@link #value()} is already encoded hence engine should not encode it.
122
* @return Whether or not this path parameter is already encoded
123
*/
124
boolean encoded() default false;
125
}
126
127
/**
128
* Annotation to annotate a parameter to be substituted into a query parameter in a REST endpoint URL.
129
*/
130
@Target(ElementType.PARAMETER)
131
@Retention(RetentionPolicy.RUNTIME)
132
@interface QueryParam {
133
/**
134
* The name of the variable in the endpoint URI template which will be replaced with the value of the parameter annotated with this annotation.
135
* @return The name of the variable in the endpoint URI template
136
*/
137
String value();
138
139
/**
140
* A value true for this argument indicates that value of {@link #value()} is already encoded hence engine should not encode it.
141
* @return Whether or not this query parameter is already encoded
142
*/
143
boolean encoded() default false;
144
145
/**
146
* A value true for this argument indicates that the REST API expects multiple parameters with the same name and different values.
147
* @return Whether or not the query parameter supports multiple values
148
*/
149
boolean multipleQueryParams() default false;
150
}
151
152
/**
153
* Annotation to annotate a parameter to be substituted into a header in a REST API request.
154
*/
155
@Target(ElementType.PARAMETER)
156
@Retention(RetentionPolicy.RUNTIME)
157
@interface HeaderParam {
158
/**
159
* The name of the header in the REST API request that the parameter should be added to.
160
* @return The name of the header
161
*/
162
String value();
163
}
164
165
/**
166
* Annotation to annotate a parameter to be substituted into a form parameter in a REST API request.
167
*/
168
@Target(ElementType.PARAMETER)
169
@Retention(RetentionPolicy.RUNTIME)
170
@interface FormParam {
171
/**
172
* The name of the form parameter.
173
* @return The name of the form parameter
174
*/
175
String value();
176
}
177
178
/**
179
* Annotation to annotate a parameter to be sent to a REST endpoint as HTTP request content.
180
*/
181
@Target(ElementType.PARAMETER)
182
@Retention(RetentionPolicy.RUNTIME)
183
@interface BodyParam {
184
/**
185
* Content type that the body should be treated as when sending to the REST API.
186
* @return The Content-Type for the body
187
*/
188
String value();
189
}
190
191
/**
192
* Annotation to annotate a parameter to be substituted into the host for a REST API call.
193
*/
194
@Target(ElementType.PARAMETER)
195
@Retention(RetentionPolicy.RUNTIME)
196
@interface HostParam {
197
/**
198
* The name of the variable in the endpoint URI template which will be replaced with the value of the parameter annotated with this annotation.
199
* @return The name of the variable in the endpoint URI template
200
*/
201
String value();
202
}
203
204
/**
205
* Annotation to annotate a parameter that contains all of the headers for a REST API call.
206
*/
207
@Target(ElementType.PARAMETER)
208
@Retention(RetentionPolicy.RUNTIME)
209
@interface HeaderCollection {
210
/**
211
* The prefix that will be prepended to each header name in the collection.
212
* @return The prefix for header names
213
*/
214
String value() default "";
215
}
216
```
217
218
### Response and Error Handling Annotations
219
220
Annotations for specifying expected responses and exception handling behavior.
221
222
```java { .api }
223
/**
224
* Annotation to annotate list of HTTP status codes that are expected in response from a REST API.
225
*/
226
@Target(ElementType.METHOD)
227
@Retention(RetentionPolicy.RUNTIME)
228
@interface ExpectedResponses {
229
/**
230
* The expected success status codes for the annotated method.
231
* @return The expected success status codes
232
*/
233
int[] value();
234
}
235
236
/**
237
* Annotation for the type of exception that should be thrown when the API returns an error status code.
238
*/
239
@Target(ElementType.METHOD)
240
@Retention(RetentionPolicy.RUNTIME)
241
@interface UnexpectedResponseExceptionType {
242
/**
243
* The exception type to throw when the API returns an unexpected status code.
244
* @return The exception type
245
*/
246
Class<? extends HttpResponseException> value();
247
248
/**
249
* HTTP status codes that should trigger this exception type.
250
* @return Array of status codes
251
*/
252
int[] code() default {};
253
}
254
255
/**
256
* Container annotation for multiple UnexpectedResponseExceptionType annotations.
257
*/
258
@Target(ElementType.METHOD)
259
@Retention(RetentionPolicy.RUNTIME)
260
@interface UnexpectedResponseExceptionTypes {
261
/**
262
* Array of UnexpectedResponseExceptionType annotations.
263
* @return Array of exception type annotations
264
*/
265
UnexpectedResponseExceptionType[] value();
266
}
267
268
/**
269
* Annotation to indicate that the method represents a resumable operation.
270
*/
271
@Target(ElementType.METHOD)
272
@Retention(RetentionPolicy.RUNTIME)
273
@interface ResumeOperation {
274
/**
275
* The name of the operation for resumption.
276
* @return Operation name
277
*/
278
String value() default "";
279
}
280
```
281
282
### Service Definition Annotations
283
284
Annotations for defining service interfaces and client characteristics.
285
286
```java { .api }
287
/**
288
* Annotation for interfaces that represent REST API service interfaces.
289
*/
290
@Target(ElementType.TYPE)
291
@Retention(RetentionPolicy.RUNTIME)
292
@interface ServiceInterface {
293
/**
294
* The name of the service. This is used in telemetry and logging.
295
* @return The name of the service
296
*/
297
String name();
298
}
299
300
/**
301
* Annotation for service client classes.
302
*/
303
@Target(ElementType.TYPE)
304
@Retention(RetentionPolicy.RUNTIME)
305
@interface ServiceClient {
306
/**
307
* The builder class that is used to build instances of the service client.
308
* @return The builder class
309
*/
310
Class<?> builder();
311
312
/**
313
* Indicates whether the service client is asynchronous.
314
* @return true if the service client is asynchronous
315
*/
316
boolean isAsync() default false;
317
318
/**
319
* The service interfaces that this client implements.
320
* @return Array of service interface classes
321
*/
322
Class<?>[] serviceInterfaces() default {};
323
}
324
325
/**
326
* Annotation for service client builder classes.
327
*/
328
@Target(ElementType.TYPE)
329
@Retention(RetentionPolicy.RUNTIME)
330
@interface ServiceClientBuilder {
331
/**
332
* An array of classes that this builder can build.
333
* @return Array of service client classes this builder can create
334
*/
335
Class<?>[] serviceClients();
336
337
/**
338
* The protocol that the built service clients will use to communicate.
339
* @return The service client protocol
340
*/
341
ServiceClientProtocol protocol() default ServiceClientProtocol.HTTP;
342
}
343
344
/**
345
* Annotation for service client methods that perform network operations.
346
*/
347
@Target(ElementType.METHOD)
348
@Retention(RetentionPolicy.RUNTIME)
349
@interface ServiceMethod {
350
/**
351
* The expected return type from the service method.
352
* @return The return type
353
*/
354
ReturnType returns();
355
}
356
```
357
358
### Header and Host Configuration Annotations
359
360
Annotations for configuring headers and host information.
361
362
```java { .api }
363
/**
364
* Annotation for static headers that will be sent to a REST endpoint.
365
*/
366
@Target(ElementType.METHOD)
367
@Retention(RetentionPolicy.RUNTIME)
368
@interface Headers {
369
/**
370
* List of static headers in "name: value" format.
371
* @return Array of header strings
372
*/
373
String[] value();
374
}
375
376
/**
377
* Annotation for specifying the host for REST API calls.
378
*/
379
@Target(ElementType.TYPE)
380
@Retention(RetentionPolicy.RUNTIME)
381
@interface Host {
382
/**
383
* The host URL for the REST service. Can contain parameters enclosed in braces.
384
* @return The host URL
385
*/
386
String value();
387
}
388
```
389
390
### Marker Annotations
391
392
Annotations for marking classes with specific characteristics.
393
394
```java { .api }
395
/**
396
* Annotation for classes that provide a fluent API.
397
*/
398
@Target(ElementType.TYPE)
399
@Retention(RetentionPolicy.RUNTIME)
400
@interface Fluent {
401
// Marker annotation - no methods
402
}
403
404
/**
405
* Annotation for classes that are immutable.
406
*/
407
@Target(ElementType.TYPE)
408
@Retention(RetentionPolicy.RUNTIME)
409
@interface Immutable {
410
// Marker annotation - no methods
411
}
412
413
/**
414
* Annotation for generated classes.
415
*/
416
@Target(ElementType.TYPE)
417
@Retention(RetentionPolicy.RUNTIME)
418
@interface Generated {
419
/**
420
* The name of the code generator.
421
* @return Generator name
422
*/
423
String value() default "";
424
425
/**
426
* Date and time the code was generated.
427
* @return Generation timestamp
428
*/
429
String date() default "";
430
431
/**
432
* Comments about the generation.
433
* @return Generation comments
434
*/
435
String comments() default "";
436
}
437
438
/**
439
* Annotation for JSON flattening in serialization.
440
*/
441
@Target(ElementType.TYPE)
442
@Retention(RetentionPolicy.RUNTIME)
443
@interface JsonFlatten {
444
// Marker annotation for JSON processing
445
}
446
```
447
448
### Supporting Enumerations
449
450
Enumerations used by the annotation system.
451
452
```java { .api }
453
/**
454
* Enumeration of return types for ServiceMethod annotation.
455
*/
456
enum ReturnType {
457
/**
458
* Return type is a single entity.
459
*/
460
SINGLE,
461
462
/**
463
* Return type is a collection or list of entities.
464
*/
465
COLLECTION,
466
467
/**
468
* Return type represents a long-running operation.
469
*/
470
LONG_RUNNING_OPERATION
471
}
472
473
/**
474
* Enumeration of service client protocols.
475
*/
476
enum ServiceClientProtocol {
477
/**
478
* HTTP protocol for REST services.
479
*/
480
HTTP,
481
482
/**
483
* AMQP protocol for message-based services.
484
*/
485
AMQP
486
}
487
```
488
489
## Usage Examples
490
491
### Defining REST Service Interface
492
493
```java
494
import com.azure.core.annotation.*;
495
import com.azure.core.http.rest.Response;
496
import com.azure.core.util.Context;
497
import reactor.core.publisher.Mono;
498
499
@ServiceInterface(name = "UserService")
500
@Host("https://api.example.com")
501
interface UserServiceClient {
502
503
@Get("/users/{userId}")
504
@ExpectedResponses({200})
505
@UnexpectedResponseExceptionType(ResourceNotFoundException.class)
506
Mono<Response<User>> getUser(
507
@PathParam("userId") String userId,
508
@HeaderParam("Accept") String acceptHeader,
509
Context context);
510
511
@Get("/users")
512
@ExpectedResponses({200})
513
@Headers({"Accept: application/json", "User-Agent: MyApp/1.0"})
514
Mono<Response<List<User>>> listUsers(
515
@QueryParam("limit") Integer limit,
516
@QueryParam("offset") Integer offset,
517
@QueryParam("filter") String filter,
518
Context context);
519
520
@Post("/users")
521
@ExpectedResponses({201})
522
@UnexpectedResponseExceptionTypes({
523
@UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = {401, 403}),
524
@UnexpectedResponseExceptionType(value = ResourceExistsException.class, code = {409})
525
})
526
Mono<Response<User>> createUser(
527
@BodyParam("application/json") User user,
528
@HeaderParam("Content-Type") String contentType,
529
Context context);
530
531
@Put("/users/{userId}")
532
@ExpectedResponses({200, 204})
533
Mono<Response<User>> updateUser(
534
@PathParam("userId") String userId,
535
@BodyParam("application/json") User user,
536
Context context);
537
538
@Delete("/users/{userId}")
539
@ExpectedResponses({204})
540
Mono<Response<Void>> deleteUser(
541
@PathParam("userId") String userId,
542
Context context);
543
}
544
```
545
546
### Service Client Implementation
547
548
```java
549
import com.azure.core.annotation.*;
550
551
@ServiceClient(builder = UserServiceClientBuilder.class, isAsync = false)
552
class UserServiceClientImpl {
553
private final UserServiceClient client;
554
555
UserServiceClientImpl(HttpPipeline pipeline) {
556
this.client = RestProxy.create(UserServiceClient.class, pipeline);
557
}
558
559
@ServiceMethod(returns = ReturnType.SINGLE)
560
public User getUser(String userId) {
561
return client.getUser(userId, "application/json", Context.NONE)
562
.block()
563
.getValue();
564
}
565
566
@ServiceMethod(returns = ReturnType.COLLECTION)
567
public List<User> listUsers(Integer limit, Integer offset, String filter) {
568
return client.listUsers(limit, offset, filter, Context.NONE)
569
.block()
570
.getValue();
571
}
572
573
@ServiceMethod(returns = ReturnType.SINGLE)
574
public User createUser(User user) {
575
return client.createUser(user, "application/json", Context.NONE)
576
.block()
577
.getValue();
578
}
579
}
580
```
581
582
### Service Client Builder
583
584
```java
585
import com.azure.core.annotation.ServiceClientBuilder;
586
import com.azure.core.client.traits.*;
587
588
@ServiceClientBuilder(serviceClients = {UserServiceClientImpl.class, UserServiceAsyncClient.class})
589
@Fluent
590
class UserServiceClientBuilder implements
591
HttpTrait<UserServiceClientBuilder>,
592
TokenCredentialTrait<UserServiceClientBuilder>,
593
EndpointTrait<UserServiceClientBuilder> {
594
595
private HttpClient httpClient;
596
private HttpPipeline pipeline;
597
private TokenCredential credential;
598
private String endpoint;
599
private List<HttpPipelinePolicy> policies = new ArrayList<>();
600
601
@Override
602
public UserServiceClientBuilder httpClient(HttpClient httpClient) {
603
this.httpClient = httpClient;
604
return this;
605
}
606
607
@Override
608
public UserServiceClientBuilder pipeline(HttpPipeline pipeline) {
609
this.pipeline = pipeline;
610
return this;
611
}
612
613
@Override
614
public UserServiceClientBuilder addPolicy(HttpPipelinePolicy policy) {
615
this.policies.add(policy);
616
return this;
617
}
618
619
@Override
620
public UserServiceClientBuilder credential(TokenCredential credential) {
621
this.credential = credential;
622
return this;
623
}
624
625
@Override
626
public UserServiceClientBuilder endpoint(String endpoint) {
627
this.endpoint = endpoint;
628
return this;
629
}
630
631
public UserServiceClientImpl buildClient() {
632
HttpPipeline pipeline = buildPipeline();
633
return new UserServiceClientImpl(pipeline);
634
}
635
636
public UserServiceAsyncClient buildAsyncClient() {
637
HttpPipeline pipeline = buildPipeline();
638
return new UserServiceAsyncClient(pipeline);
639
}
640
641
private HttpPipeline buildPipeline() {
642
if (pipeline != null) {
643
return pipeline;
644
}
645
646
List<HttpPipelinePolicy> allPolicies = new ArrayList<>();
647
allPolicies.add(new UserAgentPolicy("UserService/1.0"));
648
649
if (credential != null) {
650
allPolicies.add(new BearerTokenAuthenticationPolicy(credential,
651
"https://api.example.com/.default"));
652
}
653
654
allPolicies.addAll(policies);
655
allPolicies.add(new RetryPolicy());
656
657
return new HttpPipelineBuilder()
658
.httpClient(httpClient != null ? httpClient : HttpClient.createDefault())
659
.policies(allPolicies.toArray(new HttpPipelinePolicy[0]))
660
.build();
661
}
662
}
663
```
664
665
### Complex Parameter Binding
666
667
```java
668
@ServiceInterface(name = "SearchService")
669
interface SearchServiceClient {
670
671
@Get("/search")
672
@ExpectedResponses({200})
673
Mono<Response<SearchResults>> search(
674
@QueryParam("q") String query,
675
@QueryParam("filters", multipleQueryParams = true) List<String> filters,
676
@QueryParam("sort") String sortBy,
677
@QueryParam("limit") Integer limit,
678
@QueryParam("offset") Integer offset,
679
@HeaderCollection("X-Custom-") Map<String, String> customHeaders,
680
Context context);
681
682
@Post("/documents/batch")
683
@ExpectedResponses({200})
684
@Headers({"Content-Type: application/json"})
685
Mono<Response<BatchResult>> batchOperation(
686
@BodyParam("application/json") BatchRequest request,
687
@HeaderParam("X-Request-ID") String requestId,
688
@QueryParam("timeout") Duration timeout,
689
Context context);
690
}
691
692
// Usage
693
Map<String, String> customHeaders = Map.of(
694
"Trace-ID", "trace-123",
695
"Client-Version", "1.0"
696
);
697
698
List<String> filters = List.of(
699
"category:electronics",
700
"price:100-500",
701
"availability:in-stock"
702
);
703
704
searchClient.search("laptop", filters, "price", 20, 0, customHeaders, Context.NONE);
705
```
706
707
### Host Parameter Substitution
708
709
```java
710
@ServiceInterface(name = "MultiRegionService")
711
@Host("https://{accountName}.{region}.example.com")
712
interface MultiRegionServiceClient {
713
714
@Get("/status")
715
@ExpectedResponses({200})
716
Mono<Response<ServiceStatus>> getStatus(
717
@HostParam("accountName") String accountName,
718
@HostParam("region") String region,
719
Context context);
720
721
@Get("/data/{dataId}")
722
@ExpectedResponses({200})
723
Mono<Response<Data>> getData(
724
@HostParam("accountName") String accountName,
725
@HostParam("region") String region,
726
@PathParam("dataId") String dataId,
727
Context context);
728
}
729
730
// Usage - different regions and accounts
731
client.getStatus("myaccount", "us-west-2", Context.NONE);
732
client.getData("myaccount", "eu-west-1", "data123", Context.NONE);
733
```
734
735
### Form Data and File Uploads
736
737
```java
738
@ServiceInterface(name = "FileService")
739
interface FileServiceClient {
740
741
@Post("/upload")
742
@ExpectedResponses({200, 201})
743
Mono<Response<FileMetadata>> uploadFile(
744
@FormParam("filename") String filename,
745
@FormParam("description") String description,
746
@FormParam("tags") List<String> tags,
747
@BodyParam("application/octet-stream") BinaryData fileData,
748
Context context);
749
750
@Post("/forms/submit")
751
@ExpectedResponses({200})
752
@Headers({"Content-Type: application/x-www-form-urlencoded"})
753
Mono<Response<FormResult>> submitForm(
754
@FormParam("name") String name,
755
@FormParam("email") String email,
756
@FormParam("message") String message,
757
Context context);
758
}
759
```
760
761
### Long Running Operations
762
763
```java
764
@ServiceInterface(name = "ProcessingService")
765
interface ProcessingServiceClient {
766
767
@Post("/process")
768
@ExpectedResponses({202})
769
@ServiceMethod(returns = ReturnType.LONG_RUNNING_OPERATION)
770
Mono<Response<ProcessingOperation>> startProcessing(
771
@BodyParam("application/json") ProcessingRequest request,
772
Context context);
773
774
@Get("/operations/{operationId}")
775
@ExpectedResponses({200})
776
@ResumeOperation
777
Mono<Response<ProcessingOperation>> getOperation(
778
@PathParam("operationId") String operationId,
779
Context context);
780
781
@Delete("/operations/{operationId}")
782
@ExpectedResponses({204})
783
Mono<Response<Void>> cancelOperation(
784
@PathParam("operationId") String operationId,
785
Context context);
786
}
787
```
788
789
### Generated Model Classes
790
791
```java
792
@Generated("AutoRest")
793
@Fluent
794
@JsonFlatten
795
class User {
796
private String id;
797
private String name;
798
private String email;
799
private Map<String, Object> additionalProperties;
800
801
// Getters and setters...
802
}
803
804
@Generated("AutoRest")
805
@Immutable
806
class UserList {
807
private final List<User> users;
808
private final String continuationToken;
809
810
UserList(List<User> users, String continuationToken) {
811
this.users = users;
812
this.continuationToken = continuationToken;
813
}
814
815
// Getters only (immutable)...
816
}
817
```