web-servicesresthttpurlurl-design

CRUD URL Design for Browsers (not REST)


Many questions has been asked on Stack Overflow for RESTful URL design

To name a few...

Hierarchical URL Design: Hierarchical RESTful URL design

Understanding REST: Verbs, error codes, and authentication: Understanding REST: Verbs, error codes, and authentication

So I am well aware for Restful URL Design. However, how about URL Design for the Browser for traditional Websites which are not Single Page Applications (SPA).

For the purpose of this example, lets assume we have a Book Database. Lets further assume we have 2 traditional HTML sites created.

  1. HTML Table for showing all books
  2. HTML Form for showing one book (blank or pre-filled with book details)

Now we want that the user of our website can do CRUD operations with it. How about the following URL Design then:

GET /book/show/all        // HTML Table
GET /book/show/{id}       // HTML Form pre-filled
GET /book/new             // HTML Form blank
POST /book/new            // Submit HTML Form
POST /book/update/{id}    // Submit updated HTML Form
POST /book/delete/{id}    // A Link/Button with POST ability (no JS needed)

Questions:

Best practise Browser URL Design

Am I following best practice for URL Design in the Browser (I am not talking about REST here)? Also regarding SEO, Bookmarking and short URL Design? I was thinking of something like: /resource/action/ ...

GET and POST only URL Design

Browsers can only make GET and POST unless someone uses JavaScript. Considering the above URL Design, should it be wiser to introduce JavaScript and make PUT and DELETE requests for updating and deleting a resource? Or should I stay with GET and POST only?

Cheers


Solution

  • Instead of CRUD (create-read-update-delete), I prefer the acronym (D)AREL (display, add, remove, edit, list) -- the (D) is silent ;-)

    While not all RESTful API design choices make sense for a browser based crud app, we can borrow much of it, e.g.:

    GET  /books                -- html table listing all books (alternatively /books/list to go with the DAREL acronym)
    GET  /books/add            -- display a form for adding a new book
    POST /books/add            -- adds a new book and redirects to /book/1 (where 1 is a new book id)
    

    I personally prefer to use plural nouns for collections and singular nouns for items, so..

    GET  /book/1               -- display book 1 info (e.g. a customer view)
    GET  /book/1/edit          -- display a form to edit /book/1
    POST /book/1/edit          -- updates /book/1 and redirects to /book/1
    GET  /book/1/remove        -- maybe/probably optional
    POST /book/1/remove        -- normally /book/1/edit will have a delete button that handles "are you sure..?" and posts here, redirects to /books
    

    The uri scheme is /resource/unique-identifier/action. The (D) / display action is silent/default for a given resource uri.

    This also works if you want to model that a book can have multiple authors:

    GET  /book/1/authors       -- list all authors for /book/1
    GET  /book/1/authors/add   -- add author form
    GET  /book/1/author/1
    GET  /book/1/author/1/edit
    // etc.
    

    although you will likely need a separate/additional url-hierarchy for authors:

    GET  /authors
    GET  /authors/add
    GET  /author/1
    // etc.
    

    and similarly, books that an author has written:

    GET  /author/1/books
    // etc.
    

    Most modern web-apps use ajax calls for sub-resources though, so here you can use a pure RESTful api too:

    GET    /api/book/1/authors     -- returns list of all authors for /book/1
    POST   /api/book/1/authors     -- create a new author, returns the new author uri, e.g. /api/author/1
    GET    /api/author/1           -- get /author/1 info according to MIME type etc.
    PUT    /api/author/1           -- update /author/1
    DELETE /api/author/1           -- delete the /author/1 resource
    DELETE /api/book/1/author/1    -- delete author/1 from /book/1? (or maybe this is covered by PUT /api/author/1 ?)
    

    The translation from the original url-scheme is pretty mechanical

    /resource/unique-id/action -> http-verb /resource/unique-id
    

    where action = http-verb

    display = GET (on a singular resource)
    add = POST
    remove = DELETE
    edit = PUT
    list = GET (on a plural/collection resource)