Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    DELETE action sends data in URL

    I've been struggling with the RestDataSource (SmartClient 10 evaluation version of October 13th, 2014).

    I've defined a BaseRestDataSource that extends RestDataSource and sets it up for a RubyOnRails server.

    Code:
    (function (isc, METADATA) {
        'use strict';
    
        isc.defineClass('BaseRestDataSource', isc.RestDataSource).addProperties({
            dataFormat: 'json',
            operationBindings: [
                { operationType: 'fetch' },
                { operationType: 'add' },
                { operationType: 'update', requestProperties: { httpMethod: 'PUT' } },
    
                // CORRECT BEHAVIOR
                // this line generates the correct url (http://url) and sends the data via the post data
                { operationType: 'remove', requestProperties: { httpMethod: 'POST', params: { '_method': 'DELETE' } } }
    
                // INCORRECT BEHAVIOR
                // this line generates the incorrect url (http://url?id=1&name=something&value=something&authenticity_token=abcdefghiklmnopqrstuvwxz&isc_dataFormat=json)
                { operationType: 'remove', requestProperties: { httpMethod: 'DELETE' } }
            ],
            sendMetaData: false,
            transformRequest: function (request) {
                if (request.operationType === 'fetch') {
                    // check if paging is enabled
                    if ((request.startRow !== undefined) && (request.endRow !== undefined)) {
                        request.params = isc.addProperties({}, request.params, {
                            offset: request.startRow,
                            limit: request.endRow - request.startRow
                        });
                    }
                } else {
                    request.data = isc.addProperties({}, request.data, {
                        authenticity_token: METADATA.authenticity_token
                    });
                }
                return this.Super('transformRequest', arguments);
            }
        });
    }(this.isc, this.METADATA));
    Please check the part for the "remove" operationBinding. Two scenarios are given, the first one works, but is not in line with the other operations and it does a POST request with a special data attribute that Rails understands and causes it to execute the deletion. The second line is what I would like to have, but it generates the wrong URL (in my opinion).

    I've had the dataProtocol attribute set as well on the operation bindings ("getParams" for fetch, "postParams" for the others), but this didn't make a difference so I removed it.

    Am I doing something wrong? Or is it a bug?

    #2
    You need to be specific about what's wrong with the URL in your opinion. It seems to the URL one would expect with your settings.

    Comment


      #3
      I would think the data in the url should be in POST data, not the url itself.

      When it comes to REST in Rails I would really like to have the ID in the url and all other data in the POST data.

      Normally, in Rails one would write:

      Code:
      resources :customers
      And these URLs would be mapped to controller methods:

      GET /customers # index (a list with all customers, optionally limited by query parameters)
      GET /customers/1 # show (one specific customer, in this case with ID 1)
      GET /customers/1/edit # edit (extra, not really necessary in SmartClient)
      GET /customers/new # new (extra, not really necessary in SmartClient)
      POST /customers # create (create a customer, attributes in POST data)
      PUT /customers/1 # update (update a customer, attributes in POST data)
      DELETE /customers/1 # destroy (delete a customer)

      I make it work in SmartClient and Rails by defining a route like this:

      Code:
      resource :customers # thus resources without the s
      I don't think this is correct but it works. The ID is in the query string then.

      Is it possible to instruct SC to have the ID inside the url path? (before he query string)?

      Comment


        #4
        Looking back to my previous reply the first sentence was the most important one, the rest is actually a nice-to-have (or nice-to-know). I did read your Rails wiki and also looked at the gem, but it doesn't use resources in the routes configuration.

        Comment


          #5
          Stepping back a moment, it's a bad idea to use distinct URLs and/or distinct HTTP verbs for different operationTypes because it prevents using a single HTTP request to send multiple kinds of operationTypes, a very common use case. So you'd be much better off using the default RestDataSource protocol rather than attempting these customizations.

          As far as including a request body in a DELETE request, this was a murky area of the HTTP spec and like a lot of other software, SmartClient currently doesn't support this (see background here). If you need support for this mode, we'd suggest Feature Sponsorship.

          Comment


            #6
            So the best mapping would be:

            GET /customers (for collections and individual records, based on extra extra criteria)
            POST /customers (to create records)
            POST /customers?_method=PUT (to update records)
            POST /customers?_method=DELETE (to delete records)

            This will work out-of-the-box with Rails if the route "resource :customers" is used.

            I won't get myself in a discussion about how to best use REST etc., I just like the way Rails maps the URLs to its controller actions, with just one line of code.

            Mixing multiple actions into one request is something I haven't yet looked into, but I'll see if that can be beneficial for me.

            Thanks so far.

            Comment


              #7
              About the parameters in the query string. I know there's a limitation in the length of it. Just sending the ID for a delete could work but is less "secure" of course than sending the whole record. I guess sending the whole record is a way of making sure you're deleting the "instance" as you requested before.

              Comment


                #8
                No, the best mapping is the default for RestDataSource - one URL only.

                This isn't really an area where you have to think hard about REST design. If you want to handle common scenarios like Mass Update or multi-row drag and drop, then there needs to be a single URL and a single POST'd body of data or there cannot be a server-side transaction. There isn't really room for a discussion of tradeoffs once this is recognized. Multiple URLs and multiple HTTP verbs can handle certain very simple UIs and certain automated systems, but can't handle advanced UIs.

                And yes, with the default RestDataSource protocol, the previous values of the record can be sent to the server to enable detection of concurrent edits (sometimes called "long transactions").

                Comment

                Working...
                X