Example AuthenticateDocument Network Call

The AuthenticateDocument endpoint takes multipart/form-data in the request. If you’re not using a networking library, it may be a little confusing to write. Below is some basic code that will get you going.

Note

This is not production-ready code. Please make the necessary modifications to insert this code in your app.

import Foundation
import CFDocumentScanSDK

class ExampleNetworking {
    /**
    This method creates the image dictionary for use with the Authenticate Document request
    - Parameter resultArray : An array of DSResult objects. The array is expected to be in the form of
    [FrontResult, BackResult]
    */
    func generateImageData(resultArray: [DSResult]) -> [String: Data] {
        // We recommend using cropped images and setting the "AutoCrop" API header parameter to false.
        // If the device cannot crop the document, then there is likely an issue with the document capture.
        var imageData = [String: Data]()
        if let frontResult = resultArray.first {
            if let nonFlashImage = frontResult.croppedImage {
                imageData["frontImage"] = nonFlashImage
            }
            if let flashImage = frontResult.croppedFlashImage {
                imageData["frontFlashImage"] = flashImage
            }
        }
        if resultArray.count > 1, let backResult = resultArray.last {
            if let nonFlashImage = backResult.croppedImage {
                imageData["backImage"] = nonFlashImage
            }
            if let flashImage = backResult.croppedFlashImage {
                imageData["backFlashImage"] = flashImage
            }
        }
        return imageData
    }

    /**
    This method sends the request for Authenticate Document with URL, Headers and Parameters.
    - Parameters:
        - urlString : URL to send the request to.
        - imageData : Dictionary of various images for upload. Valid keys are "frontImage", "frontFlashImage",
        "backImage", and "backFlashImage". The data is the exact image data property from the DSResult object
        - headers : HTTPHeaders object of Alamofire
        - completion : Completion handler for the response
    */
    func authenticateDocumentRequest(urlString: String,
                                    imageData: [String: Data],
                                    headers: [String: String] = [:],
                                    completion: @escaping (Result<Data?, Error>) -> Void) {

        var parameters = [[String: Any]]()
        if let frontImage = imageData["frontImage"] {
            parameters.append([
                "key": "Front",
                "filename": "front.jpg",
                "src": frontImage,
                "type": "image/jpg"
            ])
        }
        if let frontFlashImage = imageData["frontFlashImage"] {
            parameters.append([
                "key": "FrontFlash",
                "filename": "frontFlash.jpg",
                "src": frontFlashImage,
                "type": "image/jpg"
            ])
        }
        if let backImage = imageData["backImage"] {
            parameters.append([
                "key": "Back",
                "filename": "back.jpg",
                "src": backImage,
                "type": "image/jpg"
            ])
        }
        if let backFlashImage = imageData["backFlashImage"] {
            parameters.append([
                "key": "BackFlash",
                "filename": "backFlash.jpg",
                "src": backFlashImage,
                "type": "image/jpg"
            ])
        }
        let boundary = "Boundary-\(UUID().uuidString)"

        #warning("Avoid using force unwraps in production code")
        let postData = NSMutableData()
        for param in parameters {
            let paramName = param["key"]!
            postData.appendString("--\(boundary)\r\n")
            postData.appendString("Content-Disposition:form-data; name=\"\(paramName)\"")
            if param["contentType"] != nil {
                postData.appendString("\r\nContent-Type: \(param["contentType"] as! String)")
            }
            let paramType = param["type"] as! String
            if paramType == "text" {
                let paramValue = param["value"] as! String
                postData.appendString("\r\n\r\n\(paramValue)\r\n")
            } else {
                let paramSrc = param["filename"] as! String
                let fileData = param["src"] as! Data
                postData.appendString("; filename=\"\(paramSrc)\"\r\n"
                                        + "Content-Type: \"content-type header\"\r\n\r\n")
                postData.append(fileData)
                postData.appendString("\r\n")
            }
        }
        postData.appendString("--\(boundary)--\r\n")

        var request = URLRequest(url: URL(string: urlString)!,timeoutInterval: Double.infinity)
        request.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

        // Headers as described in CatfishAir API documentation
        request.allHTTPHeaderFields = headers

        request.httpMethod = "POST"
        request.httpBody = postData as Data

        // NOTE: Most iOS networking libraries (Alamofire, Moya, etc.) safely construct and
        // send multipart/form-data requests. If this is an option for you, then it would
        // be a cleaner approach.
        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            if let error = error {
                print(String(describing: error))
                completion(.failure(error))
                return
            }
            completion(.success(data))
        }

        task.resume()
    }
}


// Helper extension used in the above code
extension NSMutableData {
    /**
    This method converts a string to Data (using utf8 encoding), then appends it to Self
    - Parameter string : the String to be appended and converted.
    */
    func appendString(_ string: String) {
        if let data = string.data(using: .utf8) {
            self.append(data)
        }
    }
}