POST with parameters AND content

POST with parameters AND content

GregPGregP Posts: 487Questions: 8Answers: 0
edited March 2013 in DataTables 1.9
Working on a RESTful service that wants to ingest a set of parameters in the form of JSON. Imagining I don't use DataTables at all, I simply stringify an object and send it as the POST's content. The server reads in the content and acts accordingly.

However, with DataTables what I'm accustomed to is simply POSTing a set of parameters in the usual way, in the header. If I have additional parameters for custom processing, I use fnServerParams to push my new parameters in.

Unfortunately, what I'm accustomed to isn't what the back end development team wants. What they want is a division of concerns:

- the usual DataTables parameters in the header
- the custom information as the request's content.

DataTables is so deep that the function might already exist for specifying content, but I didn't see it. I wasn't really interested in rewriting the entire Ajax call (I like letting DataTables do its job in a default way wherever possible!), so an additional parameter would be ideal.

sAjaxContent or something. ;)

Thanks!

Replies

  • allanallan Posts: 63,180Questions: 1Answers: 10,411 Site admin
    Hi Greg,

    I'm not sure I 100% understand I'm afraid. The 'HTTP parameters' sent by POST are the POST request's body. Parameters are not sent in the header (HTTP headers). From Wikipedia:

    > The POST request method is designed to request that a web server accepts the data enclosed in the request message's body for storage

    Here is an example I've just captured with Wireshark in my local examples:

    [code]
    POST /datatables/DataTables/examples/server_side/scripts/post.php HTTP/1.1
    X-Requested-With: XMLHttpRequest
    User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-gb) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    Accept: application/json, text/javascript, */*; q=0.01
    Accept-Language: en-gb
    Accept-Encoding: gzip, deflate
    Content-Length: 507
    Connection: keep-alive

    sEcho=2&iColumns=5&sColumns=&iDisplayStart=0&iDisplayLength=10&mDataProp_0=0&mDataProp_1=1&mDataProp_2=2&mDataProp_3=3&mDataProp_4=4&sSearch=&bRegex=false&sSearch_0=&bRegex_0=false&bSearchable_0=true&sSearch_1=&bRegex_1=false&bSearchable_1=true&sSearch_2=&bRegex_2=false&bSearchable_2=true&sSearch_3=&bRegex_3=false&bSearchable_3=true&sSearch_4=&bRegex_4=false&bSearchable_4=true&iSortCol_0=1&sSortDir_0=asc&iSortingCols=1&bSortable_0=true&bSortable_1=true&bSortable_2=true&bSortable_3=true&bSortable_4=true
    [/code]

    You can see here that the request body has the POST parameters in it, and it is these that are decoded by the server to be the POST variables.

    So I'm afraid I don't really understand the different you were getting at for the header and the body. It might be my limited understanding of HTTP though...

    Allan
  • GregPGregP Posts: 487Questions: 8Answers: 0
    More like mine. I thought I understood the problem as described by the back-end developer, but now it appears not. I'll get back to you.. thanks for the reply!
  • GregPGregP Posts: 487Questions: 8Answers: 0
    edited March 2013
    While I'm waiting to hear back, it occurs to me that I may have misunderstood him. So here's a follow-up question:

    Is there a way to change it so that instead of sending a serialized query string, we just send the parameters as stringified JSON? Then it would include both the DT parameters and my custom ones in a format that doesn't need to be more complex than:

    [code]
    {
    "sEcho" : 2,
    "iColumns" : 5,
    "etc" : "etc",
    "myCustom" : "someValue"
    }
    [/code]

    or even better (though not necessary by any stretch):

    [code]
    {
    "dataTables" : {
    "sEcho" : 2,
    "iColumns" : 5,
    "etc" : "etc"
    },
    "myCustom" : {
    "someKey" : "someValue"
    }
    }
    [/code]

    I know in a standard $.ajax() jQuery call (which I believe is really all that DT does in the end!), you can set processData to false (it is true by default); but not sure how to "intercept" this setting using DT as the Ajax abstraction layer.
  • allanallan Posts: 63,180Questions: 1Answers: 10,411 Site admin
    > Is there a way to change it so that instead of sending a serialized query string, we just send the parameters as stringified JSON?

    Sort of :-)

    You need to override fnServerData and just pass a string to jQuery's Ajax `data` parameter - something like: `data: JSON.stringify( aoData )` . When jQuery seems a plain string passed in as the data for the Ajax request, it simply uses that as the POST body. If it is passed an array of name / value pairs or an object, it will parameterise it for the body before sending it.

    Allan
  • GregPGregP Posts: 487Questions: 8Answers: 0
    Thanks, Allan. I'll see if that fits the bill!
  • GregPGregP Posts: 487Questions: 8Answers: 0
    Alrighty... so...

    We're going to send the search data as some stringified JSON:

    [code]
    data: someJSON, // already stringified
    [/code]

    But we're going to pass the DataTables parameters through the query string.

    Normally you would use GET and then the "data" attribute would be appended as a query string. What I need to do is use POST, which means modifying the url parameter:

    [code]
    url: urlBase + queryString,
    data: someJSON, // already stringified
    [/code]

    where queryString is the set of serialized dataTables parameters (normally aoData).

    Is there a way I can retrieve these parameters in order to append them as a string to the URL? I've done a proof of concept in which I just set "queryString = ?foo=bar&baz=mati"; however, I'm not sure how to get my parameters in order to send them in the URL.

    I'm sure there's a getter somewhere, but it's a deep API! I can't find it!
  • GregPGregP Posts: 487Questions: 8Answers: 0
    edited March 2013
    so within fnServerData, I have access to aoData and should theoretically be able to use it from there. Problem is, it's an object. Not sure if the serialization of that object is a DataTables utility or just a built-in jQuery function. I know about jQuery .serialize(), but the aoData object isn't a jQuery object and therefore doesn't have that method. Wrapping it up in jQuery doesn't do the trick either.

    I know how to write a serialization function, but I'd rather use anything that's already available. That failing, I'll write the function.

    It's on the tip of my brain...
  • GregPGregP Posts: 487Questions: 8Answers: 0
    Alright, back the other direction then. I'd still like to know if I can get a serialized aoData, but in the meantime we're going with your earlier suggestion of just added them into the object with fnServerParams and stringifying it. :)
  • allanallan Posts: 63,180Questions: 1Answers: 10,411 Site admin
    Sounds like you want $.param ( http://api.jquery.com/jQuery.param/ ). Something like:

    [code]
    "fnServerData": function ( sSource, aoData, fnCallback, oSettings ) {
    oSettings.jqXHR = $.ajax( {
    "dataType": 'json',
    "type": "POST",
    "url": sSource+'?'+$.param(aoData),
    "data": someJSON,
    "success": fnCallback
    } );
    }
    [/code]

    Allan
  • GregPGregP Posts: 487Questions: 8Answers: 0
    edited March 2013
    Yes, that would do the trick, Allan! Thanks for the reply. We ended up going a more convoluted route, but one that works better for the mental headspace of devs who like things to be RESTful and use nice tidy JSON exchanges.

    For future readers of the thread, it goes something like this:

    1. I have a search form, and I need the contents to be sent to the server during the request for data. In other words, during the dataTables initialization and then whenever a draw is requested.

    a) I listen for clicks on a "Search" button.
    b) I execute $('#form').serializeArray(); on it, storing the results in the variable "form"
    b) I iterate through the form, creating a new object that's available in the application namespace (fcSearch.formData):

    [code]
    for (var i=0, len=form.length; i < len; i++) {
    if (form[i].value != "" && form[i].value != "NaN") {
    var value = form[i].value;
    if (value.match(/^\d+$/)) {
    value = +value;
    }
    fcSearch.formData[form[i].name] = value;
    }
    }
    [/code]

    Quite simply, it only pushes into the new object if there's a reason to (the RESTful service just ignores non-present key-value pairs). Additionally, it runs a regex to convert "numbers stored as strings" into actual numbers. This converts something like:

    [code]
    [
    {
    name: "something",
    value: "foo"
    },
    {
    name: "somethingElse",
    value: "123"
    }
    ]
    [/code]

    into

    [code]
    {
    "something" : "foo",
    "somethingElse" : 123
    }
    [/code]

    2. Inside the fnServerData parameter, I immediately send the aoData object off to convert into a similar format. I send along a string to use as a key for an object within the object (you'll see the example in a second for clarification!) The results are stored in a new object that will also contain the formData.

    [code]
    "fnServerData": function ( sSource, aoData, fnCallback ) {
    var newObj = someConvertFunction(aoData, "dataTableParams");
    //etc
    [/code]

    3. I add the formData object to the new object ( newObj["searchCriteria"] = {} ), which results in a JavaScript object that looks like:

    [code]
    {
    "dataTableParams": {
    "sEcho": 2,
    "iColumns": 10,
    "etc" : "etc"
    },
    "searchCriteria": {
    "searchId": "Placeholder",
    "resultSet": "sessionSearch",
    "etc" : "etc"
    }
    }
    [/code]

    4. Instead of passing aoData into the "data" attribute, I now pass a stringified version of the object. So within fnServerData, I have:

    [code]
    data: JSON.stringify(newObj);
    [/code]
This discussion has been closed.