-
Notifications
You must be signed in to change notification settings - Fork 26
Fhir_extensions
- Updates
- Goals
- FHIR server
- Simulator as FHIR server
- Simulator event logging
- Test client as FHIR client
- Client event logging
- FHIR base
- FHIR operations on a Resource type
- FHIR operations on a Resource instance
- Submission Operations against a server
- Bundle
- ResDB
- Implementing support for a Resource in the server
- Implementing Create
- Implementing Read
- Implementing Search
- Test Client
- Create Transaction
- Read Transaction
- Query Transaction
- Integration tests
- FHIR Context - expensive to build
Since this was first presented, several key things have changed.
-
ResDb has gone away. FHIR simulators live in SimDb just like SOAP based simulators.
-
Integrate an existing FHIR server into Toolkit
-
Simulator as FHIR server
-
One instance of Toolkit is many FHIR server instances
-
-
Extend Simulator event logging to FHIR
-
Use Test client as FHIR client
-
Extend Client event logging to FHIR
-
Using HAPI open source FHIR implementation
-
Full HAPI server is a complete FHIR implementation - too much for testing
-
Integrate as a collection of JAR files and a Servlet
-
This approach
-
Requires integration with a data server
-
Extension of SimDb
-
Search implemented with Lucene
-
-
We implement each Resource of interest based on their APIs
-
-
Built in handling of XML or JSON
-
Create FHIR server with same ease as we now create a Registry or Repository
-
Two possible names: FHIR simulator or Resource simulator
-
-
Data organization is a bit different
-
Use a variation on SimDb
-
FHIR integration is hidden to most of code base
-
-
We implement per-resource searches in our code
-
Resource indexing/searching based on Apache Lucene
-
-
SimDb extension is (currently) called ResDb (Resource DB)
-
SimDb.groovy is used for both SOAP and FHIR simulators
-
Specific FHIR operations are added
-
SimId class
-
Used for both types of simulators
-
Carries this is FHIR status flag
-
-
Same utilities used to create SOAP and FHIR simulators
-
=⇒ Same GUI too!
-
FHIR client is just HTTP client with content rules
-
FHIR defines collection of operations that map to HTTP operations
-
Create Toolkit transactions for each operation
-
Use same logging
-
The base URL of a FHIR server - common term in FHIR spec
-
Examples typically show something like http://example.com/fhir
-
Toolkit needs are more complicated - one URL offers multiple servers (simulators)
-
Toolkit base URL for FHIR is http://example.com/xdstools/fsim/${simId}
-
=⇒ The Simulator ID is built into the base URL
See FHIR Spec
-
Create
-
Search
-
Read
-
Update
-
Delete
(These are a subset of the available operations)
-
Batch
-
Transaction
This is where you can have multiple Resources in a submission. With Batch a partial sucesss is possible. With transaction it is all or none.
We now have two uses of the term transaction: an IHE reference and a FHIR reference
MHD (XDS on FHIR) Provide is based on FHIR transaction.
Batch and Transaction operations can include multiple Resource types.
-
In SOAP we had MTOM to assemble multiple things into one message
-
FHIR uses a Bundle
-
Bundle is defined as part of the FHIR standard
-
Technically it is a Resource (meta-Resource????)
-
Can be coded as XML or JSON
-
Contains zero or more Resources
-
Carries FHIR metadata (details about the bundle)
-
Not to be confused with XDS metadata which is implemented in FHIR using three types of Resources
-
-
Same directory structure as SimDb
-
Separate directory
External_Cache/ environment/ actors/ simdb/ TestLogCache/ resdb/
In resdb
default__test/ fhir/ any/ 2017_06_27_06_53_00_157/ date.ser Patient/ UUID1.json request_body.bin request_body.txt request_hdr.txt sim_type.txt simId.txt simindex/
-
default__test names the simulator. Same as SimDb.
-
Use SimId class for SOAP or FHIR simulators
-
Has flag indicating which type
-
Difference managed by SimDb.groovy
-
-
The directory simindex is owned by the Lucene search engine which we use to index the resources in a simulator. Lucene manages all content in this directory.
-
The date named directory is the event (reaction to an incoming transaction). Same as SimDb.
-
fhir and any directories are the equivalent of the actor and transaction directories in SimDb. These may change as the implementation gets more sophisticated. You should only reference them through SimDb.groovy.
-
There is directory for each Resource type. Here is shown Patient. In FHIR resources are managed within their type. So, there can be a Patient with ID of 1 and an Observation with ID of 1. It is the type/ID that must be unique. This is why you frequently see example resource IDs like Patient/8.
-
FHIR spec mandates that resource ids must be no more that’s 64 characters, be alpha-numeric, hyphen, period in construction. So, it is legal to create a resource id using a UUID without the urn:uuid: prefix. Toolkit uses this approach for now…
-
This is good and bad. We do not have to keep a counter to assign the next id. But you cannot glance at the IDs and tell the order of creation. Also, since I need to test MHD using UUIDs does make some things easier. I cannot comment on whether this will change in the future. Your code should not depend on it.
-
Resource Provider
-
A Java/Groovy class that implements the operations on a single Resource type
-
This is part of the HAPI/FHIR architecture
-
Implements IResourceProvider interface
-
Key methods are identified by Java annotations
-
-
Primary operations
-
Create - a resource instance
-
Read - GET by Resource ID
-
Search - GET by query parameters
-
-
Secondary issues
-
Versioning
-
Validation
-
-
Patient Resource example is found here
-
Implementing method annotated with @Create
-
Most of the implementation is delegated to the support class ToolkitResourceProvider
-
The exception is the resource validation - that is resource specific
-
Submission can be in XML or JSON format
-
Internally (ResDb) all Resource storage is in JSON format
-
Server assigns ID and Version to Resource
-
Create returns status 201 for successful creation
-
Also returns Location HTTP header - the URL of where the newly created Resource can be read from
-
Example:
Location: /xdstools2/sim/default__test/Patient/1ff98d09-r3r4-8883-bd98-994309fce920/_history/1
Note that the host and port are not part of the Location.
Later when this is used in a Read, the formal reference is Patient/1ff98d09-r3r4-8883-bd98-994309fce920
-
Implementing method annotated with @Read
-
Read is a simple lookup by ID
-
Internally (in Toolkit), this is a search by type and ID because of the way we use Lucene
-
Most of the implementation is delegated to the support class ToolkitResourceProvider
-
The exception is the reading of the file and parsing the JSON into a Resource class for returning
-
HAPI framework handles translating into the requested format
-
XML or JSON
-
-
Implementing method annotated with @Search
-
Search parameters are specified in spec Patient example
-
In the implementing method, parameters are tagged as Required or Optional
-
Search translates into Lucene Boolean Query
-
PatientResourceProvider shows implementation of required and optional parameters
-
There can be multiple @Search methods
-
First one listed that matches the parameters provided in the URL is used
-
-
Remember that each simulator has its own Lucene index
-
and it can contain content for multiple Resource types
-
-
Support for the Create, Read, and Query operations have been added to the test client
-
These are demonstrated in the test definition FhirTestClientCreate which has a section for each operation
<TestPlan> <Test>FhirTestClientCreate/create</Test> <TestStep id="create"> <ExpectedStatus>Success</ExpectedStatus> <FhirCreateTransaction> <ResourceFile>patient.json</ResourceFile> <UrlExtension>/Patient</UrlExtension> </FhirCreateTransaction> </TestStep> </TestPlan>
-
The transaction name is FhirCreateTransaction
-
It requires two parameters as shown
-
ResourceFile points to an input file in the same directory
-
It contains the JSON definition for a single Resource instance to be submitted
-
UrlExtension is part of the FHIR server URL
-
The endpoint managed by Toolkit provides the base address of the FHIR server
-
In the case of a simulator it looks like
http://localhost:8889/xdstools2/fsim/bill__myfhirsys
-
Where bill__myfhirsys is the simulator ID
-
The UrlExtension is appended to the base FHIR server address
-
In this case we are creating a Patient resource so /Patient is required
-
The final URL is
http://localhost:8889/xdstools2/fsim/bill__myfhirsys/Patient
-
-
A significant output of the transaction is the Reports generated, some of which are required by the READ and QUERY transaction
<Report name="Url">http://localhost:8889/xdstools2/fsim/bill__myfhirsys/Patient</Report> <Report name="FhirIdWithHistory">Patient/36bc13d4-82e2-4407-9d0e-83422afb955f/_history/1</Report> <Report name="RefWithHistory">http://localhost:8889/xdstools2/fsim/bill__myfhirsys/Patient/36bc13d4-82e2-4407-9d0e-83422afb955f/_history/1</Report> <Report name="FhirId">Patient/36bc13d4-82e2-4407-9d0e-83422afb955f</Report> <Report name="Ref">http://localhost:8889/xdstools2/fsim/bill__myfhirsys/Patient/36bc13d4-82e2-4407-9d0e-83422afb955f</Report>
-
Url is the endpoint used (to mix REST and SOAP terminology)
-
FhirId is the formal ID of the resource as it sits on the server (simulator in this case)
-
Ref is the combination of the base server URL and the resource ID (FhirID)
-
The two WithHistory reports include the history information
-
Managing history is optional and not yet supported by Toolkit
-
<TestPlan> <Test>FhirTestClientCreate/read</Test> <TestStep id="read"> <ExpectedStatus>Success</ExpectedStatus> <FhirReadTransaction> <UseReport test="FhirTestClientCreate" section="create" step="create" reportName="Ref" useAs="Ref"/> </FhirReadTransaction> </TestStep> </TestPlan>
-
Note the UseReport references the Create transaction
-
The reportName references the auto-generated Report from the Create transaction
-
The useAs is Ref but there is not metadata file like with SOAP transactions
-
This value Ref is expected by the FhirReadTransaction implementation.
-
-
The execution of this transaction produces this Report
<Report name="Url">http://localhost:8889/xdstools2/fsim/bill__myfhirsys/Patient/36bc13d4-82e2-4407-9d0e-83422afb955f</Report>
-
This is the URL that was read
-
The other significant output is the Result which is the JSON coded resource returned
<TestPlan> <Test>FhirTestClientCreate/query</Test> <TestStep id="query"> <ExpectedStatus>Success</ExpectedStatus> <FhirQueryTransaction> <UseReport test="FhirTestClientCreate" section="create" step="create" reportName="Url" useAs="Url"/> <QueryParams>?family=Chalmers</QueryParams> </FhirQueryTransaction> </TestStep> </TestPlan>
-
The above UseReport is required and must have the useAs value of Url as shown
-
Note that it references the create section of the test
-
-
The QueryParams element is also required - it is the query extension to the Url
-
Taking the Url reported by the Create transaction above, the resulting query (GET) is
http://localhost:8889/xdstools2/fsim/bill__myfhirsys/Patient?family=Chalmers
-
The transaction generates a single Report which is the URL it used in the HTTP GET
<Report name="Url">http://localhost:8889/xdstools2/fsim/bill__myfhirsys/Patient?family=Chalmers</Report>
-
And in Result is the JSON encoded response
-
For a query this is always a Bundle
-
In this example the bundle contains a single resource (our query matched a single resource)
-
-
The Integration Test fhir/TestClientSpec.groovy demonstrates their use
-
FHIR-based Spock tests are a bit different
class TestClientSpec extends FhirSpecification
-
They extend FhirSpecification
@Shared SimId simId = new SimId(testSession, simIdName).forFhir()
-
They use a new extension on SimIds shown with the .forFhir() call which sets a boolean
-
SimId and SimDb have been extended to support FHIR
-
There are some new FHIR-specific methods exposed for low-level testing, the .forFhir() should get you all the functionality you need
startGrizzlyWithFhir('8889')
-
The Grizzly Servlet container is started with HAPI/FHIR integrated
spi.delete(spiSimId(simId))
-
The Service Programming Interface (SPI) has been extended
-
Note the SimId translation needed (SPI and GWT have to use different implementations)
spi.createFhirServer(simId.id, simId.user, 'default')
-
Create a FHIR server (simulator) with the SimId shown and the default environment
def 'do create'() { when: def sections = ['create'] def params = [ :] List<Result> results = api.runTest(testSession, siteName, testInstance, sections, params, true) then: results.size() == 1 results.get(0).passed() }
-
Building a test is identical once the proper test environment is created
-
The HAPI code base relies on a structure called FhirContext
-
With references to this structure the code is made to implement multiple versions of FHIR standard
FhirContext ourCtx = FhirContext.forDstu3()
-
is the incantation to establish an environment for DSTU3
-
Creating this context is expensive and the server should only do it once
-
Towards that we have
class ToolkitFhirContext { static private FhirContext ourCtx
public static FhirContext get() { if (!ourCtx) ourCtx = FhirContext.forDstu3() return ourCtx } }
-
so to get the current context
ToolkitFhirContext.get()
-
This will need extension as we start to play with multiple versions
Toolkit
Downloads
Installing Toolkit
Configuring Toolkit for Imaging Tests
Reporting Toolkit Installation Problems
Environment
Test Session
Conformance Test Tool
Writing Conformance Tests
Overview of Imaging Tests
Test Context Definition
Launching Conformance Tool from Gazelle
Inspector
External Cache
Support Tools
Test Organization
Configuring Test Kits
Managing Multiple Test Kits
SAML Validation against Gazelle
Renaming Toolkit
Toolkit API
Managing system configurations
Configuring Toolkit for Connectathon
Developer's blog