Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I have a print operation to perform for my customer documents. I need the other standard operations to be performed as well, like add,update, delete. so, I have following:

  • For creating new customer:
    URI = /customer/{id}, type = POST, Methodname = CreateCustomer()
  • For updating:
    URI: /customer/{id}, type = PUT, method = UpdateCstomer()
  • For Delete customer:
    URI = /customer/{id}, type = DELETE, Methodname = DeleteCustomer()
  • For View:
    URI: /customer/{id}, type = GET, method = GetCustomer()

Now, if I need to print a document for that customer, I need a print function. My URI may look like this: /customer/{id}, type = POST , method = PrintCustomer(). But I have used that URI and POST type for CreateCustomer. I wanted the URI to look like this: /customer/Print/{id}, type = POST , method = PrintCustomer().

But I cannot have "Print" verb in my URI. Whats the best way to do this? I thought about /customer/document/{id} as the URI... but I will run into the same issue. I would have the CRUD operations on the "document". So, again I run out of what I would used for "print". Please advise.

share|improve this question
2  
Printing is usually a client-side operation, so I'm curious - how is your setup such that it requires you to send a command to a REST server? –  Shauna Jan 4 '13 at 17:27
1  
@Shauna Not necessarily, the URI may be a request to the server for a print-friendly version of the resource (ie a different view). –  Evan Plaice Jan 4 '13 at 20:07
1  
@EvanPlaice - Fair enough, though that still leaves the act of printing to the client (which, even after fetching a server-side print-friendly version, would then decide what device to print to and send the print command itself, even if that command goes to a print server). A request to get a print-friendly version of a resource would then logically be...well...GET. –  Shauna Jan 7 '13 at 14:10
    
@Shauna Yep but that gets left to the client-side. This is referring to REST operations, which may only take place on the server-side. The question could use some clarification but I think it's safe to make that assumption. –  Evan Plaice Jan 7 '13 at 21:35
add comment

3 Answers

I done this before. To print a document I just return a pdf version of a resource. The client only need to send a GET request for the resource with Accept header application/pdf.

This also avoid creating new URI for temporary resource like print job. Using HTTP header is also part of REST and it keeps the URI clean.

share|improve this answer
add comment

Just add a parameter to the current URI's GET

It's pretty typical to use a URI's for multiple actions.

If you're talking about the same resource but a different action, you'd define it as a parameter.

/customer/{id}?print=true

Then where you define your GET method you detect the presence of the print parameter and handle it differently.

REST is defined in the following way:

  • POST - Create a record, asset, or resource
  • PUT - Update, a record, asset, or resource
  • DELETE - Remove a, record, asset, or resource

GET, on the other hand, is meant to be used in multiple ways because there are typically a lot of different forms that a resource may be retrieved. That's also why GET requests are represented as a query string. If you were working with a database resource you'd literally be retrieving a view via a query but REST is intentionally abstracted to a higher level because it's designed to handle with many different types of resources.

The REST specification is pretty forward thinking, even though API's are only recently starting to use it heavily.

If you're interested in learning more about REST protocols I highly suggest you read "Haters Gonna Hate HATEOAS".


Update:

@Shauna pointed out an interesting hole in my reasoning. There's no true right way and many forms are considered acceptable. I thought about it some more and since your intended use is to transform the data into a different representation, it makes sense to define the transform as a new MIME-Type.

For example, you could represent the URI as:

/customer/{id}+print

Where you could set the response Content-Type to text/html+print. That way you'd also have the option to define more transforms in the future.

For example:

// for application/json
/customer/{id}+json

// for application/atom+xml
/customer/{id}+json

Either way, all forms are acceptable. The implementation you decide depends more on personal preference, and the capabilities of your server.

share|improve this answer
    
To add - As an alternative to using the query string (?print=true), you can also use URI parameters (ie - /customer/{id}/printable). Which one you use will largely depend on the standard your system (CMS, framework, code in general) is set up to handle. Both are considered valid and acceptable. –  Shauna Jan 7 '13 at 14:21
    
@Shauna Technically, the best approach would be to employ a MIME-type specific to printing with the URI '/customer/{id}+print' and a response MIME-Type of text/html+print. The advantage of such an approach being, you can create transforms for many MIME-types (ex text/html, text/x-markdown, application/json, etc) for the same URI. The disadvantage of the solution you present is, you'd need to create an additional URI (and define another route) for every different MIME-Type. It kinda defeats the purpose of using REST. –  Evan Plaice Jan 7 '13 at 21:59
    
(cont) I would argue that URI-hacks are an anti-pattern introduced primarily by the ROR community but that doesn't mean they aren't useful. With the arrival of better low-level HTTPd servers it's just becoming easier to implement REST in a manner that fully leverages its potential. Things have come a long way since the days where Apache and routing everything through index.html was the only option. –  Evan Plaice Jan 7 '13 at 22:13
add comment

POST doesn't mean "create", it means "process". You can create a new resource by posting a suitable request to an existing resource (i.e. post to /customers to create a new customer). But you can also use POST to fill in all of the other actions which don't correspond to a neat CRUD paradigm.

In the case of printing, you should consider the act of printing as a resource itself. You're asking the system to create a "print job" for you. This means you can have a prints/ resource which acts as the container for all prints requested. When you want to print something you POST a document to this resource which contains all the information about the print-out you want to create, identifying the resources you want to print with links to them.

As a JSON document, it could look like this:

{
   contents: ["http://site/customers/12345"],
   paper-size: "A4",
   duplex: "true"
}

Obviously, you need to customise this to be relevant to what you want to do. The key thing is that you're identifying other resources to print by specifying their URL.

In response to the request, you could simply return a 200 OK or a 204 No-Content and treat it as a fire-and-forget process. However, if you wanted to enhance it, you could return 201 Created and specify the URL of the newly created print job, e.g. /prints/12345.

A user could then perform a GET on the resource to see the status of their print job (pending, in-progress, etc), or could request the job be cancelled by issuing a DELETE.

Once you rephrase the problem in terms of resource, the RESTful design should come naturally and give you opportunity to expand and enhance in ways you may not have immediately considered.

share|improve this answer
1  
POST usually means create/insert, whereas put usually means update save/update. That's how it's defined in REST even if it isn't how it's usually used in HTML. –  Evan Plaice Jan 4 '13 at 20:01
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.