user550738
user550738

Reputation:

what should my URLs look like for this simple REST web service?

I'm new to REST but I've built a simple web service and I'm having trouble finding a simple explaination of what URL format would be correct.

The service allows to create an invoice and push it through a series of simple approval phases.

(1) Read all invoices in an XML format:

GET: http://localhost/webapp/ws/invoices

(2) Read one invoice in an XML format (ex. invoice id = 555):

GET: http://localhost/webapp/ws/invoices/555

(3) Submit a new invoice:

POST: http://localhost/webapp/ws/invoices

With the invoice attributes ("userid", "totalprice", etc) are included like the POST parameters of a simple HTML form.

(4) Approve an invoice:

POST: http://localhost/webapp/ws/invoices/action

With the action attributes (ex. "userid=123", invoiceid=567, "action=APPROVE" or "REJECT", etc) are included like the POST parameters of a simple HTML form.

It works fine, but is that even close to what a RESTful web service is supposed to look like?

Any advice is greatly appreciated, thanks.

Rob

Upvotes: 1

Views: 1145

Answers (2)

Tom Howard
Tom Howard

Reputation: 6687

The URLs don't make an API RESTful or not. It is more important to clearly represent your resources and their state transitions (through links and forms) and avoiding out-of-band information that couples clients to your implementation. A RESTful Hypermedia API in Three Easy Steps covers this concept nicely.

1) Create a root resource that provides a well know starting point for all clients and allows them to discover the services available (this can be the same URL used by Browers. Use the Accept header to determine if HTML or your APIs media-type should be returned).

GET: http://localhost/webapp

<webapp href="/webapp">
    <invoices href="/webapp/invoices"/>
    ... any other services ...
</webapp>

2) Create a collection resource for you invoices

GET: http://localhost/webapp/invoices

<invoices href="/webapp/invoices">
    <invoice href="/webapp/invoices/555"/>
    <invoice href="/webapp/invoices/554"/>
    <invoice href="/webapp/invoices/553"/>
    <invoice href="/webapp/invoices/552"/>
    ...
    <search href="/webapp/invoices/" method="get">
        <query type="xpath" cardinality="required"/>
    </search>
    <next href="/webapp/invoices?page=2" method="get"/>
    <create-draft href="/webapp/invoices" method="post">
        <total-price type="decimal" cardinality="optional"/>
        ... user should be picked up automatically based on the authorised user posting the form ...
        ... add other optional and required parameters here. ...
    </create-draft>
</invoices>

This is a paginated collection, with the next element telling the client how to get the next page. If there weren't enough invoices (e.g., 5 invoices and each page can contain 10) then the next element would not be show. Similarly if the requester is no authorised to create invoices then the create-draft form would not be included.

Getting the next page would look something like:

GET: http://localhost/webapp/invoices?page=2

<invoices href="/webapp/invoices">
    <invoice href="/webapp/invoices/545"/>
    <invoice href="/webapp/invoices/544"/>
    <invoice href="/webapp/invoices/543"/>
    <invoice href="/webapp/invoices/542"/>
    ...
    <search href="/webapp/invoices/" method="get">
        <query type="xpath" cardinality="required"/>
    </search>
    <next href="/webapp/invoices?page=3" method="get"/>
    <prev href="/webapp/invoices" method="get"/>
    <create-draft href="/webapp/invoices" method="post">
        <total-price type="xs:decimal" cardinality="optional"/>
        ... user should be picked up automatically based on the authorised user posting the form ...
        ... add other optional and required parameters here. ...
    </create-draft>
</invoices>

3) Create an item resource for your invoices

GET: http://localhost/webapp/invoices/555

<invoice href="/webapp/invoice/555">
    ... details go here ...
    <reject href="/webapp/invoices/555" method="delete">
        <reason type="xs:string" cardinality="required"/>
    </reject>
    <approve href="/webapp/invoices/555" method="put">
       ... add approval parameters here ...
    </approve>
</invoices>

Similarly, if the user is not authorised to reject or approve invoices then those elements should not be displayed. Same goes if the invoice has already been approved (in which case maybe there is a cancel form).

Upvotes: 2

Zheileman
Zheileman

Reputation: 2559

IMHO for the approval process I would do:

(4) Approve an invoice:

PUT: http://localhost/webapp/ws/invoices/555

As you are going to modify an existing resource, identified by the ID (555), so you only need to pass the attributes that will change.

Upvotes: 0

Related Questions