Loading ...
Sorry, an error occurred while loading the content.
 

How to handle in a RESTful fashion?

Expand Messages
  • Donald Ball
    I m trying to develop a webapp in a RESTful fashion, but recently ran into a conundrum that I m hoping y all can help me solve. I ve already scoured the wiki
    Message 1 of 6 , Oct 23, 2002
      I'm trying to develop a webapp in a RESTful fashion, but recently ran into
      a conundrum that I'm hoping y'all can help me solve. I've already scoured
      the wiki and the white papers but don't see any specific advice for my
      situation.

      The webapp is framed (not necessarily my choice, but it's also not
      necessarily a bad choice for it either). The left frame contains an
      explorer-type folder tree containing essentially the names of columns in a
      database table. The right frame is a content pane. When the user selects a
      column from the tree, the column's values should be added to a table in the
      content frame. Selecting another column from the tree adds more columns to
      the table.

      Question is, how do I make all of this happen in a RESTful fashion? Is it,
      in fact, even possible given our design constraints? The links in the tree
      are going to have to be of the form:

      GET /viewer?column=foo

      on the server-side, when processing such a request, we add the requested
      column to a session variable and render the new table. But the URL for the
      table frame is going to be incorrect after a couple such requests. If the
      user were to bookmark the URL and revisit it later, they would get a table
      with only the last column that was added. Clearly, that's not RESTful.

      I was idly wondering, would it be RESTful if the server-side piece that
      adds the requested column to the session variable were to redirect the
      browser to a URL for the table that was, well, unique? e.g.

      /viewer?column=foo&column=bar&column=bat

      Alternately, would it be RESTful if the server-side piece were to create a
      named resource which stores the state of the table and return a URL to that
      resource? e.g.

      /viewer?table=23

      Or is there another, better possibility that would make for a cleaner, more
      RESTful urlspace?

      - donald
    • S. Mike Dierken
      ... From: Donald Ball ... more ... Two possiblities a) use client-side state for the set of column selected If the left panel has a list
      Message 2 of 6 , Oct 23, 2002
        ----- Original Message -----
        From: "Donald Ball" <dball@...>

        >
        > Or is there another, better possibility that would make for a cleaner,
        more
        > RESTful urlspace?

        Two possiblities

        a) use client-side state for the set of column selected
        If the left panel has a list of db columns, and each were a checkbox in a
        form, auto-submit the form when a checkbox is checked, and have the form use
        method=GET. This will cause a URL to be generated of the format
        ?col1=on&col3=on&col7=on
        This URI identifies a resource which is that particular permutation of
        column names. This can be easily rendered into HTML
        Of course, using a FORM literally might not be the most chrome looking UI,
        so let your script kiddies go nuts.

        b) use persistent data on the server to maintain state
        If this information should be long-lived, have the server maintain a URI
        that doesn't change and is unique for that user (in the same sense that a
        session variable is unique to a user). When the left hand panel POSTs data
        to that URI, keep updating the selected columns and return a representation
        of the table with the users current set of selected columns.
        This is nice if the purpose of the app is to later use that selected 'db
        view' in some way - perhaps to modify attributes (like 'max rows' or
        something), as well as this approach makes that 'db view' an identifable
        concept so you could do something like 'show me db #2 with view #27'

        mike
      • Donald Ball
        ... Can t / don t want to reload this frame every time the link is checked. It s a big tree and somewhat expensive to render. Could use javascript to generate
        Message 3 of 6 , Oct 28, 2002
          >a) use client-side state for the set of column selected
          >If the left panel has a list of db columns, and each were a checkbox in a
          >form, auto-submit the form when a checkbox is checked, and have the form
          >use
          >method=GET. This will cause a URL to be generated of the format
          >?col1=on&col3=on&col7=on
          >This URI identifies a resource which is that particular permutation of
          >column names. This can be easily rendered into HTML
          >Of course, using a FORM literally might not be the most chrome looking UI,
          >so let your script kiddies go nuts.

          Can't / don't want to reload this frame every time the link is checked.
          It's a big tree and somewhat expensive to render. Could use javascript to
          generate the links on the fly, but that's also not necessarily desirable
          from a RESTful pov.

          >b) use persistent data on the server to maintain state
          >If this information should be long-lived, have the server maintain a URI
          >that doesn't change and is unique for that user (in the same sense that a
          >session variable is unique to a user). When the left hand panel POSTs data
          >to that URI, keep updating the selected columns and return a
          representation
          >of the table with the users current set of selected columns.
          >This is nice if the purpose of the app is to later use that selected 'db
          >view' in some way - perhaps to modify attributes (like 'max rows' or
          >something), as well as this approach makes that 'db view' an identifable
          >concept so you could do something like 'show me db #2 with view #27'

          I think that's the one I'd like to run with. Question is, what do the
          mechanics look like? When adding a column to a view, I issue a request
          something like:

          GET /view?task=add&var=foo

          then I redirect the user to:

          /view?id=23

          which is the long-lived URL for the dataset view they're constructing. This
          solution isn't entirely RESTful for two reasons, though, I think:

          1. I'm not specifying the view id in the change request. Due to the fact
          that I don't want to regenerate the link tree, though, this is largely
          unavoidable. I'll just store the user's active view id in their session,
          but always redirect them to a URL which they can use absent a session.

          2. I should be using a POST request when changing the dataset view. There
          are two reasons why I can't/shouldn't though:

          a. The change request is activated by a link, which can't issue a POST
          request unless use javascript links

          b. You're not supposed to issue a redirect from a POST request

          Any thoughts on either the proposed solution or the (nitpicky) problems I
          see in the solution?

          - donald
        • S. Mike Dierken
          ... From: Donald Ball To: Sent: Monday, October 28, 2002 7:56 AM Subject: Re: [rest-discuss] How to
          Message 4 of 6 , Oct 28, 2002
            ----- Original Message -----
            From: "Donald Ball" <dball@...>
            To: <rest-discuss@yahoogroups.com>
            Sent: Monday, October 28, 2002 7:56 AM
            Subject: Re: [rest-discuss] How to handle in a RESTful fashion?


            > >a) use client-side state for the set of column selected
            > >If the left panel has a list of db columns, and each were a checkbox in a
            > >form, auto-submit the form when a checkbox is checked, and have the form
            > >use
            > >method=GET. This will cause a URL to be generated of the format
            > >?col1=on&col3=on&col7=on
            > >This URI identifies a resource which is that particular permutation of
            > >column names. This can be easily rendered into HTML
            > >Of course, using a FORM literally might not be the most chrome looking
            UI,
            > >so let your script kiddies go nuts.
            >
            > Can't / don't want to reload this frame every time the link is checked.
            > It's a big tree and somewhat expensive to render.
            You don't re-load the frame on the left, you use <form target='panel_right'
            > to reload the panel on the right.

            > Could use javascript to generate the links on the fly, but that's also not
            necessarily desirable
            > from a RESTful pov.
            You are in a classical browser, you aren't going to get very far into REST
            land that way.
            Serve the user first, and the architecture second.

            >
            > >b) use persistent data on the server to maintain state
            > >If this information should be long-lived, have the server maintain a URI
            > >that doesn't change and is unique for that user (in the same sense that a
            > >session variable is unique to a user). When the left hand panel POSTs
            data
            > >to that URI, keep updating the selected columns and return a
            > representation
            > >of the table with the users current set of selected columns.
            > >This is nice if the purpose of the app is to later use that selected 'db
            > >view' in some way - perhaps to modify attributes (like 'max rows' or
            > >something), as well as this approach makes that 'db view' an identifable
            > >concept so you could do something like 'show me db #2 with view #27'
            >
            > I think that's the one I'd like to run with. Question is, what do the
            > mechanics look like? When adding a column to a view, I issue a request
            > something like:
            >
            > GET /view?task=add&var=foo
            No, no, no. Did I mention, no? Do not do an 'update' with a GET.
            If you have a single view that you add names to over time, then the requests
            will go to the /same uri/ - so don't put things in the query terms (it is
            part of the URI).
            You will want something like:

            ====
            // request #1
            POST /view?task=add
            Content-Type: application/x-www-form-urlencoded

            var=foo

            // request #2
            POST /view?task=add
            Content-Type: application/x-www-form-urlencoded

            var=bar

            =====
            Notice how the same URI is used twice. That is because the same resource is
            updated twice. Also, notice that the URI that is being used isn't all that
            great - all users would be appending column names all day long. You need to
            get some qualifying information intothe URI - either the userID, the viewID,
            or something.


            >
            > then I redirect the user to:
            >
            > /view?id=23
            >
            > which is the long-lived URL for the dataset view they're constructing.
            This
            > solution isn't entirely RESTful for two reasons, though, I think:
            >
            > 1. I'm not specifying the view id in the change request. Due to the fact
            > that I don't want to regenerate the link tree, though, this is largely
            > unavoidable. I'll just store the user's active view id in their session,
            > but always redirect them to a URL which they can use absent a session.
            Tell me again why using a viewId causes the tree to change?

            >
            > 2. I should be using a POST request when changing the dataset view. There
            > are two reasons why I can't/shouldn't though:
            >
            > a. The change request is activated by a link, which can't issue a POST
            > request unless use javascript links
            Causing updates on the server via a link is to be avoided. I know it would
            be really nice to do this, but you need to avoid this anyway.
            If you really want that kind of silent update, use javascript. If you use
            checkboxes and send the form on each click, then you'll know when the user
            de-selects a column. Clicking links won't allow you do de-select columns.

            >
            > b. You're not supposed to issue a redirect from a POST request
            There are two different response status codes - one means 'request
            finished - see this link for results', the other means 'request not
            processed - try again at this location'.
            Why aren't you supposed to redirect from a POST?
          • Donald Ball
            ... form ... target= panel_right ... I take your point, if the thing on the left was a form with checkboxes, but UI constraints dictate that it s an explorer
            Message 5 of 6 , Oct 28, 2002
              >> >a) use client-side state for the set of column selected
              >> >If the left panel has a list of db columns, and each were a checkbox in
              >a
              >> >form, auto-submit the form when a checkbox is checked, and have the
              form
              >> >use
              >> >method=GET. This will cause a URL to be generated of the format
              >> >?col1=on&col3=on&col7=on
              >> >This URI identifies a resource which is that particular permutation of
              >> >column names. This can be easily rendered into HTML
              >> >Of course, using a FORM literally might not be the most chrome looking
              >UI,
              >> >so let your script kiddies go nuts.
              >>
              >> Can't / don't want to reload this frame every time the link is checked.
              >> It's a big tree and somewhat expensive to render.
              >You don't re-load the frame on the left, you use <form
              target='panel_right'
              >> to reload the panel on the right.

              I take your point, if the thing on the left was a form with checkboxes, but
              UI constraints dictate that it's an explorer tree with links. c'e la vie.

              >> Could use javascript to generate the links on the fly, but that's also
              >not
              >necessarily desirable
              >> from a RESTful pov.
              >You are in a classical browser, you aren't going to get very far into REST
              >land that way.
              >Serve the user first, and the architecture second.

              I think the REST architecture principles have just as much to offer
              traditional HTML webapps as new-fangled XML web services. But that's beside
              the point.

              >> I think that's the one I'd like to run with. Question is, what do the
              >> mechanics look like? When adding a column to a view, I issue a request
              >> something like:
              >>
              >> GET /view?task=add&var=foo
              >No, no, no. Did I mention, no? Do not do an 'update' with a GET.
              >If you have a single view that you add names to over time, then the
              >requests
              >will go to the /same uri/ - so don't put things in the query terms (it is
              >part of the URI).

              So you're of the opinion that, given the design constraints, it would be
              preferable to massage the requests to POSTs using javascript than to issue
              GET requests without relying on javascript?

              >You will want something like:
              >
              >====
              >// request #1
              >POST /view?task=add
              >Content-Type: application/x-www-form-urlencoded
              >
              >var=foo
              >
              >// request #2
              >POST /view?task=add
              >Content-Type: application/x-www-form-urlencoded
              >
              >var=bar
              >
              >=====
              >Notice how the same URI is used twice. That is because the same resource
              is
              >updated twice. Also, notice that the URI that is being used isn't all that
              >great - all users would be appending column names all day long. You need
              to
              >get some qualifying information intothe URI - either the userID, the
              >viewID,
              >or something.

              unless the semantics for the /view URL dictate that, absent a specific
              identifier, the current view for the user is the one being modified. Is
              that legit from a REST pov?

              >> 1. I'm not specifying the view id in the change request. Due to the fact
              >> that I don't want to regenerate the link tree, though, this is largely
              >> unavoidable. I'll just store the user's active view id in their session,
              >> but always redirect them to a URL which they can use absent a session.
              >Tell me again why using a viewId causes the tree to change?

              because I don't know the view id until the user has created one by clicking
              on a link in the tree. It would be undesirable for a couple of other
              reasons as well, actually.

              >> 2. I should be using a POST request when changing the dataset view.
              There
              >> are two reasons why I can't/shouldn't though:
              >>
              >> a. The change request is activated by a link, which can't issue a POST
              >> request unless use javascript links
              >Causing updates on the server via a link is to be avoided. I know it would
              >be really nice to do this, but you need to avoid this anyway.
              >If you really want that kind of silent update, use javascript. If you use
              >checkboxes and send the form on each click, then you'll know when the user
              >de-selects a column. Clicking links won't allow you do de-select columns.

              Once a column is in the active dataset view, there are a number of things
              that can be done to the column in the view frame, including removing it
              from the dataset.

              >> b. You're not supposed to issue a redirect from a POST request
              >There are two different response status codes - one means 'request
              >finished - see this link for results', the other means 'request not
              >processed - try again at this location'.
              >Why aren't you supposed to redirect from a POST?

              I had been given to understand that it was technically not allowed
              according to the HTTP spec, but as it turns out, that's untrue. It _is_
              true that browsers are supposed to verify a redirect request with a user if
              the server issues a 302 or a 307 in response to a POST (although none do,
              it would seem), but HTTP/1.1 added a 303 response which is suitable for
              redirects from POST requests. Doesn't work with NN4, but 302 is an
              acceptable fallback.

              So the upshot seems to be that, given my constraints, the links in the
              explorer should silently turn into POST requests, which send back 303
              redirects to a long-lived URL for the dataset view. I can live with that,
              thanks for the conversation.

              - donald
            • S. Mike Dierken
              ... From: Donald Ball ... but ... Use a hidden frame with a form to send control messages. The onClick for the link calls script that
              Message 6 of 6 , Oct 28, 2002
                ----- Original Message -----
                From: "Donald Ball" <dball@...>

                > >You don't re-load the frame on the left, you use <form
                > target='panel_right'
                > >> to reload the panel on the right.
                >
                > I take your point, if the thing on the left was a form with checkboxes,
                but
                > UI constraints dictate that it's an explorer tree with links. c'e la vie.
                Use a hidden frame with a form to send control messages. The onClick for the
                link calls script that submits a non-visible form in a zero or one pixel
                high frame. This can be used to communicate with the server without bumping
                into UI/presentation issues.


                >
                > So you're of the opinion that, given the design constraints, it would be
                > preferable to massage the requests to POSTs using javascript than to issue
                > GET requests without relying on javascript?
                If doing a GET modifies data on the server, then I would use POST - even if
                that means using script on the client.
                What happens if the user clicks the same link twice?
                How does a user remove the column name from the view?
                What happens when a spider crawls the link?
                What happens when a user bookmarks a link or drags the link to their
                desktop?
                What does the user see when they click link A, then link B, then link A? The
                second time they click link A they won't see the same as the first time they
                clicked on link A - it'll look like they are still on link B.

                >
                > unless the semantics for the /view URL dictate that, absent a specific
                > identifier, the current view for the user is the one being modified. Is
                > that legit from a REST pov?
                No. The resource identifier should identify the same resource for all
                clients.
                If you generate the HTML for the tree control with href= links that have the
                userid in a query term, then that isn't a problem.
                It makes the HTML slightly larger though.

                >
                > >> 1. I'm not specifying the view id in the change request. Due to the
                fact
                > >> that I don't want to regenerate the link tree, though, this is largely
                > >> unavoidable. I'll just store the user's active view id in their
                session,
                > >> but always redirect them to a URL which they can use absent a session.
                > >Tell me again why using a viewId causes the tree to change?
                >
                > because I don't know the view id until the user has created one by
                clicking
                > on a link in the tree. It would be undesirable for a couple of other
                > reasons as well, actually.
                What about always having a view ID for each user - even if it is empty.
                The tree would always have that URI in the href= links.


                > So the upshot seems to be that, given my constraints, the links in the
                > explorer should silently turn into POST requests, which send back 303
                > redirects to a long-lived URL for the dataset view. I can live with that,
                > thanks for the conversation.

                No problem. But this conversation is like many I've had when designing
                systems in the past.
                It's also very indicative of why I believe that REST based resource
                modelling is best suited for 'automation' based Web systems and classical UI
                based systems with existing browsers & server technology just run into too
                many issues that are counter to good REST based design. Essentially I
                believe that usability requirements (projected onto browsers and their use
                of HTTP) conflict with REST principles projected onto HTTP.

                So, it's okay to strive for RESTfulness with HTML and browsers, but don't
                sweat the (sometimes major) conflicts that are going to pop up.
              Your message has been successfully submitted and would be delivered to recipients shortly.