HAPI FHIR HELP on Create and Update

1,327 views
Skip to first unread message

Stan Zajdel

unread,
Dec 8, 2017, 9:57:54 AM12/8/17
to HAPI FHIR
Hi All,

I'm new to FHIR and HAPI FHIR and I'm tasked with building a CDR which is a relational database of tables that address most of the FHIR resources (DSTU 3).  So for instance, from a Patient Resource, we have a series of tables (one to many) that house patient contacts, patient identifiers, patient languages, patient addresses, etc and I have built DAOs that access those tables.  Our front ends will be mobile apps, web apps and otther channels that will be consuming the HAPI FHIR-based APIs (REST services) that I am developing.  As of now, all of my Reads and Searches are working beautifully and returning all data per the JSON format as specified in the FHIR spec (using the HAPI Resource classes).  However, I cannot get a Create or Update to work and I've been reading the HAPI docs but not having much luck. 

According to the docs, the Create and Update expect a ResourceParam of the resourvce that needs to be added or updated.  It also allows for the raw data to be sent as well.  I am getting the following error no matter what I try:

2017-12-08 08:10:40,697 WARN  [ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor] (default task-2) Failure during REST processing: ca.uhn.fhir.rest.server.exceptions.InvalidRequestException: Invalid request: The FHIR endpoint on this server does not know how to handle OPTIONS operation[Patient] with parameters [[]]
2017-12-08 08:10:40,698 INFO  [cdrfhir.RequestLogger] (default task-2) ERROR -  - Patient

I have no idea how to get this to work.  Also, is it possible to only send in the raw data and not the actual resource to a Create or Update?  The reason being is that from a mobile app, a patient address may be created or updated and the app may not be able to send the entire Patient JSON back to the server.  I would much rather parse the raw data myself and create/update what is requested so is there any way to do that?  

Any help on this would be GREATLY appreciated and if you need any more details from me then please let me know.

Thanks,
Stan
 

James Agnew

unread,
Dec 8, 2017, 10:32:05 AM12/8/17
to Stan Zajdel, HAPI FHIR
The error "The FHIR endpoint on this server does not know how to handle OPTIONS operation[Patient] with parameters [[]]" would indicate that they are making an HTTP OPTIONS request instead of a POST.

This could either indicate that you have a CORS issue and need to add a CORS interceptor/filter, or it could indicate that your client has a bug.

Cheers,
James


--
You received this message because you are subscribed to the Google Groups "HAPI FHIR" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hapi-fhir+unsubscribe@googlegroups.com.
To post to this group, send email to hapi...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/hapi-fhir/1d84355b-fdca-4c55-8e4f-32d26ad41886%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Stan Zajdel

unread,
Dec 8, 2017, 11:47:21 AM12/8/17
to HAPI FHIR
Hi James,

I have just solved that problem by adding the CORS filter so now I am still working on successfully passing in the json.  I do have a question though:

My FHIR api will be called from various different channels (mobile, tablet, desktop, TV, etc) and even though I am passing back complete json payloads of any resource that is being called however, when either an insert or an update is requested, most of the time only that piece of data will be available to be sent back to the server (Create or Update) so if a new patient address or contact or language is added then only that will be available to be sent back so i'm not sure if this will pass validation since only partial info will be available so i'm wondering if in both the Create and Update of a resource if I can just get the raw body back from the calling program and then I can do my own parsing and updating of my database via my DAOs.  In other words, is it an absolute requirement that a resource class such as Patient, Practitioner, etc needs to always be passed into the Create and Update methods in the Java resource?  I'm hoping that the answer is no and that I can just get the raw body.

Any and all help on this would be greatly appreciated.  Also, you had met my colleague, Mike Gould, down in NO this week.

Thank,s
Stan


On Friday, December 8, 2017 at 10:32:05 AM UTC-5, James Agnew wrote:
The error "The FHIR endpoint on this server does not know how to handle OPTIONS operation[Patient] with parameters [[]]" would indicate that they are making an HTTP OPTIONS request instead of a POST.

