Search code examples
backbone.jsdrupal-7drupal-services

Drupal services module JSON response fetched: Backbone.js model attributes turn into string


I've set up web services using Drupal's services module. It outputs JSON for me which I am requesting through a Backbone.js front-end application.

I'm having issues with this set-up. If I request data through Backbone.js' fetch method of a model, the model's attributes are all typed as string after fetching, while there are some attributes that should be e.g. integer.

For example:

  • I have enabled the user resource, which is standard available in the Drupal services module
  • I can request a user, e.g.:

    http://mydevmachine/services/user/8
    

...which results in the following response (slimmed down version from the real response):

    {"uid":"8","name":"itsme","mail":"[email protected]"}
  • What I see in the response from the web service above, all values are quoted, however uid is really not a string but an integer in the database.
  • If I fetch the same user in my Backbone.js model, by setting the uid field of my model to 8 (integer), then call the fetch method. After fetching the uid field is typed as 'string'.

I assume the above leads to my model ending up with a uid attribute of not integer, but string. It also happens with all other web service resources I have created, using my own entities.

I need correct typing of attributes in my model due to sorting issues using Backbone's collection sorting. I.e. sorting a collection of models using a field of type 'integer' leads to different sorting results when sorting the field with the same values although stored as a string.

I'm not sure exactly where to look:

  • Is the JSON format output by the Drupal services module according to standards?
  • Is the JSON output format configurable or overridable in the Drupal services module?
  • Is it perhaps possible to keep the type of a model's attribute after a fetch in Backbone.js?
  • Should I provide a specific implementation for Backbone's collection comparator function, which handles this situation (seems hackey)?
  • Should I introduce other solutions, e.g. like posted here: How can I enforce attribute types in a Backbone model? (feels too heavy).

Thanks for any help.


Solution

  • So I finally managed to crack this issue and I found my solution here: How to get numeric types from MySQL using PDO?. I thought I'd document the solution.

    Drupal 7 uses PDO. Results fetched using PDO, using Drupal's default PDO settings result in stringified values.

    In Drupal's includes/database.inc file you will find this around lines 40-50:

    $connection_options['pdo'] += array(
      // So we don't have to mess around with cursors and unbuffered queries by default.
      PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => TRUE,
      // Because MySQL's prepared statements skip the query cache, because it's dumb.
      PDO::ATTR_EMULATE_PREPARES => TRUE,
    );
    

    The statement here that MySQL's prepared statements skip the query cache is not entirely true, as can be found here: http://dev.mysql.com/doc/refman/5.1/en/query-cache-operation.html. It states MySQL > 5.1.17 prepared statements use the query cache under certain conditions.

    I used the info from the other stack overflow question/answers to override the PDO settings for the database connection in Drupal's sites/default/settings.php (please note I only did this for the database I was querying, which is different than Drupal's own database):

    'database_name' =>
      array (
        'default' => 
        array (
          'database' => 'database_name',
          'username' => 'user_name',
          'password' => 'user_pass',
          'host' => 'localhost',
          'port' => '',
          'driver' => 'mysql',
          'prefix' => '',
          'pdo' => array(
            PDO::ATTR_STRINGIFY_FETCHES => FALSE,
            PDO::ATTR_EMULATE_PREPARES => FALSE
          ),
        ),
      ),
    

    This resulted in integers being integers. Floats/decimals are incorrectly returned by PDO still, but this is different issue. At least my problems are solved now.