The TRESTRequest component has an AcceptEncoding property where you can specify the type of compression you would like applied to the response. The TRESTResponse component has a ContentEncoding property that specifies the the encoding that the server chose. The most common compression encoding is gzip, followed by deflate. The others are rarely used (although brotli is a new compression that looks promising for the future.)
The TRESTResponse has two ways to access the response data directly, the RawBytes property and the Content property. Both are read-only. So we can read the compressed response data, but cannot update the TRESTResponse with the decompressed data. Updating the TRESTReponse allows it to work with the TRESTResponseDataSetAdapter, which is a fantastic feature.
Luckily we can use the protected mode workaround to update the value. Here is a unit that you can include in your project to easily decompress the TRESTResponse and continue to use it with the Data Set Adapter.
<br /> unit RestDecompress;</p> <p>interface</p> <p>uses<br /> System.SysUtils, System.Types, System.Classes, IPPeerClient, REST.Client;</p> <p>procedure DecodeRestResponse(ARestResponse: TRESTResponse);</p> <p>implementation</p> <p>uses<br /> System.Zlib,<br /> IdBaseComponent, IdException, IdZLibCompressorBase, IdCompressorZLib;</p> <p> type // protected mode work around<br /> TProtectedRESTResponse = class(TRESTResponse)<br /> end;</p> <p>procedure DecodeRestResponse(ARestResponse: TRESTResponse);<br /> var<br /> LCompressed: TMemoryStream;<br /> LDecompressed: TStringStream;<br /> LDecompress: TIdCompressorZLib;<br /> begin<br /> if Length(ARestResponse.ContentEncoding) = 0 then exit;</p> <p> LCompressed := nil;<br /> LDecompressed := nil;<br /> LDecompress := nil;<br /> try<br /> LCompressed := TMemoryStream.Create;<br /> LDecompressed := TStringStream.Create;</p> <p> LCompressed.WriteData(ARESTResponse.RawBytes, Length(ARESTResponse.RawBytes));<br /> LCompressed.Position := 0;</p> <p> // Use the Indy decompression libraries because the HTTP stream doesn't<br /> // have the proper headers that System.ZLib looks for.</p> <p> LDecompress :=TIdCompressorZLib.Create();</p> <p> if ARestResponse.ContentEncoding = 'gzip' then<br /> LDecompress.DecompressGZipStream(LCompressed, LDecompressed)<br /> else if ARestResponse.ContentEncoding = 'deflate' then<br /> begin<br /> // Due to variations in the deflate server side implementations,<br /> // this rarely works, but is here for completeness and just in case<br /> LDecompress.DecompressHTTPDeflate(LCompressed, LDecompressed);<br /> end;</p> <p> TProtectedRESTResponse(ARESTResponse).SetContent(LDecompressed.DataString);<br /> finally<br /> LDecompressed.Free;<br /> LCompressed.Free;<br /> LDecompress.Free;<br /> end;<br /> end;</p> <p>end.<br />
Simply use this unit, and then add a call to DecodeRestResponse(RESTResponse) to RESTResponse’s OnAfterExecute event handler. It checks the ContentEncoding and then uses the correct decompression and updates the content.
You’ll notice it uses the Indy TIdCompressorZLib component instead of the new System.ZLib library. The reason is a GZip encoded HTTP response doesn’t include the full headers expected by the ZLib library. There is a way to work around this, but no need to do that since the Indy library works fine.