The HAPI FHIR Plain Server (RestfulServer) is implemented as a standard JEE Servlet, meaning that it can be deployed in any compliant JEE web container.
For users who already have an existing JAX-RS infrastructure, and who would like to use that technology for their FHIR stack as well, a module exists which implements the server using JAX-RS technology.
The server currently supports:
The primary intention for this project is to ensure that other web technologies (JAX-RS in this case) can be used together with the base-server functionality. An example server can be found in the Git repo here.
The set-up of a JAX-RS server goes beyond the scope of this documentation. The implementation of the server follows the same pattern as the standard server. It is required to put the correct annotation on the methods in the Resource Providers in order to be able to call them.
Implementing a JAX-RS Resource Provider requires some JAX-RS annotations. The @Path annotation needs to define the resource path. The @Produces
annotation needs to declare the produced formats. The constructor needs to pass the class of the object explicitly in order to avoid problems with proxy classes in a Java EE environment.
It is necessary to extend the abstract class AbstractJaxRsResourceProvide.
@Path("/Patient")
@Produces({MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML})
public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider<Patient> {
public JaxRsPatientRestProvider() {
super(JaxRsPatientRestProvider.class);
}
Extended Operations require the correct JAX-RS ( @Path, @GET or @POST annotations. The body of the method needs to call the method [AbstractJaxRsResourceProvider#customOperation](/hapi-fhir/apidocs/hapi-fhir-jaxrsserver-base/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.html#customOperation(java.lang.String,ca.uhn.fhir.rest.api.RequestTypeEnum,java.lang.String,java.lang.String,ca.uhn.fhir.rest.api.RestOperationTypeEnum) with the correct parameters. The server will then call the method with corresponding name.
@GET
@Path("/{id}/$someCustomOperation")
public Response someCustomOperationUsingGet(@PathParam("id") String id, String resource) throws Exception {
return customOperation(
resource,
RequestTypeEnum.GET,
id,
"$someCustomOperation",
RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
}
@Operation(
name = "someCustomOperation",
idempotent = true,
returnParameters = {@OperationParam(name = "return", type = StringDt.class)})
public Parameters someCustomOperation(@IdParam IdType myId, @OperationParam(name = "dummy") StringDt dummyInput) {
Parameters parameters = new Parameters();
parameters.addParameter().setName("return").setValue(new StringType("My Dummy Result"));
return parameters;
}
In order to create the conformance profile, a conformance provider class needs to be deployed which exports the provider's conformance statements. These providers need to be returned as the result of the method AbstractJaxRsConformanceProvider#getProviders. This method is called once, during PostConstruct.
@Path("")
@Stateless
@Produces({MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML})
public class JaxRsConformanceProvider extends AbstractJaxRsConformanceProvider {
@EJB
private JaxRsPatientRestProvider provider;
public JaxRsConformanceProvider() {
super("My Server Description", "My Server Name", "My Server Version");
}
@Override
protected ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider> getProviders() {
ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider> map =
new ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider>();
map.put(JaxRsConformanceProvider.class, this);
map.put(JaxRsPatientRestProvider.class, provider);
return map;
}
}
A complete example showing how to implement a JAX-RS RESTful server can be found in our Git repo here: