ios – Image upload with URLSession in Swift

[ad_1]

Trying to create a simple script to upload an image with URLSession in Swift. In order to test the code I send a POST request to https://api.imagga.com/v2/uploads. I created an account to https://imagga.com in order to gain the credentials for uploading. The code for URLSession does not work.

It returns {“status”:{“text”:”No file for upload supplied, use the image or video keys.”,”type”:”error”}}, with Status Code: 400.

The error with status code: 401 is for authorization issues, so I am doing something wrong with the format of the request.

When I use the Alamofire’s implementation the image is uploaded successfully.

My credentials for imagga.com are stored as a struct:

import Foundation

struct ImaggaCredentials {
  static let username = "myUsername"
  static let password = "myPassword"
}

The code for URLSession upload task:

import SwiftUI

class URLSessionObserved: NSObject, ObservableObject {

  @Published var uploadedAmount: Float = 0

  lazy var urlSession: URLSession = {
    let configuration = URLSessionConfiguration.default
    return URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
  }()

  func upload() {

    let urlString = "https://api.imagga.com/v2/uploads"

    let url = URL(string: urlString)!
    let fileURL = Bundle.main.url(forResource: "image", withExtension: "jpeg")
   
    guard let fileURL = fileURL else {
      return
    }

    let loginString = String(format: "%@:%@", ImaggaCredentials.username, ImaggaCredentials.password)
    let loginData = loginString.data(using: String.Encoding.utf8)!
    let base64LoginString = loginData.base64EncodedString()

    let boundary = "Boundary-\(UUID().uuidString)"

    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
    request.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")

    let fileName = fileURL.lastPathComponent

    let mimetype = "image/" + fileName.components(separatedBy: ".")[1]

    let paramName = "file"
    let fileData = try? Data(contentsOf: fileURL)
    guard let fileData = fileData else {
      return
    }

    var data = Data()

    data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
    data.append("Content-Disposition: form-data; name=\"\(paramName)\"; filename=\"\(fileName)\"\r\n".data(using: .utf8)!)
    data.append("Content-Type: \(mimetype)\r\n\r\n".data(using: .utf8)!)

    data.append(fileData)
    data.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)

    request.setValue(String(data.count), forHTTPHeaderField: "Content-Length")

    let task = urlSession.uploadTask(with: request,
                                            from: data,
                                            completionHandler: { data, response, error in
      print(response)
      if(error != nil){
        print("1--\(error!.localizedDescription)")
      }

      guard let data = data else {
        print("no response data")
        return
      }

      if let responseString = String(data: data, encoding: .utf8) {
        print("2--\(responseString)")
      }
    })
    task.resume()
  }
}

The code for Alamofire upload task that works fine:

import SwiftUI
import Alamofire
import UIKit

class AlamofireObserved: NSObject, ObservableObject {
  
  @Published var uploadedAmount: Float = 0

  func upload() {
    print("Button pressed (AlamofireObserved)")

    let urlString = "https://api.imagga.com/v2/uploads"

    let fileURL = Bundle.main.url(forResource: "image", withExtension: "jpeg")
    guard let fileURL = fileURL else {
      return
    }

    let fileName = fileURL.lastPathComponent
    let withName = fileName.components(separatedBy: ".")[0]
    let mimeType = "image/" + fileName.components(separatedBy: ".")[1]

    let fileData = try? Data(contentsOf: fileURL)
    guard let fileData = fileData else {
      return
    }

    AF.upload(multipartFormData: { multipartFormData in
      multipartFormData.append(fileData, withName: withName, fileName: fileName, mimeType: mimeType)
      }, to: urlString)
      .authenticate(username: ImaggaCredentials.username, password: ImaggaCredentials.password)
      .validate()
      .uploadProgress { progress in
        print(Float(progress.fractionCompleted))
        self.uploadedAmount = Float(progress.fractionCompleted)
      }
      .responseDecodable(of: UploadImageResponse.self) { response in
        switch response.result {
        case .failure(let error):
          print("Error uploading file: \(error)")
        case .success(let uploadResponse):
          let resultID = uploadResponse.result.uploadID
          print("Content uploaded with ID: \(resultID)")
        }
    }
  }
}

The response type of the request:

import Foundation

struct UploadImageResponse: Codable {
  let result: UploadResponseResult
  let status: UploadResponseStatus
  
  struct UploadResponseResult: Codable {
    let uploadID: String
    
    enum CodingKeys: String, CodingKey {
      case uploadID = "upload_id"
    }
  }
  
  struct UploadResponseStatus: Codable {
    let text: String
    let type: String
  }
}

[ad_2]

Source link

Leave a Reply

Your email address will not be published.