1

I'm experimenting with the UK NHS 'GP Connect' REST API and trying to wrap some of the connection complexity in a more simple Ruby layer.

I've been successfully playing with the API via Postman and the responses are all correctly unzipped to JSON/FHIR. Taking the simplest of the requests from my Postman session and converting it to Ruby using the Faraday HTTP gem, I can make the request/response cycle work fine, but the response is still gzipped. (I'm using Ruby 2.6.1 and Faraday 0.15.4)

(The API requires 'accept-encoding': 'gzip' to work at all.)

Googling the problem I'm having turns up only Faraday middleware which is intended to be used when not using Net::HTTP (the default adapter, and what I am using)

The whole thing is a single script at this stage so it's easy enough to show. (There are additionally some client certs and a locally installed CA cert which are all working fine and no issues)

***** = I've blanked it to protect the innocent, although the healthcare endpoint I'm using here is a dummy-test with fictional data anyway.

require 'faraday'

identifier = "identifier=https://fhir.nhs.uk/Id/nhs-number|*****"
baseurl = "https://systmoneukdemo1.tpp-uk.com"
headers = {
  "authorization": '*****',
  "content-type": 'application/json+fhir',
  "accept-encoding": 'gzip',
  "accept": 'application/json+fhir',
  "ssp-from": '*****',
  "ssp-interactionid": 'urn:nhs:names:services:gpconnect:fhir:rest:search:patient-1',
  "ssp-to": '123456',
  "ssp-traceid": '*****',
  "cache-control": 'no-cache',
}

connection = Faraday.new(
  url: baseurl,
  ssl: {
    ca_file: './certs/cacert.crt',
    client_cert: OpenSSL::X509::Certificate.new(File.read("certs/summer-school-cert.crt")),
    client_key: OpenSSL::PKey::RSA.new(File.read("certs/summer-school-cert.key")),
  }
)

response = connection.get do |request|
  request.url "/SystmOneMHS/NHSConnect/Z12345/STU3/1/Patient?#{identifier}"
  request.headers = headers
end

puts response.body

The response when I run ruby script.rb is:

�U�o�0������-   |Z��U�nӪjrV�A�T����;;dM�n�4-������{wϽ'
������)9f�W�Һ�b�-+�e��7���2pZ���dPr�5o���,m��\;
                                                  `*�:�Ά������r��1Aju�H��셸T�Ϙ��ލ|�?�
                                                                                          ߶ih>jy����D����5&=��m��/G��Ñ�'�Ϣ#?��'Q6�~���y��^[.�u��-��@�ȡSǛ^�~�b?|A�#צ�%eu��:
                   �� ���h�M�4dm��j�WB�l
                                        8�%��f��b��sf����C�>iS[
��C�q$�ɛ���ǣ��h�oF�?�jٙR
                         �7�gh�h�����w�`��d�:iq�P�  ������Ya�z<����k��d5X1����J�WfV��}�y�@�w%��0���
��;à)�!g����(��L�WMm�<xg��L����p�I�������9��]#
                                                 ��i�N3�nz��z�'�Mf�țz�ڪ�����]"�y�����r'
                                                                                         j����gru��_��u��C,��U�� /
ý"���H����V��0�kT�ĸ��.f��pUNՊI�ݎvs��Z���잹˂�}��g��6Q��v���p<
             �-.6z
R�Ğ��6�V��  ��-Pzs�L��Ի�4�_��L��Z�b��g:��;�OF=g{�y�?Ly�+����kk���H�y���
������a��s}��O/�W�=��r��F��%a

however if I pipe that output into gzip:

ruby script.rb | gzip -d
{"resourceType":"Bundle","id":"4D2EAEC0-A8DB-11E9-8B9A-1BA7090BDAD3","meta":{"profile":["https://fhir.nhs.uk/STU3/StructureDefinition/GPConnect-Searchset-Bundle-1"]},"type":"searchset","entry":[{"fullUrl":"Patient/9222500000000000","resource":{"resourceType":"Patient","id":"9222500000000000","meta":{"profile":["https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Patient-1"],"versionId":"220262D942C746E9D8023C82ABC8F500","lastUpdated":"2019-07-17T22:39:05+01:00"},"identifier":[{"system":"https://fhir.nhs.uk/Id/nhs-number","value":"6656336566","extension":[{"url":"https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-NHSNumberVerificationStatus-1","valueCodeableConcept":{
    "coding":
    [
        {
            "system":"https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-NHSNumberVerificationStatus-1",
            "code":"01",
            "display":"Number present and verified"
        }
    ]
}}]}],"name":[{"prefix":["Mr"],"given":["Michael"],"family":"Smith","use":"official"}],"address":[{"use":"home","type":"both","line":["6 Wren Street"],"city":"London","postalCode":"WC1X 0HD"}],"telecom":[{"system":"phone","use":"home","value":"01132252263"},{"system":"email","use":"home","value":"liang.lin@tpp-uk.com"}],"birthDate":"1960-01-19","gender":"male","active":true,"managingOrganization":{"reference":"Organization/bd00000000000000"},"generalPractitioner":[{"reference":"Practitioner/e576600000000000"}],"extension":[{"url":"https://fhir.nhs.uk/STU3/StructureDefinition/Extension-CareConnect-GPC-RegistrationDetails-1","extension":[{"url":"registrationPeriod","valuePeriod":{"start":"2017-01-01T00:00:00Z"}},{"url":"registrationType","valueCodeableConcept":{"coding":[{"system":"https://fhir.nhs.uk/STU3/CodeSystem/CareConnect-RegistrationType-1","code":"O","display":"Other"}]}},{"url":"preferredBranchSurgery","valueReference":{"reference":"Location/bd00000000000000_0100000000000000"}}]}]}}]}
gzip: stdin: unexpected end of file

I get un-gzipped FHIR JSON content, which is what I'm expecting. So everything is working right up until the ungzipping stage, which is not being carried out, and the raw ugzipped content is returning to me as the response.

Somehow it seems that Faraday isn't automatically un-gzipping the response body. I've searched in Faraday's documentation for a flag or other control that I perhaps should be setting, but I can't find a clear explanation of how this should be handled.

Clearly I could un-gzip this output directly, but I would like to know if there is a proper internal 'Faraday' way of doing it. If it's using the Faraday Gzip middleware, then great, but how?

If it helps with working out what's going on, I've reimplemented this in plain Net::HTTP and the results are exactly the same, the reponse body is not being un-gzipped. Both Faraday and Net::HTTP say they do the ungzipping automatically, but neither of them are.

Any thoughts or advice welcome.

1 Answers1

2

Given you are using the faraday-middleware gem, you can just use the :gzip middleware in connection setup.

request.use :gzip

Using your code as example:

response = connection.get do |request|
  request.url "/SystmOneMHS/NHSConnect/Z12345/STU3/1/Patient?#{identifier}"
  request.use :gzip
  request.headers = headers
end
Duke
  • 3,226
  • 1
  • 18
  • 23
  • Works. But beware of trying to mix .response :json with .use :gzip as decompression apparently does not execute prior to the json parse sadly. – jprio Dec 21 '22 at 03:14