开发者

Ruby on Rails - differentiating plural vs singular resource in a REST API

I'm working on building the URLs for my REST API before I begin writing any code. Rails REST magic is fantastic, but I'm slightly bothered the formatting of a URL such as:

http://myproject/projects/5

where Project is my resource and 5 is the project_id. I think if a user is looking to retrieve all of their projects, then a respective HTTP GET http://myproject/projects makes sense. However if the开发者_如何学运维y're looking to retrieve information on a singular resource, such as a project, then it makes sense to have http://myproject/project/5 vs http://myproject/projects/5. Is it best to avoid this headache, or do some of you share a similar concern and even better - have a working solution?


Rails (3) has a lot of conventions when it comes to singular vs plural. For example, model classes are always singular (Person), while the corresponding tables are always plural (people). (For example, Person.all maps to select * from people.)

For routes, there's a concept of a singular resource as well as a plural resource. So if you did resource :account then you would get paths like /account for the default path or /account/edit for a path to a form to edit the account. (Note that Rails uses /account with a PUT method to actually update the account. /account/edit is a form to edit the account, which is a separate resource from the account itself.) If you did resources :people, however, then you would get paths like /people, /people/1, and /people/1/edit. The paths themselves indicate whether there can only be one instance of a given type of resource, or whether there can be multiple instances distinguished by some type of identifier.


I agree, go with the flow. Consider how the URL forms a hierarchy.

The root of your website is where you start to access anything.

/projects/ narrows it down to only projects, not anything else. From projects you can do lots of things, /list, /index/, /export, etc... the /id limits things even further.

At each / the scope of what do becomes narrower, and I think it makes sense.

Further programming is all about arbitrary rules. Indexs starting at 1 vs 0, and so on. Anyone working with your urls will sort things out in short order.


There are cases where a singular path to a resource is helpful. If your resource ids are non-numeric user defined names then routing clashes are possible. Example:

/applications/new --> create a new application or show user's application named new?

In this situation you can choose to limit the user input to avoid the clash, or, this can be worked around by overwriting the default Rails 3 behavior:

class ActionDispatch::Routing::Mapper
  module Resources
    RESOURCE_OPTIONS  << :singular_resource
    class Resource
      def member_scope
        @options[:singular_resource] ? "#{singular}/:id" : "#{path}/:id"
      end

      def nested_scope
        @options[:singular_resource] ? "#{singular}/:#{singular}_id" : "#{path}/:#{singular}_id"
      end
    end
  end
end

Then when specifying a new resource route:

resources :applications, :singular_resource => true

Which will generate the routes:

    GET     /applications
    GET     /applications/new
    POST    /applications
    GET     /application/:id
    GET     /application/:id/edit
    PUT     /application/:id
    DELETE  /application/:id
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