78

I have been having a debate about what to do with a trailing slash in a RESTful API.

Lets say I have a resource called dogs and subordinate resources for individual dogs. We can therefore do the following:

GET/PUT/POST/DELETE http://example.com/dogs
GET/PUT/POST/DELETE http://example.com/dogs/{id}

But what do we do with the following special case:

GET/PUT/POST/DELETE http://example.com/dogs/

My personal view is that this is saying send a request to an individual dog resource with id = null. I think the API should return a 404 for this case.

Others say the request is accessing the dogs resource i.e. the trailing slash is ignored.

Does anyone know the definitive answer?

GWed
  • 3,085
  • 5
  • 26
  • 43
  • 2
    I thought the RESTful way was to distinguish between dog/id and dogs (meaning all dogs). – pdr Feb 13 '13 at 12:54
  • From the book RESTful Web Services - subordinate resources: resources that exist in relation to some other “parent” resource i.e. dogs/{id} A web-enabled database may expose a table as a resource, and the individual database rows as its subordinate resources. – GWed Feb 13 '13 at 13:04
  • It is accessing the dog resource, the trailing slash should be ignored which means it should get a forbidden response for trying to delete something that delete should not be applied to. I guess that 404 is also acceptable. Does it matter though? – Benjamin Gruenbaum Feb 13 '13 at 13:18
  • I don't follow - who said you can't delete dogs? If you delete dogs it deletes itself and all the individual dogs. That's why i think allowing calls to dogs/ is risky. What if the client meant to delete an individual dog, but accidentally left off the {id}. The result would be that all dogs would be deleted. Much safer to assume it is asking for {id} null and return 404 – GWed Feb 13 '13 at 14:12
  • I'd treat `dogs` and `dogs/` as equivalent. For me it's clear that `dogs/` is a directory containing the individual dogs. Its less clear what `dogs` is, but I'd treat it as equivalent, just like most webservers accept accesses to directories without the trailing `/`. – CodesInChaos Feb 13 '13 at 18:44

3 Answers3

62

None of this is authoritative (as REST has no exact meaning). But from the original paper on REST a full (not ending in /) URL names a resource, while one ending in a slash '/' is a resource group (probably not worded like that).

A GET of a URL with a slash on the end is supposed to list the resources available.

GET http://example.com/dogs/          /* List all the dogs resources */

A PUT on a URL with a slash is supposed to replace all the resources.

PUT http://example.com/dogs/          /* Replace all the dogs resources */

A DELETE on a URL with a slash is supposed to delete all the resources

DELETE http://example.com/dogs/       /* Deletes all the dogs resources */

A POST on a URL with a slash is supposed to create a new resource can then be subsequently accessed. To be conformant the new resource should be in this directory (though lots of RESTful architectures cheat here).

POST http://example.com/dogs/        /* Creates a new dogs resource (notice singular) */

etc.

The Wikipedia page on the subject seems to explain it well: https://en.wikipedia.org/wiki/Representational_state_transfer#Applied_to_web_services.

Martin York
  • 11,150
  • 2
  • 42
  • 70
  • 1
    It also fits the normal path/url model, where directories are often written with a trailing `/` – CodesInChaos Feb 13 '13 at 18:41
  • 5
    So what should happen if you access a resource group without the trailing `/`? – oberlies Jul 03 '13 at 12:21
  • 1
    @oberlies: It depends on context. There are no hard and fast rules only best practices. There are always expcetions to the rule and it should mean what you expect it to mean. In the example above: `GET http://example.com/dogs` may return meta information about the dogs (not the list itself but meta information about the list of dogs). Maybe or maybe its an error. – Martin York Jul 03 '13 at 19:09
  • 2
    `As the last character within a URI’s path, a forward slash (/) adds no semantic value and may cause confusion. It’s better to drop them completely.` This's not the only [place](https://restfulapi.net/resource-naming/) that suggest to don't use training slash – Laiv Aug 28 '17 at 22:49
  • @Laiv I don't disagree with the sentiment. But please link a more authoritative reference (that's a weak link). – Martin York Aug 28 '17 at 23:11
