0

I have an api which return huge data, so I want to compress this data and return to the client. I know there are ways of doing in Nginx or Rack::deflater in application.rb. But i want to compress this data only for this particular api response.(don't want to do it in ngnix)

I tried as mentioned in this answer: https://stackoverflow.com/a/35758106/5925134. I am able to compress but not able to respond to client with compressed data. I tried this and want to somehow respond_to gz as response-type.

Zlib::GzipWriter.open('public/huge_data.gz') { |gz| gz.write data.to_json }
    respond_to do |format|
      format.gz { render gz: {File.read('public/huge_data.gz') } }
    end

Is there any way to pass this compressed data to client or any other approach? Thanks in advance

QuadSquad
  • 178
  • 3
  • 13
  • This seems like a fools errand. Just set it up in NGiNX or Rack and then clients can automatically get gzipped responses (or not) depending on the request headers. There is no harm in providing gzipped responses for the rest of the app so I don't see why you would make things an PITA by doing something that belongs on the web server layer in the application. – max Jan 29 '20 at 10:50
  • You also haven't grasped at all how gz compression in HTTP works at all. Gzip encoding is set by the `Content-Encoding` header and not by requesting a gz `Content-Type`. The client can actually request any Content-Type and get it gzipped and it all happens transparently which is kind of the point. https://tools.ietf.org/html/rfc2616#section-3.5 – max Jan 29 '20 at 10:58
  • I agree that i could do it in Nginx or Rack, compressing and decompressing the data has its own cost. What if total time of compression, decompression and data transfer is less than that of only data transfer without compression? There are many apis which have small responses for which we dont need compression. – QuadSquad Jan 29 '20 at 12:34
  • I agree the fact that i could do it in nginx as already mentioned in the question itself – QuadSquad Jan 29 '20 at 12:35
  • If you're using catching then the response is only compressed once. That's also a huge case of premature optimization. – max Jan 29 '20 at 12:40
  • If you really want to do it manually you need to use responds_to :json and just send the content encoding header. You don't want to send the wrong content type. – max Jan 29 '20 at 12:43

1 Answers1

0

I don't recommend this but if you really wanted to manually compress a JSON response this is how you would do it:

class CompressedController < ApplicationController
  def test
    respond_to do |f|
      f.json do
        file = Tempfile.new
        json = JSON.generate(hello: 'World')
        Zlib::GzipWriter.open(file.path) { |gz| gz.write json }
        response.set_header('Content-Encoding', 'gzip')
        send_data file.read, type: :json, disposition: 'inline'
      end
    end
  end
end

This is just a self contained minimal example. Adapt it your actual use case.

If you actually want to solve your performance problems in a sane way use compression on the web server layer together with caching.

max
  • 96,212
  • 14
  • 104
  • 165