How to create REST URLs without verbs?

I'm struggling to determine how to design restful URLs. I'm all for the restful approach of using URLs with nouns and not verbs don't understand how to do this.

We are creating a service to implement a financial calculator. The calculator takes a bunch of parameters that we will upload via a CSV file. The use cases would involve:

  1. Upload new parameters
  2. Get the latest parameters
  3. Get parameters for a given business date
  4. Make a set of parameters active
  5. Validate a set of parameters

I gather the restful approach would be to have the following type URLs:

/parameters
/parameters/12-23-2009

You could achieve the first three use cases with:

  1. POST where you include the parameter file in the post request
  2. GET of first URL
  3. GET of second URL

But how do you do the 4th and 5th use case without a verb? Wouldn't you need URLs like:

/parameters/ID/activate
/parameters/ID/validate

??


Solution 1:

General principles for good URI design:

  • Don't use query parameters to alter state
  • Don't use mixed-case paths if you can help it; lowercase is best
  • Don't use implementation-specific extensions in your URIs (.php, .py, .pl, etc.)
  • Don't fall into RPC with your URIs
  • Do limit your URI space as much as possible
  • Do keep path segments short
  • Do prefer either /resource or /resource/; create 301 redirects from the one you don't use
  • Do use query parameters for sub-selection of a resource; i.e. pagination, search queries
  • Do move stuff out of the URI that should be in an HTTP header or a body

(Note: I did not say "RESTful URI design"; URIs are essentially opaque in REST.)

General principles for HTTP method choice:

  • Don't ever use GET to alter state; this is a great way to have the Googlebot ruin your day
  • Don't use PUT unless you are updating an entire resource
  • Don't use PUT unless you can also legitimately do a GET on the same URI
  • Don't use POST to retrieve information that is long-lived or that might be reasonable to cache
  • Don't perform an operation that is not idempotent with PUT
  • Do use GET for as much as possible
  • Do use POST in preference to PUT when in doubt
  • Do use POST whenever you have to do something that feels RPC-like
  • Do use PUT for classes of resources that are larger or hierarchical
  • Do use DELETE in preference to POST to remove resources
  • Do use GET for things like calculations, unless your input is large, in which case use POST

General principles of web service design with HTTP:

  • Don't put metadata in the body of a response that should be in a header
  • Don't put metadata in a separate resource unless including it would create significant overhead
  • Do use the appropriate status code
  • 201 Created after creating a resource; resource must exist at the time the response is sent
  • 202 Accepted after performing an operation successfully or creating a resource asynchronously
  • 400 Bad Request when someone does an operation on data that's clearly bogus; for your application this could be a validation error; generally reserve 500 for uncaught exceptions
  • 401 Unauthorized when someone accesses your API either without supplying a necessary Authorization header or when the credentials within the Authorization are invalid; don't use this response code if you aren't expecting credentials via an Authorization header.
  • 403 Forbidden when someone accesses your API in a way that might be malicious or if they aren't authorized
  • 405 Method Not Allowed when someone uses POST when they should have used PUT, etc
  • 413 Request Entity Too Large when someone attempts to send you an unacceptably large file
  • 418 I'm a teapot when attempting to brew coffee with a teapot
  • Do use caching headers whenever you can
  • ETag headers are good when you can easily reduce a resource to a hash value
  • Last-Modified should indicate to you that keeping around a timestamp of when resources are updated is a good idea
  • Cache-Control and Expires should be given sensible values
  • Do everything you can to honor caching headers in a request (If-None-Modified, If-Modified-Since)
  • Do use redirects when they make sense, but these should be rare for a web service

With regard to your specific question, POST should be used for #4 and #5. These operations fall under the "RPC-like" guideline above. For #5, remember that POST does not necessarily have to use Content-Type: application/x-www-form-urlencoded. This could just as easily be a JSON or CSV payload.

Solution 2:

Perhaps something like:

PUT /parameters/activation HTTP/1.1
Content-Type: application/json; encoding=UTF-8
Content-Length: 18

{ "active": true }

Solution 3:

Whenever it looks like you need a new verb, think about turning that verb into a noun instead. For example, turn 'activate' into 'activation', and 'validate' into 'validation'.

But just from what you've written I'd say your application has much bigger problems.

Any time a resource called 'parameter' is proposed, it should send up red flags in every project team member's mind. 'parameter' can literally apply to any resource; it's not specific enough.

What exactly does a 'parameter' represent? Probably a number of different things, each of which should have a separate resource dedicated to it.

Another way to get at this - when you discuss your application with end users (those who presumably know little about programming) what are the words they themselves use repeatedly?

Those are the words you should be designing your application around.

If you haven't yet had this conversion with prospective users - stop everything right now and don't write another line of code until you do! Only then will your team have an idea of what needs to be built.

I know nothing about financial software, but if I had to guess, I'd say some of the resources might go by names such as "Report", "Payment", "Transfer", and "Currency".

There are a number of good books on this part of the software design process. Two I can recommend are Domain Driven Design and Analysis Patterns.

Solution 4:

The design of your URLs has nothing to do with whether your application is RESTful or not. The phrase "RESTful URLs" is therefore nonsense.

I think you should do some more reading on what REST actually is. REST treats the URLS as opaque, and as such doesn't know what's in them, whether there are verbs or nouns or whatever. You might still want to design your URLs, but that's about UI, not REST.

That said, let's get to your question: The last two cases are not RESTful and don't fit into any kind of restful scheme. Those are what you might call RPC. If you're serious about REST, you'll have to rethink how your application works from the ground up. Either that or abandon REST and just do your app as an RPC app.

Hrmmm maybe not.

The idea here is that you have to treat everything as a resource, so once a set of parameters has a URL you can refer to it from, you just add:

GET [parametersurl]/validationresults

POST [paramatersurl]
body: {command:"activate"}

But again, that activate thing is RPC, not REST.