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
精彩评论