This could either indicate that you have a CORS issue and need to add a CORS interceptor/filter, or it could indicate that your client has a bug.

Cheers,
James

On Fri, Dec 8, 2017 at 9:57 AM, Stan Zajdel <c62...@gmail.com> wrote:
Hi All,

I'm new to FHIR and HAPI FHIR and I'm tasked with building a CDR which is a relational database of tables that address most of the FHIR resources (DSTU 3).  So for instance, from a Patient Resource, we have a series of tables (one to many) that house patient contacts, patient identifiers, patient languages, patient addresses, etc and I have built DAOs that access those tables.  Our front ends will be mobile apps, web apps and otther channels that will be consuming the HAPI FHIR-based APIs (REST services) that I am developing.  As of now, all of my Reads and Searches are working beautifully and returning all data per the JSON format as specified in the FHIR spec (using the HAPI Resource classes).  However, I cannot get a Create or Update to work and I've been reading the HAPI docs but not having much luck. 

According to the docs, the Create and Update expect a ResourceParam of the resourvce that needs to be added or updated.  It also allows for the raw data to be sent as well.  I am getting the following error no matter what I try:

2017-12-08 08:10:40,697 WARN  [ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor] (default task-2) Failure during REST processing: ca.uhn.fhir.rest.server.exceptions.InvalidRequestException: Invalid request: The FHIR endpoint on this server does not know how to handle OPTIONS operation[Patient] with parameters [[]]
2017-12-08 08:10:40,698 INFO  [cdrfhir.RequestLogger] (default task-2) ERROR -  - Patient

I have no idea how to get this to work.  Also, is it possible to only send in the raw data and not the actual resource to a Create or Update?  The reason being is that from a mobile app, a patient address may be created or updated and the app may not be able to send the entire Patient JSON back to the server.  I would much rather parse the raw data myself and create/update what is requested so is there any way to do that?  

Any help on this would be GREATLY appreciated and if you need any more details from me then please let me know.

Thanks,
Stan
 

--
You received this message because you are subscribed to the Google Groups "HAPI FHIR" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hapi-fhir+...@googlegroups.com.

James Agnew

unread,
Dec 8, 2017, 12:00:25 PM12/8/17
to Stan Zajdel, HAPI FHIR
Hi Stan,

You may want to look at the PATCH operation for that. Note that HAPI FHIR JPA currently supports XML patch and JSON patch, but not FHIR Patch.

Cheers,
James

To unsubscribe from this group and stop receiving emails from it, send an email to hapi-fhir+unsubscribe@googlegroups.com.

To post to this group, send email to hapi...@googlegroups.com.

Stan Zajdel

unread,
Dec 8, 2017, 9:44:18 PM12/8/17
to HAPI FHIR
Hi James,

Is it possible to include another plain servlet along with the FHIR servlet that would handle all POST and PUT requests?  The reason that I'm asking this is that responses can come from just about any channel and since i have a relational database that serves as the overall repository, I would need total control of the data coming in.  I am seeing that most of the HAPI examples that are out there seem to interact with all JSON via the many HAPI methods which is different than my implementation.  Anyway, I did try to create a plain old servlet in the same WAR as the FHIR servlet but it doesn't seem to want to play together.  Any suggestions?

Thanks and I do appreciate your help.
Stan 

James Agnew

unread,
Dec 8, 2017, 11:53:56 PM12/8/17
to Stan Zajdel, HAPI FHIR
HAPI's restful server is a standard JEE Servlet, so yup- there should be no issues including another servlet in the same WAR.

This isn't an architecture I can point to any specific examples of though unfortunately.

Cheers,
James

To unsubscribe from this group and stop receiving emails from it, send an email to hapi-fhir+unsubscribe@googlegroups.com.

To post to this group, send email to hapi...@googlegroups.com.

Kevin Mayfield

