I have to following endpoint structure in Jersey:
/objects/
/objects/:id
/objects/:id/:field
/objects/:id/:field/:subfield
The IDs I'm using have a very specific format, so I first check if the format is valid before making a request to the database.
Right now I have to put this code in each of the POST
, PUT
, GET
, DELETE
functions for each of the functions that has :id
as a parameter. So this just means an early return.
if (!isIdValid(id)){
return Response.status(Response.StatusType.BAD_REQUEST)
.entity("The ID you've provided is invalid")
.build();
}
(In reality the error entity is an object containing more information about the error)
And then for each function using the :field
or :subfield
parameters the code is similar. This checking and error-handling behavior has to be copied every time. And when I start copy-pasting stuff, I start thinking: there should be a better way?
I would like to place the :id
checking code at the the /objects/:id
level, and then all further nested levels are assumed have a valid ID. The same for the other parameters further nesting down.
I've been looking into using subresource locators, but then you create a function returning a new instance of the subresource. I can't put a conditional return of a Response
-object at that level for if the validation fails.
@Path("{id}")
function Class<ObjectFieldResource> getObjectById(@PathParam("id") String id){
return ObjectFieldResource.class;
}
I could start throwing exceptions, but I would rather avoid that, since I don't really consider invalid input to be an exception .
How would such a structure best be implemented? I've looked at bean validation but that doesn't seem to allow me to define validation for my specific format + custom error responses.
Am I missing something in the way subresources should be implemented?
If you can use regexp checks instead of your isIdValid
method it's possible to define your resources like this
@POST
@Path("objects/{id:\\d+}")
public Response doSmth(@PathParam("id") String id) {
...
}
In a case of invalid id
format caller will have 'Not Found' response status without even reaching your doSmth
method.
Obviously, you can use String constants for all equal path values.
final static String ID_RES = "objects/{id:\\d+}";
@POST
@Path(ID_RES)
public Response postSmth(@PathParam("id") String id) {
...
}
...
@GET
@Path(ID_RES)
public Object getSmth(@PathParam("id") String id) {
...
}
The can also read full description of Path#value
parameter
Create and register at your REST server javax.ws.rs.container.ContainerRequestFilter
implementation with filter
method having needed URI checks.
The single filter parameter has ContainerRequestContext
type from witch you can call getUriInfo
for getting URI and method abortWith(Response response)
which can be used for aborting caller request if your resource ids validation was failed.
See Chapter 10. Filters and Interceptors chapter of Jersey Manual.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.