2

I can't find any example of handling file upload, especially how to save into some specific folder.

Here is the code, addVideo is a HTTP POST multipart/form-data:

videos.post("addVideo") { req in

    // need to save req.multipart["video"] into /data/videos/

    return try JSON(node: ["status": 0, "message": "success"])
}
Valerii Lider
  • 1,774
  • 16
  • 21
  • You may want to check this out: http://stackoverflow.com/questions/38988329/uploading-files-using-vapor – Chris Nov 15 '16 at 00:41

3 Answers3

3

example look like this:

vapor 2.0 server code:

let d =drop.grouped("file");
d.post("updateFile") { req in
  let data = Data.init(bytes: (req.data["image"]?.bytes)!)
  let picName = req.data["name"]?.string ?? String();
  try Data(data).write(to: URL(fileURLWithPath: "/Users/xx/Desktop/\(picName).jpg"))
  return try JSON(node: ["status": 0, "message": "success"])
}

Client code:

Alamofire.upload(multipartFormData: { (multipartFormData) in

        multipartFormData.append(imageData!, withName: "image", fileName: "pic", mimeType:"image/jpg")

        multipartFormData.append("picName".data(using: .utf8)!, withName: "name")

    }, to: "http://0.0.0.0:8083/file/updateFile") { (encodingResult) in

        switch encodingResult {
        case .success(let upload, _, _):
            upload.responseJSON { response in
                debugPrint(response)
            }
        case .failure(let encodingError):
            print(encodingError)
        }
}
Nemo Agoni
  • 83
  • 9
  • 2
    thanks for this example, but we figured out already how this works. Anyway, my main concern here is that you creating Data instance from file's bytes. This means that you load file bytes into memory. Imagine that you uploaded video - so you constructing Data from received bytes, loading in memory, which takes time and ram. What I'm looking is some way to just save into file without loading into memory, like just writing to handle. – Valerii Lider Aug 15 '17 at 12:06
  • Did you find a better solution? @ValeriiLider – Emre Önder Nov 01 '21 at 15:17
2

From your Multipart.File get the Bytes and convert to Data.

guard let file = request.multipart?["video"]?.file else {
  return "Not found"
}
try Data(file.data).write(to: URL(fileURLWithPath: "/data/videos/FILENAME"))

You can get FILENAME from the File object or make your own.

tobygriffin
  • 5,339
  • 4
  • 36
  • 61
  • Thanks, it works, but: is there a way to save bytes to file without creating Data object? For big files it takes time till it performs, but I only need to save to file system – Valerii Lider Nov 16 '16 at 18:23
  • do you know who to get the absolute path (with the host) of the file? I get something like file:///path/to/folder which is okay but I want to have https://myapp.herokuapp.com/images/image.jpg – Marcos Griselli Feb 28 '17 at 12:58
  • For me neither `let d = Data(req.data as? Primitive)` nor `let d = Data(req.body.bytes)` works. Why? – János Sep 29 '17 at 13:46
1

While other answers explained how to save data as file, the following code shows how to save data as database blob:

guard 
    let name = request.data["filename"]?.string, 
    let blob = request.data["file"]?.bytes
else {
    throw Abort(.badRequest, reason: "Fields 'filename' and/or 'file' is invalid")
}
let user = try request.user()
let image = try Image(filename: name, user: user, file: blob)
try image.save()
superarts.org
  • 7,009
  • 1
  • 58
  • 44