Rails: Restrict API requests to JSON format

23,678

Solution 1

Setting a default in your routes won't turn all requests into a JSON request.

What you want is to make sure that whatever you're rendering is a JSON response

You pretty much had it in the first option except you need to do this

before_filter :set_default_response_format

private
  def set_default_response_format
    request.format = :json
  end

That would go under your Base API controller so that when it gets to your actual action the format will always be JSON.

Solution 2

If you want to return a 404, or raise a RouteNotFound error if the format is not :json, I would add a route constraint like this:

Require JSON format:

# routes.rb
MyApp::Application.routes.draw do
  namespace :api, constraints: { format: 'json' } do
    namespace :v1 do
      resources :posts
    end
  end
end

More information can be found here: http://edgeguides.rubyonrails.org/routing.html#request-based-constraints

Solution 3

Second option, using routes format. If a user explicitly requests a XML format, he should not receive a JSON response. He should get a message saying that this URL doesn't answer to XML format, or 404.

By the way, it would be rather easy to respond to all which is what you should do in my opinion.

class FooController
  respond_to :xml, :json
  def show
    @bar = Bar.find(params[:id])
    respond_with(@bar)
  end
end
Share:
23,678

Related videos on Youtube

JJD
Author by

JJD

Android, Kotlin, Java, Git, Python, Ruby, Ruby on Rails, JavaScript, MacOS, Ubuntu #SOreadytohelp http://stackoverflow.com/10m

Updated on June 01, 2020

Comments

  • JJD
    JJD about 4 years

    I would like to restrict requests to all API controllers to being redirected to the JSON path. I would like to use a redirect since also the URL should change according to the response.
    One option would be to use a before_filter which redirects the request to the same action but forces the JSON format. The example is not working yet!

    # base_controller.rb
    class Api::V1::BaseController < InheritedResources::Base
      before_filter :force_response_format
      respond_to :json
      def force_response_format
        redirect_to, params[:format] = :json
      end
    end
    

    Another option would be to restrict the format in the routes settings.

    # routes.rb
    MyApp::Application.routes.draw do
      namespace :api, defaults: { format: 'json' } do
        namespace :v1 do
          resources :posts
        end
      end
    end
    

    I want all request to end up as a JSON request:

    http://localhost:3000/api/v1/posts
    http://localhost:3000/api/v1/posts.html
    http://localhost:3000/api/v1/posts.xml
    http://localhost:3000/api/v1/posts.json
    ...
    

    Which strategy would you recommend?

  • JJD
    JJD over 11 years
    Setting the request.format to :json solves the problem that all responses return JSON. It does however not change the URL in the addressbar.
  • Leo Correa
    Leo Correa over 11 years
    If you're doing an API why would you need to write the URL in the address bar? Note that doing a redirect would return a 300 status and its probably not the most efficient, don't quote me on that though.
  • JJD
    JJD over 11 years
    This being said, would you then recommend to rewrite the request format to JSON in any case? Another option would be to return some HTTP status as mathieugagne and you mentioned.
  • Leo Correa
    Leo Correa over 11 years
    These are design options that you have to consider for your API. Do you want to just accept/return JSON or are you open for returning XML and other formats...
  • Eric Platon
    Eric Platon almost 10 years
    +1 for the beginning of the comment. Adding a format is not that easy in my experience, although Rails make it easy to implement. The API designer still has to think through what it means to support an additional format, with all the implications.
  • asymmetric
    asymmetric about 9 years
    I would argue that a 406 is a more accurate response in this case. Any Idea why this approach returns a 404?
  • dgmstuart
    dgmstuart about 6 years
    @asymmetric It's because the constraint says "this rule only matches json requests", so any non-json requests won't match and will fall through to the end unless you have a specific later rule which matches non-json requests and responds explicitly with another response.