title: Uploading an image and parameters with multipart/form-data in Swift
body: <p><strong>[WARNING]</strong><br>
  As I am seeing that this question is getting noticed more than it should, 
  I want to tell you not to use any of the following code.<br>
  At the time I asked the question, Swift had less than a year, was moving fast, most of the libraries were not Swift-friendly and unstable. 
  I strongly recommend you to try using <a href="https://github.com/Alamofire/Alamofire" rel="nofollow noreferrer">Alamofire</a> or another library for that kind of task. But don't do it yourself.<br>
  <strong>[/WARNING]</strong>  </p>
  
  <p>I want to upload an image to a Drupal endpoint.</p>
  
  <p>The problem I have is that I receive an HTTP 200 OK response with text/html content type. In the HTML response, there is a clear message that the node has been correctly created. But on the server side the image is not associated with the node.</p>
  
  <p>Also I am not expecting text/html but application/json as I specify it in the Accept header.</p>
  
  <p>It already works in the Android app using Android Rest Template. Here is the code for reference: </p>
  
  <pre><code>String url = getUrl("node/{info_id}/attach_file");
  
  HttpHeaders headers = new HttpHeaders();
  headers.setContentType(MediaType.MULTIPART_FORM_DATA);
  
  if (user.isLoggedIn()) {
      headers.add(user.getSessionName(), user.getSessionId());
      headers.add("X-CSRF-Token", user.getToken());
      headers.add("Cookie", user.getSessionName() + "=" + user.getSessionId());
  }
  
  MultiValueMap&lt;String, Object&gt; parts = new LinkedMultiValueMap&lt;&gt;();
  
  parts.add("files[field_mobileinfo_image]",
          new FileSystemResource(info.getImageUri()));
  parts.add("field_name", "field_mobileinfo_image");
  
  HttpEntity&lt;MultiValueMap&lt;String, Object&gt;&gt; request = new HttpEntity&lt;&gt;(parts, headers);
  return getRestTemplate().exchange(url, HttpMethod.POST, request, Void.class, info.getId()).getBody();
  </code></pre>
  
  <p>I know I don't check the response in Android (<code>Void.class</code>) but everything works fine and the image is attached to the node on the server side.</p>
  
  <p>Now on iOS in Swift I tried multiple things. </p>
  
  <p><strong>With AFNetworking:</strong> </p>
  
  <pre><code>func upload(mobileInfo: MobileInfo) {
      let user = userService.load()
      let url = Config.buildUrl("")
  
      let manager = AFHTTPRequestOperationManager(baseURL: NSURL(string:url)!)
      let serializer = AFHTTPRequestSerializer()
      serializer.setValue(user.sessionId, forHTTPHeaderField: user.sessionName)
      serializer.setValue(user.token, forHTTPHeaderField: "X-CSRF-Token")
      serializer.setValue("\(user.sessionName)=\(user.sessionId)", forHTTPHeaderField: "Cookie")
      manager.requestSerializer = serializer
  
      manager.responseSerializer.acceptableContentTypes.removeAll(keepCapacity: false)
      manager.responseSerializer.acceptableContentTypes.insert("application/json")
  
      let imageData = UIImageJPEGRepresentation(mobileInfo.image, 0.3)    
      manager.POST("/node/\(mobileInfo.id)/attach_file", parameters: nil, constructingBodyWithBlock: { (formData) -&gt; Void in
          formData.appendPartWithFileData(
              imageData,
              name: "files[field_mobileinfo_image]",
              fileName: "field_mobileinfo_image",
              mimeType: "image/jpeg")
          formData.appendPartWithFormData("field_mobileinfo_image".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true), name: "field_name")
      },
      success: { (operation, data) -&gt; Void in
          println(data)
      }) { (operation, error) -&gt; Void in
          println(error)
      }
  }
  </code></pre>
  
  <p><strong>Manually</strong> with information grabbed from other stackoverflow questions: </p>
  
  <pre><code>func upload2(mobileInfo: MobileInfo) {
      let user = userService.load()
      let imageData = UIImageJPEGRepresentation(mobileInfo.image, 0.3)
      let url = NSURL(string:Config.buildUrl("/node/\(mobileInfo.id)/attach_file"))!
      println(url)
      var request = NSMutableURLRequest(URL: url)
      var session = NSURLSession.sharedSession()
      request.HTTPMethod = "POST"
      var boundary = "---------------------------14737809831466499882746641449"
      var contentType = "multipart/form-data; boundary=\(boundary)"
      println(contentType)
      request.addValue(contentType, forHTTPHeaderField: "Content-Type")
      request.addValue("application/json", forHTTPHeaderField: "Accept")
      request.addValue("\(user.sessionName)=\(user.sessionId)", forHTTPHeaderField: "Cookie")
      request.addValue(user.sessionId, forHTTPHeaderField: user.sessionName)
      request.addValue(user.token, forHTTPHeaderField: "X-CSRF-Token")
  
      println(request.allHTTPHeaderFields)
  
      var body = NSMutableData()
  
      body.appendData("\r\n--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      body.appendData("Content-Disposition: form-data; name=\"field_name\"\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      body.appendData("field_mobileinfo_image".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!)
  
      body.appendData("\r\n--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      body.appendData("Content-Disposition: form-data; name=\"files[field_mobileinfo_image]\"; filename=\"img.jpg\"\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      body.appendData("Content-Type: application/octet-stream\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      body.appendData(imageData)
      body.appendData("\r\n--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
  
  
      var returnData = NSURLConnection.sendSynchronousRequest(request, returningResponse: nil, error: nil)
  
      var returnString = NSString(data: returnData!, encoding: NSUTF8StringEncoding)
  
      println("returnString \(returnString)")
  }
  </code></pre>
  
  <p><strong>With SRWebClient:</strong>  </p>
  
  <pre><code>func upload3(mobileInfo: MobileInfo) {
      let user = userService.load()
      let imageData:NSData = NSData(data: UIImageJPEGRepresentation(mobileInfo.image, 0.3))
      SRWebClient.POST("http://master.test.lesfrontaliers.lu/node/\(mobileInfo.id)/attach_file")
          .headers(["Accept": "application/json",
              user.sessionName: user.sessionId,
              "X-CSRF-Token": user.token,
              "Cookie": "\(user.sessionName)=\(user.sessionId)"])
          .data(imageData, fieldName:"files[field_mobileinfo_image]", data:["field_name":"field_mobileinfo_image"])
          .send({ (response: AnyObject!, status: Int) -&gt; Void in
              println(status)
              println(response)
          },failure:{(error:NSError!) -&gt; Void in
              println(error)
          })
  }
  </code></pre>
  
  <p>Please save me! ;-) 
  I tried so many things to make it work that I can't see anymore if I am doing something wrong. It seems ok for me. The only difference I can see is that I am not storing the image on the filesystem but directly sending the binary data which is the same thing in the end.</p>
  
  <p>Here is an image of the request created in Postman (working and receiving json)</p>
  
  <p><img src="https://i.stack.imgur.com/8M48P.png" alt="Postman"></p>
  
  <p><strong><em>[EDIT] If it can help someone here is the correct code of the wrong part of the above manual request:</em></strong> </p>
  
  <pre><code>var body = NSMutableData()
  
  body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
  body.appendData("Content-Disposition: form-data; name=\"field_name\"\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
  body.appendData("field_mobileinfo_image\r\n".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!)
  
  body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
  body.appendData("Content-Disposition: form-data; name=\"files[field_mobileinfo_image]\"; filename=\"img.jpg\"\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
  body.appendData("Content-Type: image/jpeg\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
  body.appendData(imageData)
  body.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
  
  body.appendData("--\(boundary)--\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
  
  request.HTTPBody = body
  </code></pre>