简体   繁体   中英

Jersey reuse parameter validation for subresources

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?

Solution 1

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

Solution 2

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM