26.0.1FHIR Gateway Endpoint

 

The FHIR Gateway Endpoint module creates a FHIR server that acts as a proxy for one or more target FHIR servers.

The FHIR Gateway provides the benefits of a Smile CDR FHIR endpoint over top of the target servers. This includes:

  • Complete authentication/authorization services, including support for SMART on FHIR
  • Audit and Transaction logs
  • Automatic request/response conversion between XML/JSON/RDF
  • FHIR response manipulation including support for FHIR features such as the _elements and _fhirpath parameters
  • Automatic FHIR version conversion if Versioned API Mode is enabled
  • Request validation (see Request Validating Enabled). Additionally, instance validation can be configured by setting a validation dependency to the validation-supporting module

When the FHIR Gateway is placed in front of multiple target servers, it can be used to present a collection of servers as a single unified FHIR endpoint. This can be particularly useful when implementing APIs for SMART on FHIR applications, since these applications will often expect a single endpoint through which all data flows.

The FHIR Gateway is also designed to avoid revealing details about the internal FHIR servers. Internal server addresses, paging URLs, etc. are all obscured by the FHIR Gateway in its responses to clients.

Gateway Overview

26.0.2Troubleshooting

 

Additional logging can be enabled in order to troubleshoot Gateway routing issues. See FHIR Gateway Troubleshooting Log for details.

26.0.3Limitations

 

This section lists the known limitations on this module.

  • FHIR Gateway has limited support for FHIR operations. Only $meta, $meta-add, $meta-delete, $graphql, $process-message, $everything, $export, $export-poll-status and $proxy-link operations are supported by default. However, it is possible to add support for custom operations by configuring Custom Operation Providers.
  • By default, $everything operation on instance and type level is supported only for Patient resource.
  • Conditional delete operation (e.g. DELETE Observation?status=outdated) is NOT supported by FHIR Gateway module.
  • PATCH operation is NOT supported by FHIR Gateway.
  • The FHIR Gateway cannot route individual entries within a transaction bundle to different target servers. All operations in a transaction bundle are directed to the first matching FHIR target server.
  • The _history interaction is limited to the instance level.
  • Downloading exported files is currently only supported for Binary files, which is the case when target servers are HAPI-FHIR servers.
  • Cancelling an export operation using DELETE [polling content location] is not supported.

26.0.4Configuring Consent Service

 

As mentioned in the Consent Service documentation, Consent Service can be enabled and implemented for FHIR Gateway modules using JavaScript or Java APIs. Note though that for JavaScript implementations, the following APIs are NOT available for FHIR Gateway modules:

26.0.5Bulk Export Operation

 

The gateway $export operation supports the same options and parameters as a fhir endpoint. The urls used for status and for results have a few differences:

  1. In $export responses, the _jobId parameter points to a JSON Web Token (JWT), as shown below:
HTTP/1.1 202 Accepted
Content-Location: http://localhost:8888/$export-poll-status?_jobId=eyJraWQiOiJmYWFhMDljNy0yNmVmLTQ3MTQtYTc3Mi1lMzYyNjllMzI1NDIiLCJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.MqSBJhODntHL0rEiDNw7cJEbScXYzQ0AYsvf40YFji2xBnxy9cG88Ft26R4P4233s6NXwp-8kCpATYUCSBviW_otBhXw8tuheKFSghgI3rcDYg6c-8cMZPALwPVhsyQGYqc4Lh7GUicWP14YsSs58edb0tt3i8w-OmmRwIFbKfLGoIgbc6Dvndf50N7UGjuzXGIV7gNeg81a5qZnlwoW_OSwEreca6ttQvqyGDxDbgcPgV5_ujbJmy7p3ETHu2i-rDRI-i9TZSd73fqRjK1lqB2GqUpwGQ67mUXD6A8cPsXWkdG-yNkHPbIJX1VBNja25F6OpNGcOS7J7QUnSHf94w.Zint-j80_YScO8OC.EtV-hmkc0y0wQdG3K6PZpw7JC9lUSjKym0w5y7eSN944bcSSXHCrv8dOxDH-IRzzG32xXgNiVZMvB0E5GeJWJE9nSbVFt6B0UzNLxy5hmEhNQ6oArN_YX8Ms2cM84RdDBLG6xauOrycjGSTl7ghPRDsi5uy-njNcwjIMY9fNeEu_baxUZkR6SngHnI_ZW0LqfC8yg-sBM029sTUamyEGgQ_VEebdAhz9Z5t7OJGKyRsqI4FwkASX04IkXR2CjoHKxvViKpdCoOz4yToUbxir0zeOT3W2q9PMF9IL2HVC-FfPfFNafvwocbUPbzbumoThGIij5vowk-EdL2qI2XM98FBE6g0hVHHUKcWrnI_jd4UTk7qFMhiq4VX4416vG3ICOfYCVabjgKfJ1oDtf9GUyC9yvvOFkcr_urVbT_QZjuqnSw.jrcH1lrUA07uLl_leSrWRA
  1. When the $export-poll-status operation returns a completed response (status code 200), the JSON result url points to a $proxy-link operation for each exported resource type. A GET request must be made to this url in order to retrieve the exported resources for each type. An example response is shown below:
{
  "transactionTime": "2025-04-16T09:33:04.902-04:00",
  "request": "http://localhost:8001/$export?_type=Patient%2CObservation&_format=json",
  "requiresAccessToken": true,
  "output": [
    {
      "type": "Observation",
      "url": "http://localhost:8888/$proxy-link?_jwtId=eyJraWQiOiJmYWFhMDljNy0yNmVmLTQ3MTQtYTc3Mi1lMzYyNjllMzI1NDIiLCJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.cqSwg47f57Z43msAZdha1VvAf-W0t1V37uPdF-C8EGuJ5YzqQg8GI2_a1N2wEIpgVLXIFJQqz68mVowyegALp7Wtl0RVJcUkcsowKvfrdKMsKJaP4eqjek2x5e8qg75PETWp3aWN3Gi9azf3MvXn0FhVD9N5PNVecCfx2UeOo3kpYSrq6qSmNJha9mSoqbu5eqbQTVYbcw9yGuoM2c4Cqcsp3TqLkz8VCw--BDr9m7egK7paeN8Kr52lJIuvSdFNWwMqrerGhByBE7OsnpN5accl7o4d1RJZVCzXJJFmdjq-eZLGJsTlXzB4v6dypkfIsQRPZozdJp717pvVBUh_Ww.Xe-1tGbvOOME5Wmx.gq-qJpsJcuZ_9192-qPdJjxckbGg7Q8EhHn8wKybbKAdJDBF9NFUJh_AKoSqr8sRLGKGspoi3NB51jEn7K3Aqrq3d0tGq-xpg2zH62F9WnZ2lmFoM0jRPgbIeITePKEGsMEvt4wokjDugwm94OlX7Jhb0BgUrKWI0B7YDXe9zun_x8H8X7eFUWoNBI1tNHLYtW99aGIhAYgttpUPdF7Y__aLVJll76G_-6xug8fV0zv7GGu5WkOKMHrVW9dsysl_FIeOt51uQZW6yodOgu0YJw7AM-5RnVZj2_7jFlxOJ_lYrKALzJvDhXf-Ct5FqpZCyDITodD6De1FXI5vgcGFe3kL2glBwiMYJvhTIrn8qxaSSWC2hCrISX8ENnPXyUMyXzomAE0fnYvwBe2LviK4PImoEHjUunMA6xUj4E1hxSUHG8ThHvFLfhSLVuou7nc.5PzoIzcdQmQYQ__JBMF2fg"
    },
    {
      "type": "Patient",
      "url": "http://localhost:8888/$proxy-link?_jwtId=eyJraWQiOiJmYWFhMDljNy0yNmVmLTQ3MTQtYTc3Mi1lMzYyNjllMzI1NDIiLCJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.KxRY4HLtlEl2kW1UokT2p4cXEkIr6cPsQCyTkE4r08t5i6JyzfqCR2vUaCsNBa1QNEbf05Lyky02NMYXJ9mf62W1Y-fYwFsDHIIPy_Il4v07Xlx9fl98Cz9fidbDGWnu6EyzJPSclBjwfJ6crV2Y-9T9Tjtq78fAQrfhyKgCio7q1-pBHD1y0s7ULaaAoEAeweA7Tfv7wKIooC9W6rlPjvH_cORJGsi8zCziuHUkGAzAhKxvjB3QWHbFEZ1i_7JoDryzt5GPFGX-zIXOzXnsjsfRZN_b0aMMeQm8ntewIY7kmSXVuguuLJfIAhS5TzzHzyb7yjX_g-lUYRT1aEJAew.56k3gzui9j-HIkyC.p6sjOrmuck_XE_l2RcjohuOqLD7IDiqNyzIWueVIG8_qiJ5_yX5Bkr0v5FlQlsVz3IU_vcKTcmm8bxfrUJl4r4IpkvecY7wes_coZawecZSGH0wXzlidqwiXnVRM3-cIXmpeqgxvS1NsgucOMX1OBS4y9n-nNn6xSgYDBwVfv9Nw63r-n_shXepOGmCZU7uDYyVDrWoe9bWTgZ8gZ6cs8aDwafdMiEWvvEzopCxQPtsUX_6Yv0g6qTJZfHaJHpLVqoNFWjzgRqcvQJ9d4n2-qTnPVs21zNhXpCibS_RWh4i5jwA9n0hPpk9pJbWCSQNvSjOJg4g_MtmKmyqOGccA5TfuJ20Pp0bN7W441Haju5H91AecIt2_BnJrW37GIq6JC4ImWFZxXB5grqFTTW6wtkzlzSQnX27IYU-pew5wi_pNPxgSGwOK73TAag.-pmzZ5H_uDnxTaSatDVZdg"
    }
  ],
  "error": []
}
  1. To retrieve the exported files, the url from the previously received response must be used in a GET $proxy-link operation as follows:
