Status codes and Response
The status code is the first thing an API client sees: did it work, was the record created, does it exist. When a resource method returns an object, Jakarta REST answers 200 OK. When you need another code or extra headers, the method returns a Response object — a full description of the reply: status, headers and body.
Main status codes
| Code | When it is used |
|---|---|
200 OK | Data received |
201 Created | Record created, its address is in the Location header |
204 No Content | Success without a body: for example after a delete |
400 Bad Request | An error in the client's data |
404 Not Found | No such record |
415 Unsupported Media Type | Wrong Content-Type |
500 Internal Server Error | An unhandled exception on the server |
The post or 404
Add a delete method to PostStore that reports whether the post existed:
// src/main/java/com/example/blog/PostStore.java (fragment)
public boolean delete(long id) {
return posts.remove(id) != null;
}Now the methods of the resource src/main/java/com/example/blog/PostResource.java:
// src/main/java/com/example/blog/PostResource.java (fragment)
@GET
@Path("/{id}")
public Response show(@PathParam("id") long id) {
return store.findById(id)
.map(post -> Response.ok(post).build())
.orElse(Response.status(Response.Status.NOT_FOUND).build());
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response create(NewPost data, @Context UriInfo uriInfo) {
Post post = store.add(data);
URI location = uriInfo.getAbsolutePathBuilder()
.path(String.valueOf(post.id()))
.build();
return Response.created(location).entity(post).build();
}
@DELETE
@Path("/{id}")
public void delete(@PathParam("id") long id) {
if (!store.delete(id)) {
throw new NotFoundException("Post " + id + " not found");
}
}The imports you need are jakarta.ws.rs.DELETE, jakarta.ws.rs.NotFoundException, jakarta.ws.rs.core.Context, jakarta.ws.rs.core.Response, jakarta.ws.rs.core.UriInfo and java.net.URI.
What happens here:
showreturnsResponse.ok(post)or a 404 response without a body.createbuilds the address of the new post from the address of the current request. The server passesUriInfothrough@Context.Response.created(location)gives status 201 and aLocationheader.deletereturns nothing — for avoidmethod Jakarta REST answers 204. TheNotFoundExceptionbecomes a 404 response.
Trying it out
curl -i -H "Content-Type: application/json" -d '{"title":"Status codes","body":"201, 204 and 404."}' http://localhost:8080/blog/api/postsHTTP/1.1 201 Created
Content-Type: application/json
Location: http://localhost:8080/blog/api/posts/3
Content-Length: 83
{"body":"201, 204 and 404.","createdAt":"2026-10-04","id":3,"title":"Status codes"}
curl -i -X DELETE http://localhost:8080/blog/api/posts/3
curl -i -X DELETE http://localhost:8080/blog/api/posts/3
curl -i http://localhost:8080/blog/api/posts/99The first delete returns HTTP/1.1 204 No Content, the second HTTP/1.1 404 Not Found: the post is already gone. Requesting a missing post also gives 404.
Ready-made exceptions
Instead of a Response you can throw an exception — Jakarta REST turns it into a status code:
| Exception | Code |
|---|---|
BadRequestException | 400 |
NotAuthorizedException | 401 |
ForbiddenException | 403 |
NotFoundException | 404 |
WebApplicationException(status) | Any |
Common mistake
Returning null from a method that should return an object. In the previous lesson show returned store.findById(id).orElse(null), and a request for a missing post ended like this:
HTTP/1.1 204 No Content
The client sees success and an empty body instead of an error. When the record does not exist, answer 404 — with a Response or an exception.