title: Drupal REST server, multipart/form-data image upload issue from iOS App using ASIHTTPRequest
body: <p>I am developing an iOS app that uploads an image and text to a Drupal REST server. The image and text are to be stored in a MySQL table.</p>
  
  <p>I am using ASIHTTPRequest to to do a POST to my REST server.
  On the server side, I followed this example for setting up a Drupal REST server: <a href="http://drupal.org/node/1246470" rel="nofollow">http://drupal.org/node/1246470</a></p>
  
  <p>The issue I am having is I do not know how to to reference the image on the REST server. Whenever I try to send the information, I keep getting the error <strong>"HTTP/1.0 406 Not Acceptable: Missing issue attribute image"</strong>. Can anyone point out what I'm doing wrong or what I am missing? </p>
  
  <p>My iOS version is 5.1.
  My Drupal version is 7.8.</p>
  
  <p>My iOS code is the following:</p>
  
  <pre><code> NSString* timestamp = [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]];
  
  //Add the timestamp to the filename
  NSMutableString* filename = [NSMutableString stringWithString:@"issue-"];
  
  [filename appendString: timestamp];
  [filename appendString: @".png"];
  
  //Convert the image into an NSData object
  NSData* imageData = UIImagePNGRepresentation(imageView.image);
  
  NSURL *url = [NSURL URLWithString: SERVICE_URL];
  
  ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL: url];
  
  [request setPostValue: emailAddress forKey:@"email"];
  [request setPostValue: details forKey:@"details"];
  [request setData: imageData withFileName: filename andContentType: @"image/png" forKey: @"image"];
  
  [request setPostFormat:ASIMultipartFormDataPostFormat];
  
  [request setRequestMethod:@"POST"];
  
  [request startSynchronous];
  </code></pre>
  
  <p>As for the server side, here is where I setup the hook_services_resources:</p>
  
  <pre><code>/**
  * Implementation of hook_services_services().
  */
  function issue_services_resources() {
    return array(
      'issue' =&gt; array(
        'retrieve' =&gt; array(
          'help' =&gt; 'Retrieves an issue',
          'file' =&gt; array('file' =&gt; 'inc', 'module' =&gt; 'issue'),
          'callback' =&gt; '_issue_retrieve',
          'access callback' =&gt; '_issue_access',
          'access arguments' =&gt; array('view'),
          'access arguments append' =&gt; TRUE,
          'args' =&gt; array(
            array(
              'name' =&gt; 'id',
              'type' =&gt; 'int',
              'description' =&gt; 'The id of the issue to get',
              'source' =&gt; array('path' =&gt; '0'),
              'optional' =&gt; FALSE,
            ),
          ),
        ),
        'create' =&gt; array(
          'help' =&gt; 'Creates an issue',
          'file' =&gt; array('file' =&gt; 'inc', 'module' =&gt; 'issue'),
          'callback' =&gt; '_issue_create',
          'access arguments' =&gt; array('issue service create'),
          'access arguments append' =&gt; FALSE,
          'args' =&gt; array(
            array(
              'name' =&gt; 'data',
              'type' =&gt; 'struct',
              'description' =&gt; 'The issue object',
              'source' =&gt; 'data',
              'optional' =&gt; FALSE,
            ),
          ),
        ),
        'update' =&gt; array(
          'help' =&gt; 'Updates an issue',
          'file' =&gt; array('file' =&gt; 'inc', 'module' =&gt; 'issue'),
          'callback' =&gt; '_issue_update',
          'access callback' =&gt; '_issue_access',
          'access arguments' =&gt; array('update'),
          'access arguments append' =&gt; TRUE,
          'args' =&gt; array(
            array(
              'name' =&gt; 'id',
              'type' =&gt; 'int',
              'description' =&gt; 'The id of the node to update',
              'source' =&gt; array('path' =&gt; '0'),
              'optional' =&gt; FALSE,
            ),
            array(
              'name' =&gt; 'data',
              'type' =&gt; 'struct',
              'description' =&gt; 'The issue data object',
              'source' =&gt; 'data',
              'optional' =&gt; FALSE,
            ),
          ),
        ),
        'delete' =&gt; array(
          'help' =&gt; 'Deletes an issue',
          'file' =&gt; array('file' =&gt; 'inc', 'module' =&gt; 'issue'),
          'callback' =&gt; '_issue_delete',
          'access callback' =&gt; '_issue_access',
          'access arguments' =&gt; array('delete'),
          'access arguments append' =&gt; TRUE,
          'args' =&gt; array(
            array(
              'name' =&gt; 'nid',
              'type' =&gt; 'int',
              'description' =&gt; 'The id of the issue to delete',
              'source' =&gt; array('path' =&gt; '0'),
              'optional' =&gt; FALSE,
            ),
          ),
        ),
        'index' =&gt; array(
          'help' =&gt; 'Retrieves a listing of issues',
          'file' =&gt; array('file' =&gt; 'inc', 'module' =&gt; 'issue'),
          'callback' =&gt; '_issue_index',
          'access callback' =&gt; 'user_access',
          'access arguments' =&gt; array('access content'),
          'access arguments append' =&gt; FALSE,
          'args' =&gt; array(
            array(
              'name' =&gt; 'page',
              'type' =&gt; 'int',
              'description' =&gt; '',
              'source' =&gt; array(
                'params' =&gt; 'page',
              ),
              'optional' =&gt; TRUE,
              'default value' =&gt; 0,
            ),
            array(
             'name' =&gt; 'parameters',
             'type' =&gt; 'array',
             'description' =&gt; '',
             'source' =&gt; 'param',
             'optional' =&gt; TRUE,
             'default value' =&gt; array(),
            ),
          ),
        ),
      ),
    );
  }
  </code></pre>
  
  <p>I have a hunch it may be the arguments for the "create". From what I have, I only have the "data" or type "struct". It looks I may need to have an additional argument for the image? If so, what would it be?</p>
  
  <p>and here is where I do the check and setting of the 406 error:</p>
  
  <pre><code>function _issue_create($data) {
  
  if (isset($data) &amp;&amp;  is_array($data)) $data=(object) $data; 
  
    unset($data-&gt;id);
    $data-&gt;created = time();
    $data-&gt;modified = time();
  
    if (!isset($data-&gt;email)) {
      return services_error('Missing issue attribute email address', 406);
    }
  
    if (!isset($data-&gt;details)) {
      return services_error('Missing issue attribute details', 406);
    }
  
    if (!isset($data-&gt;image)) {
      return services_error('Missing issue attribute image', 406);
    }
  
    issue_write_issue($data);
  
    return (object)array(
      'id' =&gt; $data-&gt;id,
      'uri' =&gt; services_resource_uri(array('issue', $data-&gt;id)),
    );
  }
  </code></pre>
  
  <p>The issue is where I do the check:</p>
  
  <pre><code>if (!isset($data-&gt;image))
  </code></pre>
  
  <p>It seems this is not the correct manner for checking whether the image data is present... What is the correct way to reference the image data?</p>
  
  <p>Thank you for your help in advance.</p>