Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for multi-part form data #7

Open
bcapps opened this issue Jun 30, 2022 · 0 comments
Open

Add support for multi-part form data #7

bcapps opened this issue Jun 30, 2022 · 0 comments

Comments

@bcapps
Copy link
Member

bcapps commented Jun 30, 2022

Engineering Task

Add a convenience for multi-part form data in an HTTP body, the bane of many iOS developers' existence when integrating with APIs. Here's an example of how it could look:

/// An individual item in a multipart/form-data request.
struct NetworkFormData {
    /// The key associated with this item. For example, if you see `key=value` in sample documentation, this represents the left side of that assignment.
    let key: String
    
    /// The actual data to encode as the value.
    let data: Data
    
    /// The MIME type of the data.
    let mimeType: String
    
    /// The name of the file being uploaded. Will be excluded if `nil`
    let filename: String?
}

extension NetworkRequest {
    
    /// Returns HTTP body data formatted for a multipart/form-data request.
    /// - Parameters:
    ///   - boundary: The boundary to use between items and at the end of the body.
    ///   - items: The items to list in the body.
    /// - Returns: HTTP body data formatted for a multipart/form-data request.
    func multipartFormDataHTTPBody(boundary: String, for items: [NetworkFormData]) -> Data? {
        var data = Data()
        
        for item in items {
            let filenameString = item.filename.map { "; filename=\"\($0)\"" } ?? ""
            
            data.append("--\(boundary)\r\n")
            data.append("Content-Disposition: form-data; name=\"\(item.key)\"\(filenameString)\r\n")
            data.append("Content-Type: \(item.mimeType)\r\n")
            data.append("\r\n")
            data.append(item.data)
            data.append("\r\n")
        }
        
        data.append("--\(boundary)--")
        return data
    }
}

private extension Data {
    mutating func append(_ string: String) {
        guard let data = string.data(using: .utf8) else {
            assertionFailure("String could not be converted to UTF-8 data.")
            return
        }
        
        append(data)
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant