Override API default_format for a specific endpoint

38 views
Skip to first unread message

Etienne van Tonder

unread,
Feb 11, 2020, 6:06:10 AM2/11/20
to Grape Framework Discussion
Hi,

I'm developing an API to work with Microsoft WOPI, an enpoint (PutFile) I have to implement is one that receives the contents of an updated document in binary format that is sent in the request body. The problem is that they do not include the content-type in the request header so grape defaults to treating the data as json which is my default format, it then generates an Grape::Exceptions::InvalidMessageBody error as it's trying to process the request body as json not binary.

I've searched everywhere to see how I can handle this, is there some way of overriding the default format by somehow detecting the action and then setting the appropriate formatter to use?

Any help appreciated.

Thanks,

Etienne.

Daniel D.

unread,
Feb 11, 2020, 8:22:35 AM2/11/20
to Grape Framework Discussion
I think the best way is to write a middleware that sits in front of grape and make these decisions. Alternatively you can roll a custom parser.

Some parsing happens in Rack, so you might need to do this even higher up the chain.

If you can't get it to work, put up a trivial project and we'll help you.

--
You received this message because you are subscribed to the Google Groups "Grape Framework Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ruby-grape+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ruby-grape/56cf094d-8388-41c1-ac4d-61e8c00ea2ae%40googlegroups.com.


--

Etienne van Tonder

unread,
Feb 12, 2020, 5:49:38 AM2/12/20
to Grape Framework Discussion
Thank you for getting back to me, as you suggested I ended up writing a small middelware class to set the content-type for this particular endpoint which has now fixed the problem. Thank you!


On Wednesday, February 12, 2020 at 12:22:35 AM UTC+11, Daniel Doubrovkine wrote:
I think the best way is to write a middleware that sits in front of grape and make these decisions. Alternatively you can roll a custom parser.

Some parsing happens in Rack, so you might need to do this even higher up the chain.

If you can't get it to work, put up a trivial project and we'll help you.

On Tue, Feb 11, 2020 at 6:06 AM Etienne van Tonder <etie...@gmail.com> wrote:
Hi,

I'm developing an API to work with Microsoft WOPI, an enpoint (PutFile) I have to implement is one that receives the contents of an updated document in binary format that is sent in the request body. The problem is that they do not include the content-type in the request header so grape defaults to treating the data as json which is my default format, it then generates an Grape::Exceptions::InvalidMessageBody error as it's trying to process the request body as json not binary.

I've searched everywhere to see how I can handle this, is there some way of overriding the default format by somehow detecting the action and then setting the appropriate formatter to use?

Any help appreciated.

Thanks,

Etienne.

--
You received this message because you are subscribed to the Google Groups "Grape Framework Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ruby-...@googlegroups.com.

Daniel D.

unread,
Feb 13, 2020, 11:23:42 AM2/13/20
to Grape Framework Discussion
Share your code!

To unsubscribe from this group and stop receiving emails from it, send an email to ruby-grape+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ruby-grape/5a10b1eb-c580-436a-8806-c8272a86b21d%40googlegroups.com.

Etienne van Tonder

unread,
Feb 14, 2020, 8:12:49 AM2/14/20
to Grape Framework Discussion
Sure here is my code, I can't find the particular page now but I used some example code that I found during my many searches to get me started, so I can't claim credit for all the code.

module Rack
  class WopiContentType
    def initialize(app, methods = [:post], paths = [/^\/wopi\/files\/(.*?)\/contents+/], content_type = 'application/octet-stream')
      @app = app
      @methods = (methods.is_a?(Array) ? methods : [methods]).map{ |item| item.to_s.upcase }
      @paths = paths.is_a?(Array) ? paths : [paths]
      @content_type = content_type
    end

    def call(env)
      req = Rack::Request.new(env)

      if match_path?(req.path) and match_method?(req.request_method)
        env['CONTENT_TYPE'] = @content_type
        env['ACCEPT'] = @content_type
      end

      @app.call(env)
    end

  private

    def match_path?(path)
      path = path.to_s
      @paths.find { |p| p.is_a?(Regexp) ? p.match(path) : p == path }
    end

    def match_method?(method)
      @methods.empty? || @methods.include?(method)
    end

    def output_headers(env)
      all_headers = env.select {|k,v| k.start_with? 'HTTP_'}
        .collect {|key, val| [key.sub(/^HTTP_/, ''), val]}
        .collect {|key, val| " #{key}: #{val} "}
        .sort
      Rails.logger.info("ApiContentType headers: #{all_headers.inspect}")
    end

  end
end



Share your code!

Reply all
Reply to author
Forward
0 new messages