0
# REST API Development
1
2
Jersey (JAX-RS) integration for building RESTful web services with automatic JSON serialization, validation, and metrics collection.
3
4
## Capabilities
5
6
### Jersey Environment
7
8
The Jersey environment provides methods for registering JAX-RS resources, providers, filters, and other components.
9
10
```java { .api }
11
package io.dropwizard.jersey.setup;
12
13
public class JerseyEnvironment {
14
/**
15
* Registers a JAX-RS component (resource, provider, filter, etc.).
16
*/
17
public void register(Object component);
18
19
/**
20
* Registers a JAX-RS component class.
21
*/
22
public void register(Class<?> componentClass);
23
24
/**
25
* Registers all JAX-RS components in the given packages.
26
*/
27
public void packages(String... packages);
28
29
/**
30
* Registers all JAX-RS components in the given packages recursively.
31
*/
32
public void packages(boolean recursive, String... packages);
33
34
/**
35
* Returns the Jersey resource configuration.
36
*/
37
public DropwizardResourceConfig getResourceConfig();
38
39
/**
40
* Sets the URL pattern for Jersey servlet.
41
*/
42
public void setUrlPattern(String urlPattern);
43
}
44
```
45
46
**Usage Example:**
47
48
```java
49
@Override
50
public void run(MyConfiguration configuration, Environment environment) {
51
// Register individual resources
52
environment.jersey().register(new HelloWorldResource());
53
environment.jersey().register(new UserResource());
54
55
// Register all resources in a package
56
environment.jersey().packages("com.example.resources");
57
58
// Register providers and filters
59
environment.jersey().register(new CORSFilter());
60
environment.jersey().register(new LoggingFilter());
61
}
62
```
63
64
### JAX-RS Resource Development
65
66
Standard JAX-RS annotations and patterns for building REST endpoints with Dropwizard enhancements.
67
68
```java { .api }
69
// Path and HTTP method annotations
70
@Path("/users")
71
@GET @POST @PUT @DELETE @HEAD @OPTIONS
72
73
// Content type annotations
74
@Produces(MediaType.APPLICATION_JSON)
75
@Consumes(MediaType.APPLICATION_JSON)
76
77
// Parameter annotations
78
@PathParam("id") @QueryParam("name") @FormParam("value")
79
@HeaderParam("X-Custom") @CookieParam("session")
80
81
// Validation annotations
82
@Valid @NotNull @NotEmpty
83
84
// Dropwizard metric annotations
85
@Timed @Metered @Counted @ExceptionMetered
86
87
// Caching annotations
88
@CacheControl(maxAge = 300, maxAgeUnit = TimeUnit.SECONDS)
89
```
90
91
**Usage Example:**
92
93
```java
94
@Path("/users")
95
@Produces(MediaType.APPLICATION_JSON)
96
@Consumes(MediaType.APPLICATION_JSON)
97
public class UserResource {
98
private final UserService userService;
99
100
public UserResource(UserService userService) {
101
this.userService = userService;
102
}
103
104
@GET
105
@Timed(name = "get-users")
106
@CacheControl(maxAge = 5, maxAgeUnit = TimeUnit.MINUTES)
107
public List<User> getUsers(@QueryParam("active") @DefaultValue("true") boolean active,
108
@QueryParam("limit") @DefaultValue("100") @Range(min = 1, max = 1000) int limit) {
109
return userService.findUsers(active, limit);
110
}
111
112
@GET
113
@Path("/{id}")
114
@Timed(name = "get-user-by-id")
115
public Optional<User> getUser(@PathParam("id") @NotNull Long id) {
116
return userService.findById(id);
117
}
118
119
@POST
120
@Timed(name = "create-user")
121
public Response createUser(@Valid @NotNull User user, @Context UriInfo uriInfo) {
122
User created = userService.create(user);
123
URI location = uriInfo.getAbsolutePathBuilder()
124
.path(created.getId().toString())
125
.build();
126
return Response.created(location).entity(created).build();
127
}
128
129
@PUT
130
@Path("/{id}")
131
@Timed(name = "update-user")
132
public User updateUser(@PathParam("id") @NotNull Long id,
133
@Valid @NotNull User user) {
134
return userService.update(id, user);
135
}
136
137
@DELETE
138
@Path("/{id}")
139
@Timed(name = "delete-user")
140
public Response deleteUser(@PathParam("id") @NotNull Long id) {
141
userService.delete(id);
142
return Response.noContent().build();
143
}
144
}
145
```
146
147
### Exception Handling
148
149
Custom exception mappers for converting exceptions to HTTP responses with proper status codes and error messages.
150
151
```java { .api }
152
package javax.ws.rs.ext;
153
154
@Provider
155
public interface ExceptionMapper<T extends Throwable> {
156
/**
157
* Maps an exception to a Response.
158
*/
159
Response toResponse(T exception);
160
}
161
```
162
163
**Usage Example:**
164
165
```java
166
@Provider
167
public class ValidationExceptionMapper implements ExceptionMapper<ConstraintViolationException> {
168
@Override
169
public Response toResponse(ConstraintViolationException exception) {
170
List<String> errors = exception.getConstraintViolations()
171
.stream()
172
.map(ConstraintViolation::getMessage)
173
.collect(Collectors.toList());
174
175
return Response.status(Response.Status.BAD_REQUEST)
176
.entity(new ErrorResponse("Validation failed", errors))
177
.build();
178
}
179
}
180
181
// Register the exception mapper
182
environment.jersey().register(new ValidationExceptionMapper());
183
```
184
185
### Response Filters and Providers
186
187
JAX-RS providers for custom request/response processing including filters, interceptors, and message body readers/writers.
188
189
```java { .api }
190
package javax.ws.rs.container;
191
192
@Provider
193
public interface ContainerRequestFilter {
194
void filter(ContainerRequestContext requestContext) throws IOException;
195
}
196
197
@Provider
198
public interface ContainerResponseFilter {
199
void filter(ContainerRequestContext requestContext,
200
ContainerResponseContext responseContext) throws IOException;
201
}
202
```
203
204
**Usage Example:**
205
206
```java
207
@Provider
208
public class CORSFilter implements ContainerResponseFilter {
209
@Override
210
public void filter(ContainerRequestContext requestContext,
211
ContainerResponseContext responseContext) throws IOException {
212
responseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
213
responseContext.getHeaders().add("Access-Control-Allow-Methods",
214
"GET, POST, PUT, DELETE, OPTIONS");
215
responseContext.getHeaders().add("Access-Control-Allow-Headers",
216
"Content-Type, Authorization");
217
}
218
}
219
220
@Provider
221
@PreMatching
222
public class LoggingFilter implements ContainerRequestFilter {
223
private static final Logger LOGGER = LoggerFactory.getLogger(LoggingFilter.class);
224
225
@Override
226
public void filter(ContainerRequestContext requestContext) throws IOException {
227
LOGGER.info("Processing {} request to {}",
228
requestContext.getMethod(),
229
requestContext.getUriInfo().getPath());
230
}
231
}
232
```
233
234
### JSON Configuration
235
236
Customize Jackson ObjectMapper configuration for JSON serialization and deserialization.
237
238
```java { .api }
239
package io.dropwizard.jackson;
240
241
public class ObjectMapperFactory {
242
/**
243
* Builds a new ObjectMapper with the configured settings.
244
*/
245
public ObjectMapper build();
246
247
/**
248
* Configures property naming strategy.
249
*/
250
public void setPropertyNamingStrategy(PropertyNamingStrategy strategy);
251
252
/**
253
* Configures serialization inclusion.
254
*/
255
public void setSerializationInclusion(JsonInclude.Include inclusion);
256
}
257
```
258
259
**Usage Example:**
260
261
```java
262
@Override
263
public void initialize(Bootstrap<MyConfiguration> bootstrap) {
264
// Configure JSON serialization
265
bootstrap.getObjectMapper()
266
.registerModule(new JavaTimeModule())
267
.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
268
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
269
}
270
271
// Custom JSON views
272
public class Views {
273
public static class Public {}
274
public static class Internal extends Public {}
275
}
276
277
public class User {
278
@JsonView(Views.Public.class)
279
private String name;
280
281
@JsonView(Views.Internal.class)
282
private String email;
283
284
// getters and setters
285
}
286
287
@GET
288
@JsonView(Views.Public.class)
289
public List<User> getPublicUsers() {
290
return userService.findAll();
291
}
292
```
293
294
### Custom Providers
295
296
Implement custom message body readers and writers for handling specific content types or data formats.
297
298
```java { .api }
299
package javax.ws.rs.ext;
300
301
@Provider
302
@Consumes("text/csv")
303
public interface MessageBodyReader<T> {
304
boolean isReadable(Class<?> type, Type genericType,
305
Annotation[] annotations, MediaType mediaType);
306
307
T readFrom(Class<T> type, Type genericType, Annotation[] annotations,
308
MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
309
InputStream entityStream) throws IOException, WebApplicationException;
310
}
311
312
@Provider
313
@Produces("text/csv")
314
public interface MessageBodyWriter<T> {
315
boolean isWriteable(Class<?> type, Type genericType,
316
Annotation[] annotations, MediaType mediaType);
317
318
void writeTo(T t, Class<?> type, Type genericType,
319
Annotation[] annotations, MediaType mediaType,
320
MultivaluedMap<String, Object> httpHeaders,
321
OutputStream entityStream) throws IOException, WebApplicationException;
322
}
323
```
324
325
## Response Handling
326
327
### Response Types
328
329
Standard JAX-RS response patterns for different HTTP scenarios.
330
331
```java
332
// Simple entity response
333
return user;
334
335
// Response with status code
336
return Response.ok(user).build();
337
return Response.status(201).entity(user).build();
338
339
// Created resource with location header
340
URI location = uriInfo.getAbsolutePathBuilder().path("123").build();
341
return Response.created(location).entity(user).build();
342
343
// No content response
344
return Response.noContent().build();
345
346
// Error responses
347
return Response.status(400).entity(errorMessage).build();
348
return Response.status(404).build();
349
350
// Optional responses
351
Optional<User> user = userService.findById(id);
352
return user.map(Response::ok)
353
.orElse(Response.status(404))
354
.build();
355
```