unread,
Dec 9, 2017, 3:12:52 AM12/9/17
to James Agnew, Stan Zajdel, HAPI FHIR
Hi Stan,

I believe your requirement is similar to what we are implementing here http://yellow.testlab.nhs.uk/careconnect-ri/
(The links point to more detailed description of what we are doing - it’s like a UK version of HSPC)

The server on there isn’t the actual Fhir (hapi) server. It’s a gateway or service interceptor using hapi restful server and apache camel.
We done this so we can add in new channels (next one being OAuth), with just minor config changes. Also to handle message bundles (we will break these down to individual resources) and audits coming from our ELK stack. 



Sent from my iPhone

Stan Zajdel

unread,
Dec 9, 2017, 2:31:35 PM12/9/17
to HAPI FHIR
Thanks for your help James, I think that's the route that i'm going to take at this point.

Stan

granad...@gmail.com

unread,
Mar 11, 2019, 9:34:12 AM3/11/19
to HAPI FHIR

Sez,

Could you provide a few more technical details ( example source code?) of how you did : "by adding a CORS filter"...so the community at large can learn from it?

Thank you.

........................

Invalid request: The FHIR endpoint on this server does not know how to handle OPTIONS operation

I am receiving the same error.



{
    "resourceType": "OperationOutcome",
    "issue": [
        {
            "severity": "error",
            "code": "processing",
            "diagnostics": "Invalid request: The FHIR endpoint on this server does not know how to handle OPTIONS operation[Measure/xxxxxxx/$submit-data] with parameters [[]]"
        }
    ]
}

I did follow the instructions here:



My code below:

import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.interceptor.CorsInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.web.cors.CorsConfiguration;

import java.util.Arrays;

@Configuration
public class CorsFhirRestfulServerCustomizer implements FhirRestfulServerCustomizer {

@Override
public void customize(RestfulServer server) {

/* http://hapifhir.io/doc_cors.html#_toc_hapi_fhir_server_interceptor */

CorsConfiguration config = new CorsConfiguration();
//config.applyPermitDefaultValues();

config.addAllowedMethod("*");
//config.setAllowedMethods(Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name(), HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.OPTIONS.name(), HttpMethod.PATCH.name(), HttpMethod.TRACE.name())); //"GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"));
// purposely ignoring //config.addAllowedOrigin("*");
// purposely ignoring //config.addAllowedHeader("*"); // * throws an exception

/*
config.addAllowedHeader("x-fhir-starter");
config.addAllowedHeader("Origin");
config.addAllowedHeader("Accept");
config.addAllowedHeader("X-Requested-With");
config.addAllowedHeader("Content-Type");
config.addAllowedOrigin("*");

config.addExposedHeader("Location");
config.addExposedHeader("Content-Location");
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"));
*/

// Create the interceptor and register it
CorsInterceptor interceptor = new CorsInterceptor(config);
server.registerInterceptor(interceptor);
}
}