GET http://localhost:8888/$proxy-link?_jwtId=eyJraWQiOiJmYWFhMDljNy0yNmVmLTQ3MTQtYTc3Mi1lMzYyNjllMzI1NDIiLCJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.KxRY4HLtlEl2kW1UokT2p4cXEkIr6cPsQCyTkE4r08t5i6JyzfqCR2vUaCsNBa1QNEbf05Lyky02NMYXJ9mf62W1Y-fYwFsDHIIPy_Il4v07Xlx9fl98Cz9fidbDGWnu6EyzJPSclBjwfJ6crV2Y-9T9Tjtq78fAQrfhyKgCio7q1-pBHD1y0s7ULaaAoEAeweA7Tfv7wKIooC9W6rlPjvH_cORJGsi8zCziuHUkGAzAhKxvjB3QWHbFEZ1i_7JoDryzt5GPFGX-zIXOzXnsjsfRZN_b0aMMeQm8ntewIY7kmSXVuguuLJfIAhS5TzzHzyb7yjX_g-lUYRT1aEJAew.56k3gzui9j-HIkyC.p6sjOrmuck_XE_l2RcjohuOqLD7IDiqNyzIWueVIG8_qiJ5_yX5Bkr0v5FlQlsVz3IU_vcKTcmm8bxfrUJl4r4IpkvecY7wes_coZawecZSGH0wXzlidqwiXnVRM3-cIXmpeqgxvS1NsgucOMX1OBS4y9n-nNn6xSgYDBwVfv9Nw63r-n_shXepOGmCZU7uDYyVDrWoe9bWTgZ8gZ6cs8aDwafdMiEWvvEzopCxQPtsUX_6Yv0g6qTJZfHaJHpLVqoNFWjzgRqcvQJ9d4n2-qTnPVs21zNhXpCibS_RWh4i5jwA9n0hPpk9pJbWCSQNvSjOJg4g_MtmKmyqOGccA5TfuJ20Pp0bN7W441Haju5H91AecIt2_BnJrW37GIq6JC4ImWFZxXB5grqFTTW6wtkzlzSQnX27IYU-pew5wi_pNPxgSGwOK73TAag.-pmzZ5H_uDnxTaSatDVZdg
Content-Type: application/fhir+ndjson

26.0.5.1Export retrieved Resources

Resources from all targets are combined in the $proxy-link ndjson response as follows:

{"resourceType":"Patient","id":"TGT2-1331","meta":{"versionId":"1","lastUpdated":"2025-04-16T09:30:55.490-04:00","source":"#64W1IUL7HMPRcouW"},"name":[{"family":"Wilson","given":["Amanda"]}],"gender":"female","birthDate":"1974-01-13","address":[{"line":["123 Aaa St"],"city":"SomeVille1","state":"Mac","postalCode":"1234"}]}
{"resourceType":"Patient","id":"TGT2-1332","meta":{"versionId":"1","lastUpdated":"2025-04-16T09:31:03.509-04:00","source":"#nAEykunxtxGC8oYs"},"name":[{"family":"Gonzales","given":["Silvia"]}],"gender":"female","birthDate":"1978-04-23","address":[{"line":["123 Abb St"],"city":"SomeVille2","state":"Mac","postalCode":"5432"}]}
{"resourceType":"Patient","id":"TGT1-1835","meta":{"versionId":"1","lastUpdated":"2025-04-16T09:28:26.804-04:00","source":"#7X2qMH5UbaKOTY1P"},"name":[{"family":"Stevenson","given":["Jacinda"]}],"gender":"female","birthDate":"1960-05-15","address":[{"line":["123 Ccc St"],"city":"SomeVille3","state":"Mac","postalCode":"6789"}]}
{"resourceType":"Patient","id":"TGT1-1836","meta":{"versionId":"1","lastUpdated":"2025-04-16T09:28:41.954-04:00","source":"#FIWw0A09DkM9qbPh"},"name":[{"family":"Jackson","given":["John"]}],"gender":"male","birthDate":"1963-09-17","address":[{"line":["123 Ddd St"],"city":"SomeVille4","state":"Mac","postalCode":"9876"}]}

26.0.5.2Route Configuration

$export routes must be defined in the operationRoutes section of the gateway JSON configuration as shown below:

{
  "operationRoutes": [
    {
      "id": "operatingRoute",
      "resourceTypes": [
        "Patient",
        "Practitioner",
        "Condition",
        "Group"
      ],
      "targets": [
        {
          "targetId": "target1"
        },
        {
          "targetId": "target2"
        }
      ],
      "parallel": true,
      "operations": [
        {
          "name": "$export",
          "system": true,
          "type": true,
          "instance": true
        }
      ]
    }
  ]
}

Note that the $export-poll-status and $proxy-link operations will be automatically included when the $export operation is used. These operations do not require explicit configuration.