Reputation: 1021
I have a web application implementing REST API using Jersey. The web container id Tomcat
Here is a summary of the API:
/rest/patients
Gets a list of patients' metadata.
/rest/patients/{id}
Gets detailed data about a specific patient.
/rest/patients/{id}/visits
Gets a list of visits` metadata for a specific patient.
/rest/patients/{id}/visits/{visitId}
Gets detailed data about a specific visit of a specific patient.
My problem is that I can't get the sub-sub resources. For example, when I request /rest/patients/1
the detailed data of patient #1 is received correctly.
But when I request /rest/patients/1/visits
I get 404 error, and the flow doesn't even enter the getVisits()
method.
It looks like that when a request for a specific patient id received (patients/{id}
), Jersey is directing it correctly from PatientsMetadataResource
to PatientsResource
.
But when a visits sub-sub-resource is being requested (patients/{id}/visits
), Jersey doesn't direct it into the PatientsResource
.
So how can I direct a sub resource along with all of its sub-sub resources into the same class?
Code for PatientsMetadataResource
(The name is a bit vague, and I need to change it):
@Path("/patients")
public class PatientsMetadataResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getPatients(@QueryParam("page") int pageIndex) {
//.... Loads, Builds and returns the patients' metadata list correctly
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{uid:\\d+}")
public PatientResource getPatient(@PathParam("uid") int uid) {
return new PatientResource(uid);
}
}
Code for PatientResource
:
public class PatientResource {
private final int uid;
public PatientResource(int uid) {
this.uid = uid;
}
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getPatient() {
//Returns the patient correctly
System.out.println("A Patient was asked");
Patient patient = PersistentDataProvider.loadPatientByUid(uid);
return Response.ok(patient).build();
}
@GET
@Path("/visits")
@Produces(MediaType.APPLICATION_JSON)
public VisitsResource getVisits(@PathParam("uid") int patientUid) {
//The flow doesn't even enter here. A 404 is being returned instead.
System.out.println("Visits were asked");
return new VisitsResource(patientUid);
}
}
Code for Jersey part in web.xml:
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>
com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>il.co.site_building.dvardy.resources</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Upvotes: 1
Views: 1153
Reputation: 208944
Sub-Resource Locators aren't supposed to have HTTP method annotations
// @GET <--- Remove this
// @Produces(MediaType.APPLICATION_JSON)
@Path("/{uid:\\d+}")
public PatientResource getPatient(@PathParam("uid") int uid) {
return new PatientResource(uid);
}
Their main purpose is simply to forward request to the sub-resource class, not GET/POST/etc anything. When Jersey sees that HTTP method annotation, it no longer gets treated as a sub-resource locator.
Also you don't need need to pass the id. It will get passed accordingly
@Path("parent")
class ParentResource {
@Path("{id}")
public ChildResource getChild() {
return new ChildResource();
}
}
class ChildResource {
@GET
public Response get(@PathParam("id") long id) {}
@GET
@Path("something")
public Response something(@PathParam("id") long id) {}
}
Here GET 'parent/1' goes to ChildResource.get
, passing the path param and GET parent/1/something
goes to ChilsResource.something
, passing the path param
Upvotes: 2