18
Does anyone know the definitive answer?

There isn't one as there isn't an official document on what is required for a service to be considered RESTful.

That said I would allow the trailing slash simply for ease of use. While technically speaking this could be seen as attempting to access a dog with a null ID; I do not see a user making this jump unless they have read it in your documentation. I can see a user attempting to write code against your API and including the trailing slash simply from habit and wondering why they get a 404 response when they want a list of dogs.

Mike
  • 2,046
  • 16
  • 18
  • What about DELETE http://example.com/dogs/ ? – Benjamin Gruenbaum Feb 13 '13 at 13:21
  • since dogs is the parent of all individual dogs, deleting dogs will delete all individual dogs and itself. If you don't do that, your hypermedia will break down – GWed Feb 13 '13 at 13:54
  • @Gaz_Edge: In REST `example.com/dogs` is a resource completely independent of any resource `example.com/dogs/X`. Thus a DELETE on `example.com/dogs` does not have to delete all the dogs/* (though it can if that is the semantics). But DELETE `example.com/dogs/` should delete all the dogs/*. – Martin York Feb 13 '13 at 18:41
  • @LokiAstari I disagree. `example.com/dogs` is not independent of `example.com/dogs/{id}`; the former represents the _collection_ of dogs; that is, every dog. Also I don't see how that's relevant to the trailing slash on the collection. In my view the most sensible approach is for both of `DELETE example.com/dogs(/)` to behave the same way; to delete every dog (although perhaps a 405 Method Not Allowed is more likely) – hdgarrood Feb 13 '13 at 19:00
  • @hdgarrood: In REST `example.com/PLOP` is definitely its own resource (there is no debate on that). What its internal semantics are is dependent on context. In REST `example.com/PLOP/` is a resource group (of all the resources `example.com/PLOP/*`). Again what that means is context dependent. `PUT example.com/PLOP` means update the resource PLOP (which may mean adding `example.com/PLOP/Y` but usually means updating `example.com/PLOP` dependent on context) while PUT `example.com/PLOP/` means replace **all** resources `example.com/PLOP/*`. – Martin York Feb 13 '13 at 20:13
  • but in this case, the resource `/dogs` _is_ the collection of all dogs `/dogs/*`; they are exactly the same thing (I'm sticking with dogs because a plural noun makes more sense here) – hdgarrood Feb 13 '13 at 21:03
  • 3
    I would say once again that since there isn't a definitive set of rules on what is RESTful what happens when you DELETE /dogs or /dogs/ would be based on what you expect the consumers of your API to expect. Is it likely that they would actually want to delete all dogs with a single request? If so then implement it like that, if not then give a 405 Method Not Allowed response. – Mike Feb 14 '13 at 13:19
  • 1
    I know this is an old thread, but I've recently been wondering about this myself. For what it's worth, the OS X Bash shell treats `foo`, `foo/`, and `foo////` identically. It basically seems to strip out empty path segments. So, if you follow the same approach with your REST service, `dogs` and `dogs/` would refer to the same thing. – Greg Brown Jun 17 '16 at 20:06
2

Two ways.

Method 1

Always use trailing slashes for any resource that may contain children.

Just consider "GET" on a public_html directory with files.

Not possible when hello.html is a file:

/hello.html
/hello.html/youagain.html

But possible when hello.html is a directory:

/hello.html/     (actually /hello.html/index.html)
/hello.html/youagain.html

So if "hello.html" can ever have children then it is always and forevermore "/hello.html/" and "/hello.html/index.html" (or simply /hello.html/) is a listing of these children.

Method 2

Be "smart".

$ find
.
./hello.html
./hello.html/index.html

The find command doesn't care about the type of hello.html. Directory or file, who cares, it is the name of an object. When we write "cp youagain.html hello.html", cp can figure out how to handle hello.html. cp is smart. Your webserver is smart too. It has a path handling library. It has routing. It can stat and tell you if a name is an object or a directory. It can redirect blah to blah/ or even just serve up the same response for both. This is the awesome!!! way. So much tech. Who'd ever want to simply concatenate path strings when we could do all that???