2

I have a function that is supposed to generate a multipart/form-data body for post requests so that I can send an image along with form parameters.

class HttpService {

    // https://stackoverflow.com/questions/26162616/upload-image-with-parameters-in-swift
    static func createMultipartBody(parameters: [String: String], boundary: String, data: Data, mimeType: String, filename: String) throws -> Data {

        var body = Data()

        for (key, value) in parameters {
            body.append("--\(boundary)\r\n")
            body.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
            body.append("\(value)\r\n")
        }

        body.append("--\(boundary)\r\n")
        body.append("Content-Disposition: form-data; name=\"file\"; filename=\"\(filename)\"\r\n")
        body.append("Content-Type: \(mimeType)\r\n\r\n")
        body.append(data)
        body.append("\r\n")
        body.append("--\(boundary)--\r\n")

        return body
    }

}

extension Data {
    mutating func append(_ string: String) {
        if let data = string.data(using: .utf8) {
            append(data)
        }
    }
}

I use this function like this:

let urlString = baseUrl + "/api/user"
let url = URL(string: urlString)
var urlRequest = URLRequest(url: url!)
urlRequest.httpMethod = "POST"

let boundary = "Boundary-\(UUID().uuidString)"
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

let parameters: [String: String] = ["email": email, "username": username, "password": password]

do {
    let multipartBody = try HttpService.createMultipartBody(parameters: parameters, boundary: boundary, data: imageData, mimeType: "image/jpg", filename: "photo.jpg")
    urlRequest.httpBody = multipartBody

    print(multipartBody)
    print(String(data: multipartBody, encoding: String.Encoding.utf8))
} catch let error {
    print(error)
    return
}

This outputs:

51551 bytes
nil

So it looks like the data is being generated, but I can't output it as string to see how the format looks like.

Alex
  • 5,671
  • 9
  • 41
  • 81

1 Answers1

4

What's printing nil is not the data; it's this:

print(String(data: multipartBody, encoding: String.Encoding.utf8))

The data isn't nil; the String is. The problem is that you are pretending this is thing is a UTF8-encoded string. It isn't! It's a bunch of random data bytes. Okay, they're not random, but they are nothing whatever like a UTF8 string. So when you try to convert it to a UTF-8 string, you get nil.

If what you wanted was to see the bytes, then look at the bytes. They are a sequence of small integers. (For example, you might print Array(multipartBody) or iterate over the bytes and print each one.) Don't try to treat it as something that it isn't.

(Though, to be honest, I do not at all see what good you think looking at the bytes will do you either; you likely won't understand them in any case.)

matt
  • 515,959
  • 87
  • 875
  • 1,141