Swift MultipartFormData from [String: Any] in swift using Alamofire

import Alamofire

extension MultipartFormData {
    func importData(with parameter: Parameters, parentKey: String? = nil) {
        for (key, value) in parameter {
            let newKey = genChildKeyInArray(childKey: key, parentKey: parentKey) ?? key
            log(type: .error, newKey)
            importValue(value, withName: newKey)
        }
    }

    private func importValue(_ value: Any, withName name: String) {
        if let url = value as? URL, url.isFileURL {
            append(url,
                   withName: name,
                   fileName: url.lastPathComponent,
                   mimeType: url.mimeType())
        } else if let stringValue = value as? String, let url = URL(string: stringValue), url.isFileURL {
            append(url,
                   withName: name,
                   fileName: url.lastPathComponent,
                   mimeType: url.mimeType())
        } else if let array = value as? NSArray {
            importArray(array, withParentKey: name)
        } else if let stringValue = value as? String, let data = stringValue.data(using: .utf8) {
            append(data, withName: name)
        } else if let intValue = value as? Int, let data = "\(intValue)".data(using: .utf8) {
            append(data, withName: name)
        } else if let floatValue = value as? Float, let data = "\(floatValue)".data(using: .utf8) {
            append(data, withName: name)
        }
    }

    private func importArray(_ array: NSArray, withParentKey parentKey: String) {
        array.enumerateObjects { item, _, _ in
            if let itemDictionary = item as? [String: Any] {
                importData(with: itemDictionary, parentKey: parentKey)
            } else {
                importValue(item, withName: parentKey)
            }
        }
    }

    private func genChildKeyInArray(childKey: String, parentKey: String?) -> String? {
        guard let parentKey = parentKey else {
            return nil
        }
        return parentKey + "[\(childKey)][]"
    }
}

extension URL {
    func mimeType() -> String {
        if #available(iOS 14.0, *) {
            if let mimeType = UTType(filenameExtension: self.pathExtension)?.preferredMIMEType {
                return mimeType
            } else {
                return "application/octet-stream"
            }
        } else {
            return MimeType(ext: pathExtension)
        }
    }
}

extension MultipartFormData: This is an extension for the MultipartFormData class or protocol, which corresponds to the HTTP multipart form data protocol. It allows you to add new methods and properties to that class or protocol.

func importData(with parameter: Parameters, parentKey: String? = nil): This is the main function for importing data into the multipart form data protocol. Parameters is assumed to be a dictionary type, where key-value pairs represent the information you want to send. parentKey is the name of the parent key if the data is being processed within an array.

private func importValue(_ value: Any, withName name: String): This is a small function to handle adding data to multipart form data based on the data type of value. It helps reduce repetition in the code.

private func importArray(_ array: NSArray, withParentKey parentKey: String): This function is for handling arrays in the data. It iterates through the elements in the array and recursively calls the importData function to process each element.

private func genChildKeyInArray(childKey: String, parentKey: String?) -> String?: This function generates key names for elements within an array. It ensures that elements within an array have unique key names.

This extension is structured to handle a variety of data types such as URLs, strings, integers, and floats, as well as subarrays of objects. It helps you build a complex data structure within HTTP multipart form data requests more easily.

Leave a Comment