Stream: ibm
Topic: Discussion
Lee Surprenant (Dec 05 2019 at 15:58):
A new entry in the performance testing landscape: https://chat.fhir.org/#narrow/stream/179239-tooling/topic/Tests.20for.20FHIR.20REST.20API.3A.20stresty
Lee Surprenant (Dec 05 2019 at 15:59):
The other one (thats been on my list to look into again for a LONG time) was https://github.com/FirelyTeam/Wind.Tunnel
Lee Surprenant (Dec 05 2019 at 15:59):
would be great if we could help one of these get to "industry benchmark" level
Lee Surprenant (Dec 06 2019 at 02:14):
I wonder what we do on this front: https://chat.fhir.org/#narrow/stream/179166-implementers/topic/Searching.20with.20_elements.20and.20choice.20types
Lee Surprenant (Dec 06 2019 at 02:14):
since its built into our parser, i'm guessing we actually want the full choiceElement (e.g. valueQuantity and not just value)?
Lee Surprenant (Dec 06 2019 at 16:17):
@Gidon Gershinsky I saw your post at https://chat.fhir.org/#narrow/stream/179250-bulk-data/topic/Parquet.20Bulk.20Data.20format :-)
I'm not sure if it helps you or not, but we have a module called fhir-examples
which contains:
- all examples from the fhir spec;
- a set of generated examples from us which includes:
- "minimal" examples for each
- "complete-mock" examples which include fake data in every field
- "complete-absent" examples which include every field but no data
- a set of "index" files for quickly iterating over subsets of the examples
- a couple simple java classes to help get a Reader for the index files and resource examples
Lee Surprenant (Dec 06 2019 at 16:18):
"complete-absent" examples are especially helpful for finding cases where you fail to deal with the fact all fhir primitives can have extensions and no data (a common source of NullPointerExceptions)
Lee Surprenant (Dec 06 2019 at 16:21):
finally, to ensure strong test coverage, the generated examples include at least one resource example for each allowed "choice". for example, if a resource has an element choice[x] with 3 allowed choices, we generate at least 3 examples of this resource.
Lee Surprenant (Dec 06 2019 at 16:28):
(deleted)
Gidon Gershinsky (Dec 08 2019 at 14:08):
@Lee Surprenant thanks, this is certainly helpful. We understand Parquet encryption, but any assistance with FHIR will be appreciated. In fact, it will be great if we can work together on that channel, pushing Parquet-for-FHIR-standard; or, at the very least, if we can be in touch with you to get advice on FHIR-related questions.
Lee Surprenant (Dec 09 2019 at 15:37):
@Gidon Gershinsky @Eliot Salant
per a quick search, here are the spec examples with contained resources:
activitydefinition-medicationorder-example.json activitydefinition-questionnaire.json actualgroup-questionnaire.json allergyintolerance-questionnaire.json auditevent-example-error.json auditevent-questionnaire.json biologicallyderivedproduct-questionnaire.json bmi-questionnaire.json bodyheight-questionnaire.json bodytemp-questionnaire.json bodyweight-questionnaire.json bp-questionnaire.json careplan-example-f001-heart.json careplan-example-f002-lung.json careplan-example-f003-pharynx.json careplan-example-f201-renal.json careplan-example-f202-malignancy.json careplan-example-f203-sepsis.json careplan-example-GPVisit.json careplan-example-integrated.json careplan-example-pregnancy.json careplan-example.json careplan-questionnaire.json careteam-example.json catalog-questionnaire.json cdshooksrequestgroup-questionnaire.json cdshooksserviceplandefinition-questionnaire.json chargeitem-questionnaire.json cholesterol-questionnaire.json claim-example-cms1500-medical.json claim-example-oral-bridge.json claim-example-oral-contained-identifier.json claim-example-oral-contained.json claim-example-vision-glasses-3tier.json claim-questionnaire.json claimresponse-questionnaire.json clinicaldocument-questionnaire.json clinicalimpression-questionnaire.json codesystem-questionnaire.json communication-example-fm-solicited-attachment.json communication-questionnaire.json communicationrequest-example-fm-solicit-attachment.json communicationrequest-questionnaire.json composition-questionnaire.json computableplandefinition-questionnaire.json conceptmap-questionnaire.json condition-questionnaire.json consent-questionnaire.json contract-questionnaire.json coverage-questionnaire.json coverageeligibilityrequest-questionnaire.json coverageeligibilityresponse-example-benefits-2.json coverageeligibilityresponse-questionnaire.json cqf-questionnaire-questionnaire.json cqllibrary-questionnaire.json detectedissue-questionnaire.json devicedefinition-questionnaire.json devicemetricobservation-questionnaire.json devicerequest-questionnaire.json deviceusestatement-questionnaire.json diagnosticreport-genetics-questionnaire.json diagnosticreport-questionnaire.json documentmanifest-example.json documentmanifest-fm-attachment.json documentreference-example.json elementdefinition-de-questionnaire.json encounter-example-home.json eventdefinition-questionnaire.json evidencevariable-questionnaire.json explanationofbenefit-questionnaire.json familymemberhistory-genetic-questionnaire.json familymemberhistory-questionnaire.json goal-questionnaire.json group-questionnaire.json groupdefinition-questionnaire.json guidanceresponse-example.json guidanceresponse-questionnaire.json hdlcholesterol-questionnaire.json headcircum-questionnaire.json healthcareservice-example.json heartrate-questionnaire.json hlaresult-questionnaire.json immunization-questionnaire.json immunizationevaluation-questionnaire.json immunizationrecommendation-questionnaire.json implementationguide-questionnaire.json invoice-questionnaire.json json-edge-cases.json ldlcholesterol-questionnaire.json library-questionnaire.json lipidprofile-questionnaire.json list-example-double-cousin-relationship-pedigree.json list-example-familyhistory-f201-roel.json list-example-familyhistory-genetics-profile-annie.json list-example-familyhistory-genetics-profile.json measure-questionnaire.json measurereport-cms146-cat1-example.json measurereport-cms146-cat2-example.json measurereport-cms146-cat3-example.json media-questionnaire.json medication-questionnaire.json medicationadministration-questionnaire.json medicationadministration0301.json medicationadministration0302.json medicationadministration0303.json medicationadministration0304.json medicationadministration0305.json medicationadministration0306.json medicationadministration0307.json medicationadministration0309.json medicationadministration0310.json medicationadministration0311.json medicationadministrationexample3.json medicationdispense-questionnaire.json medicationdispense0301.json medicationdispense0302.json medicationdispense0303.json medicationdispense0304.json medicationdispense0305.json medicationdispense0306.json medicationdispense0308.json medicationdispense0309.json medicationdispense0310.json medicationdispense0312.json medicationdispense0313.json medicationdispense0314.json medicationdispense0315.json medicationdispense0317.json medicationdispense0319.json medicationdispense0320.json medicationdispense0329.json medicationdispense0330.json medicationdispense0331.json medicationdispenseexample8.json medicationexample0301.json medicationexample0302.json medicationexample0303.json medicationexample0304.json medicationexample0305.json medicationexample0306.json medicationexample0307.json medicationexample0308.json medicationexample0309.json medicationexample0310.json medicationexample0311.json medicationexample0312.json medicationexample0316.json medicationexample0320.json medicationexample0321.json medicationexample15.json medicationknowledge-example.json medicationknowledge-questionnaire.json medicationrequest-questionnaire.json medicationrequest0301.json medicationrequest0302.json medicationrequest0303.json medicationrequest0304.json medicationrequest0305.json medicationrequest0306.json medicationrequest0307.json medicationrequest0309.json medicationrequest0310.json medicationrequest0315.json medicationrequest0316.json medicationrequest0317.json medicationrequest0318.json medicationrequest0319.json medicationrequest0321.json medicationrequest0322.json medicationrequest0323.json medicationrequest0328.json medicationrequest0329.json medicationrequest0330.json medicationrequest0331.json medicationrequest0332.json medicationrequest0333.json medicationrequest0336.json medicationrequest0337.json medicationrequest0338.json medicationrequest0339.json medicationrequestexample1.json medicationstatement-questionnaire.json medicationstatementexample1.json medicationstatementexample2.json medicationstatementexample7.json medicinalproduct-questionnaire.json medicinalproductauthorization-questionnaire.json medicinalproductcontraindication-questionnaire.json medicinalproductindication-questionnaire.json medicinalproductinteraction-questionnaire.json messagedefinition-questionnaire.json messageheader-questionnaire.json nutritionorder-questionnaire.json observation-example-10minute-apgar-score.json observation-example-1minute-apgar-score.json observation-example-20minute-apgar-score.json observation-example-2minute-apgar-score.json observation-example-5minute-apgar-score.json observation-genetics-questionnaire.json observation-questionnaire.json oxygensat-questionnaire.json parameters-questionnaire.json patient-questionnaire.json picoelement-questionnaire.json plandefinition-example-cardiology-os.json plandefinition-example-kdn5-simplified.json plandefinition-example.json plandefinition-options-example.json plandefinition-protocol-example.json plandefinition-questionnaire.json procedure-questionnaire.json provenance-questionnaire.json questionnaire-example-gcs.json questionnaire-profile-example-ussg-fht.json questionnaire-questionnaire.json questionnaireresponse-example.json questionnaireresponse-questionnaire.json requestgroup-example.json requestgroup-kdn5-example.json requestgroup-questionnaire.json researchdefinition-questionnaire.json researchelementdefinition-questionnaire.json resprate-questionnaire.json riskassessment-example-population.json riskassessment-questionnaire.json servicerequest-example-lipid.json servicerequest-example2.json servicerequest-genetics-questionnaire.json servicerequest-questionnaire.json shareableactivitydefinition-questionnaire.json shareablecodesystem-questionnaire.json shareablelibrary-questionnaire.json shareablemeasure-questionnaire.json shareableplandefinition-questionnaire.json shareablevalueset-questionnaire.json specimen-example-isolate.json specimen-example.json specimen-questionnaire.json specimendefinition-questionnaire.json structuremap-questionnaire.json substance-example-amoxicillin-clavulanate.json substance-questionnaire.json substancereferenceinformation-questionnaire.json substancespecification-questionnaire.json supplydelivery-questionnaire.json supplyrequest-questionnaire.json task-example1.json task-questionnaire.json triglyceride-questionnaire.json valueset-example-hierarchical.json valueset-nhin-purposeofuse.json valueset-questionnaire.json valuesets.json (2 matches) vitalsigns-questionnaire.json vitalspanel-questionnaire.json
Lee Surprenant (Dec 09 2019 at 15:41):
you have a couple options for getting them:
- download them from the spec: navigate to https://www.hl7.org/fhir/downloads.html and donwload the JSON "Examples"
- grab them from our
fhir-examples
project...as indicated above we've copied all the spec examples into a module (and combined with some of our own) and added a couple helper classes for getting them. for example, you could add a newindex
file that contains just the examples listed above
Lee Surprenant (Feb 05 2020 at 13:03):
@John Timm where, in your opinion, would a utility such as this belong:
protected Code convertToCodeSubtype(Visitable parent, String elementName, Code value) { Class<?> targetType = ModelSupport.getElementType(parent.getClass(), elementName); if (value.getClass() != targetType) { MethodType mt = MethodType.methodType(targetType, String.class); try { MethodHandle methodHandle = MethodHandles.publicLookup().findStatic(targetType, "of", mt); value = (Code) methodHandle.invoke(((Code)value).getValue()); } catch (Throwable e) { throw new IllegalArgumentException("Value of type '" + value.getClass() + "' cannot be used to populate target of type '" + targetType + "'"); } } return value; }
Lee Surprenant (Feb 05 2020 at 13:04):
currently I have that in the CopyingVisitor which my FHIRPathPatch visitors extend (they are the only ones using it today), but I'm wondering if it should be a static helper instead
Lee Surprenant (Feb 06 2020 at 15:33):
@John Timm another one for you. Today we have both:
ModelSupport.getTypeName(Class<?> type)
-
ModelSupport.getResourceTypes()
and -
FHIRUtil.getResourceTypeName(Resource resource)
FHIRUtil.getResourceTypeNames()
In general, I think we were deprecating the methods in FHIRUtil and switching things over to ModelSupport.
Should we deprecate FHIRUtil.getResourceTypeNames()
in favor of ModelSupport.getResourceTypes()
?
Should we introduce a ModelSupport.getResourceTypeNames()
and deprecate FHIRUtil.getResourceTypeNames()
?
Also, as you look at https://github.com/IBM/FHIR/issues/623, I'm wondering if we should have a variant of the getResourceTypes()
and getResourceTypeNames()
methods that controls whether or not they return:
A. abstract supertypes like Resource / DomainResource; and/or
B. "logical" resource types like MetadataResource (and/or Definition?)
John Timm (Feb 06 2020 at 15:51):
John Timm where, in your opinion, would a utility such as this belong:
protected Code convertToCodeSubtype(Visitable parent, String elementName, Code value) { Class<?> targetType = ModelSupport.getElementType(parent.getClass(), elementName); if (value.getClass() != targetType) { MethodType mt = MethodType.methodType(targetType, String.class); try { MethodHandle methodHandle = MethodHandles.publicLookup().findStatic(targetType, "of", mt); value = (Code) methodHandle.invoke(((Code)value).getValue()); } catch (Throwable e) { throw new IllegalArgumentException("Value of type '" + value.getClass() + "' cannot be used to populate target of type '" + targetType + "'"); } } return value; }
I think we can leave it where it is for now. I think we'd like to encourage users of the API to use the code subtypes directly.
John Timm (Feb 06 2020 at 15:53):
John Timm another one for you. Today we have both:
ModelSupport.getTypeName(Class<?> type)
ModelSupport.getResourceTypes()
and
FHIRUtil.getResourceTypeName(Resource resource)
FHIRUtil.getResourceTypeNames()
In general, I think we were deprecating the methods in FHIRUtil and switching things over to ModelSupport.
Should we deprecateFHIRUtil.getResourceTypeNames()
in favor ofModelSupport.getResourceTypes()
?
Should we introduce aModelSupport.getResourceTypeNames()
and deprecateFHIRUtil.getResourceTypeNames()
?Also, as you look at https://github.com/IBM/FHIR/issues/623, I'm wondering if we should have a variant of the
getResourceTypes()
andgetResourceTypeNames()
methods that controls whether or not they return:
A. abstract supertypes like Resource / DomainResource; and/or
B. "logical" resource types like MetadataResource (and/or Definition?)
There's really only one logical resource type that we need to deal with at the moment (MetadataResource). The list will should not return "logical" resource types once 623 is completed. As for "abstract" resource types, the client could filter those out pretty easily (really it's only Resource and DomainResource). I will think about this as I work 623 and whether we should introduce other method signatures. I agree that we should deprecate FHIRUtil methods that overlap with ModelSupport.
Lee Surprenant (Feb 18 2020 at 18:34):
@Gidon Gershinsky @Eliot Salant FYI I wrote up a guide on "how to create a new persistence layer" for the IBM FHIR Server: https://ibm.github.io/FHIR/guides/BringYourOwnPersistence
Lee Surprenant (Feb 18 2020 at 18:34):
please let me know what you think
Lee Surprenant (Apr 20 2020 at 13:19):
I recently did some work to enable OpenID Connect / OAuth 2.0 in my local branch. We've had some exemplary config commented out in our default server.xml
for quite some time, but I never had the time to try it out until now.
https://github.com/IBM/FHIR/pull/939 modifies this commented out config in order to pass more of the Inferno test tool, although work remains to pass more of it.
Lee Surprenant (Apr 20 2020 at 13:25):
One thing I discovered during this effort is that Liberty supports "dynamic client registration", but that it requires you to create 3 tables associated with storing and caching the clients in a databaseStore.
Paul added a comment to suggest moving the DDL for these tables out of our doc and into somewhere more executable:
https://github.com/IBM/FHIR/pull/939/files/6f1f9c3c1a2fd1cf39932974b3884dc01c5f183b#diff-46968fda8c8c67feeaad01de47b14d30
Question: is it worth moving these into fhir-persistence-schema
so they can get created like the rest of our tables?
Should they have their own separate "action"? (e.g. a --oauth-client-store
flag you pass to the tool to have it create these)?
Paul Bastide (Apr 21 2020 at 14:43):
I think it's worthy of a separate action
Paul Bastide (Apr 21 2020 at 14:43):
when I see it laid out here, I think a separate flag makes sense
Paul Bastide (Apr 21 2020 at 14:43):
it's a good idea
Lee Surprenant (Apr 21 2020 at 20:12):
haha, I just pushed an update that creates it as part of the create-schema and update-schema actions
Lee Surprenant (Apr 21 2020 at 20:12):
i pushed and then signed on here and saw your messages
Paul Bastide (Apr 22 2020 at 12:55):
no worries - I think both are fine!
Mike Schroeder (Oct 05 2020 at 17:15):
Issue 1504 analysis:
Current processing of local references for transaction bundles:
- bundle entries can have a local reference specified in the Bundle.Entry.fullUrl field - the local reference must start with 'urn:'
- for resources specified in POST and PUT requests, we look for reference fields containing references starting with 'urn:' and if they match a bundle entry local reference, we replace them with the actual resource reference of the resource in the matching bundle entry
-
we build a map of [local reference --> real resource reference] to enable the local reference resolution in the previous step. The map is built as follows:
a. after a POST request is processed, its [local ref --> real resource ref] mapping is added to the map (because it's only at that point that we know the logical ID the resource was created with)
b. after all POST resources have been processed, but before any PUT resources have been processed, all PUT [local ref --> real resource ref] mappings are added to the map (we can do this before processing because PUT requests are updates, so resources already have logical ID set) -
processing order of requests is all POST requests first, then PUT requests
With current code, the following scenarios work:
- any POST resource containing a local reference to a POST resource processed before it in the bundle will have the reference resolved properly because each POST resource has its mapping added to the map after being processed, meaning a mapping for a resource already processed will exist when a resource lower in the bundle is processed
- any PUT resource containing a local reference to a POST resource will have the reference resolved properly because all POST resources will have their mappings added to the map before any PUT resources are processed.
- any PUT resource containing a local reference to another PUT resource will have the reference resolved properly because all PUT resources will have their mappings added to the map before any PUT resources are processed.
With current code, the following scenarios fail:
- any POST resource containing a local reference to a PUT resource will not have the reference resolved properly because the PUT resources will not have their mappings added to the map until after all POST resources have been processed.
- any POST resource containing a local reference to a POST resource below it in the bundle will not have the reference resolved properly because the POST resource lower in the bundle will not have its mapping in the map at the time the resource higher in the bundle is processed.
Options to fix failing scenarios:
- Failing scenario 1 can be fixed simply by adding PUT resource mappings to the map before processing POST resources
- Failing scenario 2 I think can only be fixed by 'pre-allocating' logical IDs for resources to be created. This would allow the mappings to be added to the map before processing any POST resources, but would require that the logical ID be passed into and used by the persistence layer on resource creation.
Cases where mapping can't be added until after resource is processed:
- On POSTs, there is a conditional create option based on the Bundle.Entry.Request.ifNoneExist field. A search query can be specified in that field, and if a single search result is found for that query, the POSTed resource is not created. Instead, the metadata for the search result will be returned, meaning that the logical ID could be different than a pre-allocated ID. So if that Bundle.Entry.Request.ifNoneExist field is populated, we wouldn't want to add a mapping before processing that resource.
- On PUTs, there is a conditional update option based on the Bundle.Entry.Request.url field. A search query can be specified on the end of that url (i.e. Patient?_id=abc). If no search results are returned for the query AND if the resource ID is null, a create will be performed rather than an update, meaning we wouldn't know the logical ID until after the create. So if the Bundle.Entry.Request.url field contains a query string, we wouldn't want to add a mapping before processing that resource.
- For these cases, if we really wanted to support resolution of local references to them, we could execute the searches prior to fully processing the resources, just to get the logical ID for our mappings.
Lee Surprenant (Oct 05 2020 at 17:58):
Great analysis. Does FHIR spec say anything about those "failing scenarios"? Trying to gauge whether a client should reasonably expect those scenarios to work or not...
Lee Surprenant (Oct 05 2020 at 17:59):
My current inclination would be to make the easy fix for scenario 1 and just punt on scenario 2 (unless we think this violates the specification in some way)
Mike Schroeder (Oct 05 2020 at 18:14):
The spec (https://www.hl7.org/fhir/http.html#transaction) isn't real straight-forward, but it does say the following:
A transaction may include references from one resource to another in the bundle, including circular references where resources refer to each other. When the server assigns a new id to any resource in the bundle which has a POST method as part of the processing rules above, it SHALL also update any references to that resource in the same bundle as they are processed (see about Ids in a bundle).
I think that implies we should probably support both failing scenarios. As far as the conditional create and updates, the spec says this:
Note that transactions and conditional create/update/delete are complex interactions and it is not expected that every server will implement them. Servers that don't support the batches or transactions SHOULD return an HTTP 400 error and MAY include an OperationOutcome.
So I think it's more reasonable that we don't support local references to bundle entries with conditional creates/updates - the last 2 scenarios listed above.
Lee Surprenant (Oct 05 2020 at 18:34):
it SHALL also update any references to that resource in the same bundle as they are processed (see about Ids in a bundle)
really wonder what they mean by "as they are processed" there and whether it could be construed to support our current behavior where order matters
Lee Surprenant (Oct 05 2020 at 18:36):
i guess that reading doesn't jive with the "circular" comment
Lee Surprenant (Oct 05 2020 at 18:40):
so what would pre-computing resource ids look like?
something like this:
- turn the "generate a new resource id into standalone utility (if it isn't already)...currently that is used in
create
- use this utility to generate a resource id for any resources being created as part of the bundle
- under the covers, during bundle processing, we switch all the
create
operations intocreate-via-update
operations and pass our pre-allocated resource id to ResourceHelper.doUpdate (instead of calling doCreate like it does now)
?
Lee Surprenant (Oct 05 2020 at 18:40):
So I think it's more reasonable that we don't support local references to bundle entries with conditional creates/updates - the last 2 scenarios listed above.
+1 from me on this part of it
Mike Schroeder (Oct 05 2020 at 19:22):
I was thinking the following for the pre-allocation process:
Currently, the FHIRPersistence class generates the new ID in its create() method. I think we'd want to do the following:
- Turn the ID generator into stand-alone utility (one already exists for the JDBC persistence layer - TimestampPrefixedUUID - which is called by FHIRPersistenceJDBCImpl.create() ).
- Either 1) add a new FHIRPersistence.create() interface, same as the current one except that it takes one additional parameter - 'logicalId', or 2) just change the existing create() interface to take the additional 'logicalId' parameter
- Add a new ResourceHelper.doCreate() interface (or just change the existing doCreate() interface) that takes the additional 'logicalId' parameter, which will be passed along to the FHIRPersistence.create() method.
- For all non-conditional POST requests, generate an ID and add a mapping to the [local ref-->real resource ref] mapping table
- Now just process the POST requests followed by the PUT requests as we do now, with the slight change that POST requests will pass their logicalId on the call to doCreate(). Since we've got a mapping for every non-conditional POST or PUT request in the mapping table before starting any processing, all local references should be resolved properly to their actual resource references, regardless of order of processing.
But I like your idea of calling doUpdate and using the create-via-update
path instead of messing with adding/changing the doCreate() interfaces. Would just have to make sure the Bundle.Entry.Response sent back was equivalent to what would be sent back from doCreate.
Lee Surprenant (Oct 05 2020 at 19:27):
pretty sure that we do return a 201 when you PUT for the first time (create-on-update). but seems your approach would work similarly. no strong preference. i think the most "interesting" bit will be where to put the newly-extracted utility for generating ids.
i sort of like the idea of delegating that to the PL (so, for example, our jdbc impl can generate these special ids, but a different PL could do simpler ones), but I think it will be much easier just move the code to fhir-core
(or similar)
Last updated: Apr 12 2022 at 19:14 UTC