Stream: hapi
Topic: Trying to implement POST method based searches
Daniel Venton (Oct 12 2020 at 20:42):
According to FHIR, "Because of the way that some user agents and proxies treat GET and POST requests, in addition to the get based search method above, servers that support search SHALL also support a POST based search:"
My code accepts the GET method currently. But when I change the request to a POST, HAPI responds:
'{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "processing",
"diagnostics": "Invalid request: The FHIR endpoint on this server does not know how to handle POST operation[Observation] with parameters [[]]"
}
]
}'
What do I have to change in order to accept POST requests? Is it a configuration change or do I need another annotation (Java) on my method handler?
Lin Zhang (Oct 14 2020 at 09:49):
It seems that we might have similiar questions.
Ian Bacher (Oct 14 2020 at 18:32):
@Daniel Venton Are you doing something like this: POST [base]/Observation
? Because it needs to be POST [base]/Observation/_search
, i.e., the URL is different for GET vs POST.
Daniel Venton (Oct 14 2020 at 19:19):
Thanks much! That was the secret sauce I need to get POST to activate my code, but now why isn't my parameter being passed in?
curl --location --request POST 'http://localhost:8083/R4/Observation/_search' \
--header 'Accept: application/fhir+json' \
--header 'Authorization: Bearer **' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'patient=ZZZZZZ'
@Search()
public Bundle searchByIdentifier(
@OptionalParam(name = Observation.SP_PATIENT) TokenParam thePatient) {
When I get into my method the "thePatient" parameter is null.
Ian Bacher (Oct 15 2020 at 14:03):
The patient
search parameter for Observation is supposed to be a reference
rather than a token
so the corresponding variable should be a ReferenceParam
rather than a TokenParam
. At least that'd be my guess.
Daniel Venton (Oct 21 2020 at 17:25):
@James Agnew Can you explain this to me? I'm looking at RestfulServer code, particularly the param processing portion starting at line 913 of v5.1.0. The 1st line says, must have a querystring. but inside that if there is processing of the POST body params. Making the Restful server require AT LEAST one query string parameter in order to process POST body parameters. Should it not always (GET/POST) use any of query string parameters specified AND when the method is POST use values specified in the body? Meaning that a request can be processed where all of the params are in the body?
if (isNotBlank(theRequest.getQueryString())) {
completeUrl = requestUrl + "?" + theRequest.getQueryString();
if (isIgnoreServerParsedRequestParameters()) {
String contentType = theRequest.getHeader(Constants.HEADER_CONTENT_TYPE);
if (theRequestType == RequestTypeEnum.POST && isNotBlank(contentType) && contentType.startsWith(Constants.CT_X_FORM_URLENCODED)) {
String requestBody = toUtf8String(requestDetails.loadRequestContents());
params = UrlUtil.parseQueryStrings(theRequest.getQueryString(), requestBody);
} else if (theRequestType == RequestTypeEnum.GET) {
params = UrlUtil.parseQueryString(theRequest.getQueryString());
}
}
} else {
completeUrl = requestUrl.toString();
}
James Agnew (Oct 21 2020 at 18:07):
@Daniel Venton
You can definitely perform POST based searches with no URL based parameters in HAPI. No special coding is required, it should just work automatically.
theRequest.getQueryString()
should return null if no URL params are present, and HAPI handles that. We do still check in case someone is using both (which I have absolutely seen people do).
Daniel Venton (Oct 21 2020 at 18:29):
When I don't have any query string parameters specified then HAPI doesn't process the POST body parameters at all.
James Agnew (Oct 22 2020 at 12:29):
@Daniel Venton Hmm.. This test is verifying that exact scenario and is passing: https://github.com/jamesagnew/hapi-fhir/blob/master/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/SearchPostDstu3Test.java#L110
Are you able to see any differerence between what it's doing and what you're doing? Could you attach a debugger to the method you quoted for each and see what is happening differently?
Daniel Venton (Oct 22 2020 at 13:15):
Ok, I've isolated the difference. This line of code which calls upon the httpServletRequet interface:
if (params == null) {
params = new HashMap<>(theRequest.getParameterMap());
}
In my apache environment that resolves (eventually) to:
package org.apache.catalina.connector;
public class Request implements HttpServletRequest {
Doesn't return any values.
HAPI unit test appears to resolve to:
package org.eclipse.jetty.server;
public class Request implements HttpServletRequest {
Which does return values.
Meaning that it isn't HAPI's fault, BUT it does provide a suggestion. Since HAPI is capable of decoding the POST body params itself, as illustrated by this line "params = UrlUtil.parseQueryStrings(theRequest.getQueryString(), requestBody);". Perhaps it would be better if HAPI always decoded the post body params instead of relying on other (apparently flawed) implementations. Next step for me will be to see about upgrading the internal tomcat server inside of IDEA IDE to see if it's resolved by apache.
For any other person having the same problem Adding an ignorable query string parameter will at least let you test "/Observation/_search?_fake". This instructs HAPI to decode the POST parameters itself and since it starts with an "_" HAPI doesn't require that parameter to exist in the method signature.
James Agnew (Oct 22 2020 at 21:30):
TBH I'm not 100% sure I understand - But if this is something you could replicate in a unit test (even just with a mock HttpServletRequest object passed directly into SearchMethodBinding or whatever, we'd gladly accept a PR with a fix
Last updated: Apr 12 2022 at 19:14 UTC