(although currently I am manually adding the FhirRestfulServerCustomizer to the "list" as seen below ( I haven't seen alot/any examples of "implements FhirRestfulServerCustomizer" )


private /*final*/ List<FhirRestfulServerCustomizer> customizers;

public FhirRestfulServerConfiguration(
FhirProperties properties,
FhirContext fhirContext,
ObjectProvider<List<IResourceProvider>> resourceProviders,
ObjectProvider<IPagingProvider> pagingProvider,
ObjectProvider<List<IServerInterceptor>> interceptors,
ObjectProvider<List<FhirRestfulServerCustomizer>> customizers) {
this.properties = properties;
this.fhirContext = fhirContext;
this.resourceProviders = resourceProviders.getIfAvailable();
this.pagingProvider = pagingProvider.getIfAvailable();
this.interceptors = interceptors.getIfAvailable();
this.customizers = customizers.getIfAvailable();

if(null==this.customizers)
{
this.customizers = new ArrayList<>();
}

this.customizers.add(new
CorsFhirRestfulServerCustomizer());

}




Here may be a mini explanation. (not an answer, but a mini explanation)

granad...@gmail.com

unread,
Mar 11, 2019, 3:50:24 PM3/11/19
to HAPI FHIR

I hope this helps someone.

The error I was getting:

{
    "resourceType": "OperationOutcome",
    "issue": [
        {
            "severity": "error",
            "code": "processing",
            "diagnostics": "Invalid request: The FHIR endpoint on this server does not know how to handle OPTIONS operation[Measure/MyMeasureNameId/$submit-data] with parameters [[]]"
        }
    ]
}


What did I try?

I tried a custom WebMvcConfigurer

import org.springframework.context.annotation.Configuration;

import org.springframework.web.servlet.config.annotation.CorsRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


@Configuration

public class CorsCustomConfig implements WebMvcConfigurer {


    private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CorsCustomConfig.class);


    //private final FhirProperties properties;


    public CorsCustomConfig() { //(FhirProperties properties) {

        //this.properties = properties;

    }


    @Override

    public void addCorsMappings(CorsRegistry registry) {


        String mp = “/**”; //this.properties.getCors().getMappingPath();

        String aos = “*”; //this.properties.getCors().getAllowedOrigins();

        String ams = “*”; //this.properties.getCors().getAllowedMethods();

        String ahs = “*”; //this.properties.getCors().getAllowedHeaders();


        if (logger.isInfoEnabled()) {

            String logMsg = String.format("addCorsMappings fired. (addMapping='%1$s', allowedOrigins='%2$s', allowedMethods='%3$s', allowedHeaders='%4$s')",

                    mp, aos, ams, ahs);

            logger.info(logMsg);

        }


        registry.addMapping(mp)

                .allowedOrigins(aos)

                .allowedMethods(ams)

                .allowedHeaders(ahs);

    }

}


the above did NOT work


......


I tried the hapi fhir "way"


http://hapifhir.io/doc_cors.html#_toc_hapi_fhir_server_interceptor

the above did NOT work.

......

finally I wrote a filter



import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

import org.springframework.http.HttpMethod;
import org.springframework.web.filter.OncePerRequestFilter;

public class HapiFhirCutOffsFilter extends OncePerRequestFilter implements Filter {

private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(HapiFhirCutOffsFilter.class);

public HapiFhirCutOffsFilter() {
//Empty Constructor
}

@Override
protected void doFilterInternal(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain)
throws ServletException, IOException {

HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;


// Http Request Method
String requestMethod = request.getMethod();

// URI that the request was sent to
String requestURI = servletRequest.getRequestURI();

// For HTTP OPTIONS verb/method reply with ACCEPTED status code -- per CORS handshake
if (requestMethod.equals(HttpMethod.OPTIONS.name())) {
logger.info("HapiFhirCutOffsFilter has intercepted an OPTIONS request and is short cutting and returning HttpServletResponse.SC_ACCEPTED");
resp.setStatus(HttpServletResponse.SC_ACCEPTED);
return;
}

// pass the request along the filter chain
filterChain.doFilter(request, servletResponse);
}
}

And I wired mine with applicationContext.xml


<bean id="zzzHapiFhirCutOffsFilterBean"
class="com.mycompany.springbootfhirserver.filters.HapiFhirCutOffsFilter">
</bean>
<bean id="filterRegistrationBean2"
class="org.springframework.boot.web.servlet.FilterRegistrationBean">
<property name="filter" ref="zzzHapiFhirCutOffsFilterBean">
</property>
<property name="urlPatterns" value="/*">
</property>
</bean>


And that finally got OPTIONS working for me.  

My HapiFhirCutOffsFilter is rudimentary of course..and I need to tweak it.  BUT you get the idea.

I spent several days on this.  
James if you see something off, let me know.

And obviously my solution is jilted toward spring/springboot voodoo.


Reply all
Reply to author
Forward
0 new messages