1

I have searched for a long time but didn't find any good resource on how to do this. The api expects one form parameter "user_id"(for now sending its as urlpath not form parameter) and other "file" for the video file. please provide some code sample either using URLSession Task or any library for iOS.

Tried Alamofire:

 Alamofire.upload(multipartFormData: { (multipartFormData) in
        multipartFormData.append(self.fileurl, withName: "file")
    }, to:"http://www.www.www/upload/8590",
       headers: ["Authorization": "Bearer \(SharedPreferences.preferences.getKeyValue(key: Constants.AUTH_TOKEN_key))"] )
    { (result) in
        switch result {
        case .success(let upload, _ , _):

            upload.uploadProgress(closure: { (progress) in

                print("uploding>>>>>>")
            })

            upload.responseJSON { response in
                print(response)
                print("done")

            }

        case .failure(let encodingError):
            print("failed")
            print(encodingError)

        }

This throws 500 from server saying it can't read Header first byte using UTF-8 encoding.

    message = "An Error OccuredInvalid header string: 'utf8' codec can't decode byte 0x9b in position 1: invalid start byte";
result = "Traceback (most recent call last):\n  File \"/var/www/wb_ios/wb_app/views.py\", line 94, in post\n    user_auth = jwt_decode_handler(auth).get('sub')\n  File \"/usr/local/lib/python2.7/dist-packages/rest_framework_jwt/utils.py\", line 104, in jwt_decode_handler\n    unverified_payload = jwt.decode(token, None, False)\n  File \"/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py\", line 70, in decode\n    payload, signing_input, header, signature = self._load(jwt)\n  File \"/usr/local/lib/python2.7/dist-packages/jwt/api_jws.py\", line 177, in _load\n    raise DecodeError('Invalid header string: %s' % e)\nDecodeError: Invalid header string: 'utf8' codec can't decode byte 0x9b in position 1: invalid start byte\n";
status = 500;

}

Additionally, I can use postman to send the video successfully. Using form-data field like shown in images. body Headers

finally I also tried :

let url = NSURL(string: "http://www.www.www/upload/8590")
    let request = NSMutableURLRequest(url: url! as URL)
    let boundary = "------------------------your_boundary"

    request.httpMethod = "POST"
    request.setValue("ios", forHTTPHeaderField: "client")
    request.setValue(Constants.AUTH_KEY, forHTTPHeaderField: Constants.AUTH_KEY_key)
    request.setValue("Bearer " + SharedPreferences.preferences.getKeyValue(key: Constants.AUTH_TOKEN_key)!, forHTTPHeaderField: Constants.AUTH_AUTHORIZATION_key)
    request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
    var movieData: NSData?
    do {
        movieData = try NSData(contentsOfFile: fileurl.path, options: NSData.ReadingOptions.alwaysMapped)
        print(movieData)
    } catch _ {
        movieData = nil
        return
    }

    let body = NSMutableData()

    // change file name whatever you want
    let filename = "upload.mov"
    let mimetype = "video/mov"

    body.append("--\(boundary)\r\n".data(using: String.Encoding.utf8)!)
    body.append("Content-Disposition:form-data; name=\"file\"; filename=\"\(filename)\"\r\n".data(using: String.Encoding.utf8)!)
    body.append("Content-Type: \(mimetype)\r\n\r\n".data(using: String.Encoding.utf8)!)
    body.append(movieData! as Data)
    request.httpBody = body as Data

    let session = URLSession.shared
    let task = session.dataTask(with: request as URLRequest) {
        (data, response, error) in

        guard let _:NSData = data as! NSData, let _:URLResponse = response, error == nil else {
            print("error")
            return
        }

        let dataString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
        print(dataString)
    }

    task.resume()

this also throws error like this:

{"status":500,"message":"An Error Occuredu'file'","result":"Traceback (most recent call last):\n  File \"/var/www/wb_ios/wb_app/views.py\", line 104, in post\n    file_obj = request.data['file']\n  File \"/usr/local/lib/python2.7/dist-packages/django/utils/datastructures.py\", line 85, in __getitem__\n    raise MultiValueDictKeyError(repr(key))\nMultiValueDictKeyError: \"u'file'\"\n"})
NIKHIL MAURYA
  • 267
  • 1
  • 13
  • In the second example(URLSession) server doesn't expect filename in form data, but i don't think I makes any difference. If it couldn't upload the form properly the server can't read the dictionary properly. – NIKHIL MAURYA Dec 18 '17 at 11:57

1 Answers1

0

Swift3.0

Alamofire.upload(multipartFormData: { MultipartFormData in
            for (key, value) in parameter {
                MultipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
            }

// here you can upload only mp4 video
                multipartFormData.append(self.fileurl!, withName: "file", fileName: "video.mp4", mimeType: "video/mp4")
// here you can upload any type of video            
                 multipartFormData.append((self.fileurl.data(using: String.Encoding.utf8, allowLossyConversion: false))!, withName: "File")

            print(MultipartFormData)
        },to:"http://www.www.www/upload/8590",headers: ["Authorization": "Bearer \(SharedPreferences.preferences.getKeyValue(key: Constants.AUTH_TOKEN_key))"]
            )
        { (result) in

            switch result {
            case .success(let upload, _, _):
                upload.uploadProgress(closure: { (progress) in
                    print("Upload Progress: \(progress.fractionCompleted)")
                })
                upload.responseJSON { response in
                    print(response.result.value ?? String())
                    print(response.data ?? NSData())
                    // send to completion block
                    completion(response.data as AnyObject? ?? NSData())
                }

            case .failure(let encodingError):
                print(encodingError)
                errorOccured(encodingError as NSError?)

            }
        }
Vishnu
  • 321
  • 1
  • 2
  • 16
  • in line multipartFormData.append(("VIDEO".data(using: String.Encoding.utf8, allowLossyConversion: false))!, withName: "Type") what is "VIDEO"? – NIKHIL MAURYA Dec 18 '17 at 13:51
  • Add ur url inplace of video , you just use this multipartFormData.append(self.fileurl!, withName: "file", fileName: "video.mp4", mimeType: "video/mp4") and comment that line.Please let me know whether it works or not. – Vishnu Dec 18 '17 at 14:07
  • I am fed up with the build failures once i built the app for ipad. Didn't expect iOS to be more troublesome than android. Will post the results asap. – NIKHIL MAURYA Dec 19 '17 at 06:22
  • It worked with this line. multipartFormData: { (multipartFormData) in multipartFormData.append(self.fileurl, withName: "file") } I don't know why it didn't work with extra parameters like mimetype. Additionally if you get time can you direct me in direction where I would have to upload a bigger file, and best practices for that(like background upload) using alamofire. Thanks you. I will post complete solution when everything is working perfectly. – NIKHIL MAURYA Dec 19 '17 at 10:11
  • Can we do it with URLSession ? – Awais Fayyaz Jun 11 '19 at 11:21
  • @ Awais Fayyaz : sorry for late reply, yes we can do by using URLSession. – Vishnu Aug 26 '19 at 10:34