Search code examples
iosalamofirensurlsessionnsurlsessionuploadtaskurlsessiontask

Swift3 video file upload along with one more form parameter(can be skipped from form and sent as url path)


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"})

Solution

  • 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?)
    
                }
            }