Multi-part formdata working with Alamofire but failing with URLSession - alamofire

I am trying to make an api request which type is "multipartFormData", is working completely fine with Alamofire but getting failed when uisng URLSession
Alamofire
func alamoFire(){
let operatorID = "24601"
let custName = "PEp"
let dcName = "Richasox"
let bucketName = "s3BucketXXX"
let headers: HTTPHeaders = [
"Content-type": "multipart/form-data",
"x-api-key" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
]
AF.upload(
multipartFormData: { multipartFormData in
multipartFormData.append(operatorID.data(using: .utf8)!, withName: "pickerId")
multipartFormData.append(dcName.data(using: .utf8)!, withName: "dcName")
multipartFormData.append(custName.data(using: .utf8)!, withName: "custName")
multipartFormData.append(bucketName.data(using: .utf8)!, withName: "bucketName")
},
to: "https://xxx.us-east-2.amazonaws.com/endpoint", method: .post , headers: headers)
.validate(statusCode: 200..<300)
.response { resp in
switch resp.result{
case .failure(let error):
print(error)
case.success( _):
print("🥶🥶Response after upload Img: \(resp.result)")
}
}
}
URLSession
func urlSession() {
let operatorID = "24601"
let custName = "PEPSI%20CORPORATE"
let dcName = "Richardson%20DC"
let bucketName = "picker-images-upload-rehrig"
let url = URL(string: "https://xxx.us-east-2.amazonaws.com/endpoint")
let boundary = UUID().uuidString
let session = URLSession.shared
var urlRequest = URLRequest(url: url!)
urlRequest.httpMethod = "POST"
urlRequest.setValue("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", forHTTPHeaderField: "x-api-key")
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
var data = Data()
data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
data.append("Content-Disposition: form-data;pickerId=\"\(operatorID)\"; dcName=\"\(dcName)\"; bucketName=\"\(bucketName)\"; custName=\"\(custName)\"\r\n".data(using: .utf8)!)
data.append("\r\n".data(using:.utf8)!)
session.uploadTask(with: urlRequest, from: data, completionHandler: { responseData, response, error in
if error == nil {
let jsonData = try? JSONSerialization.jsonObject(with: responseData!, options: .allowFragments)
if let json = jsonData as? [String: Any] {
print("picker resp",json)
}
}
}).resume()
}
Error when using URLSession
Optional<NSURLResponse>
- some : <NSHTTPURLResponse: 0x283f8f4a0> { URL: https://xxx.us-east-2.amazonaws.com/endpoint } { Status Code: 502, Headers {
"Content-Length" = (
36
);
"Content-Type" = (
"application/json"
);
Date = (
"Sat, 15 Jan 2022 16:57:05 GMT"
);
Via = (
"1.1 62f7aa308c367fb8f14fc57f199056cc.cloudfront.net (CloudFront)"
);
"x-amz-apigw-id" = (
"L_xzJGBIiYcFfAA="
);
"x-amz-cf-id" = (
"2M2PlnPLZ8k_91htcX4OM4UL2a5ldOfntUbVO3xxMp702m9MMr0Elw=="
);
"x-amz-cf-pop" = (
"BLR50-C3"
);
"x-amzn-errortype" = (
InternalServerErrorException
);
"x-amzn-requestid" = (
"b7de8e82-06fe-41e0-9deb-0f2783aeea89"
);
"x-cache" = (
"Error from cloudfront"
);
} }

Related

POST method API with parameters in swiftUI

I am retrieving details from my api with POST method, I have included the parameters here. I am able to print the response in console., but to the view it's quite complicating. Here added the code which i've tried. I appreciate if someone help me to get this done.
My network code goes here:
class HostApi: ObservableObject {
#Published var todos = [HostsHome]()
#Published var amenity = [AmenitiesHome]()
func loadData() {
let Url = String(format: Host_home)
guard let serviceUrl = URL(string: Url) else {
return
}
let parameters: [String : Any] = [
"request" : ["email" : "xxxxxxxxxxx.com",
"starting" : 0,
"ending" : 10]
]
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) else {
return
}
request.httpBody = httpBody
request.timeoutInterval = 20
let session = URLSession.shared
session.dataTask(with: request) { data, response, error in
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: .json5Allowed)
print(json)
} catch {
print(error)
}
}
}.resume()
}
}
ContentView code goes here :
struct Hosts_Home: View {
#StateObject var viewModel = HostApi()
var body: some View {
ForEach(viewModel.todos, id: \.title) { todo in
Text(todo.title!)
}
.onAppear {
viewModel.loadData()
}
}
}
[![api[![parameters][1]][1]][2]
[1]: https://i.stack.imgur.com/R5sBV.png
[2]: https://i.stack.imgur.com/yMj0t.png
Found a solution, I changed my network class like this below and it worked.
class HostApi: ObservableObject {
#Published var todos = [HostsHome]()
#Published var amenity = [AmenitiesHome]()
func loadData() {
let url = URL(string: Host_home)
guard let requestUrl = url else { fatalError() }
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
let postString = "email=xxxxxxx#gmail.com&starting=0&ending=10";
request.httpBody = postString.data(using: String.Encoding.utf8);
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
do {
if let todoData = data {
let decodedData = try JSONDecoder().decode([HostsHome].self, from: todoData)
DispatchQueue.main.async {
self.todos = decodedData
self.amenity = decodedData[0].amenities
print(decodedData[0].propertyTypeGroup)
}
} else {
print("No data")
}
} catch {
print(error)
}
}
task.resume()
}
}

How to Display Post Method Requests data in Swiftui Ios Simulator Screen?

This is Doc File Generate in Postman by write method and url "link/services.php".
This is Header File.
#Headers({"Content-Type: application/json"})
 #POST("services.php")
Observable<Division> divisionListApi(#Body HashMap<String, String> map);
map.put("method", "My_List");
After Postman Generation I Got This Given Below.
{"err_code":9,
"message":"My List ",
"list":[
{"ForestDivision":"Yam(T)"},
{"ForestDivision":"Rewar(T)"},
{"ForestDivision":"Ro(T)"},
{"ForestDivision":"Bh(T)"},
{"ForestDivision":"Ka(T) "},
{"ForestDivision":"Ambal(T) "},
{"ForestDivision":"Fari(T)"}]
}
I have made request by taking post mehod, is this the right way to create code in
swiftui.
import Foundation
import Combine
struct File: Decodable, Hashable {
var error_code : Int
var message : String
var list : [lisst]
}
struct lisst: Decodable, Hashable {
var ForestDivision: String
}
class fetchResults : ObservableObject{
#Published var fetchedRes : [lisst]?
func getData(completion: #escaping (File) -> ()){
print("Fetch")
let parameters = "{ I dont Know }"
let postData = parameters.data(using: .utf8)
var request = URLRequest(url: URL(string:
"URl")!,timeoutInterval: Double.infinity)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
request.httpBody = postData
let task = URLSession.shared.dataTask(with: request) { (data, _, _) in
let resultList = try! JSONDecoder().decode(File.self, from: data!)
print(" ")
print("ID: \(resultList.error_code)")
print("VOLUME: \(resultList.message)")
print("READINGS: \(String(describing: resultList.list))")
print(" ")
print("SUCCESS: Got data - \(data! )")
DispatchQueue.main.async {
completion(resultList) // << here !!
}
}
task.resume()
}
}
Also How to Write in Swiftui View.
To Make Properly Works in List View.
import SwiftUI
import UIKit
struct DivisionList: View {
#ObservedObject var res = fetchResults()
var body: some View {
NavigationView {
Text("Nothing Here")
List(res.fetchedRes ?? [], id: \.self) { resp in // Error Here
ForEach(res.list, id: \.self) { course in
VStack {
Text(res.for) // Error Here
}
}
}
.navigationBarTitle("Data")
.onAppear(perform: {
self.getData // Error Here
})
}
}
}
struct DivisionList_Previews: PreviewProvider {
static var previews: some View {
DivisionList()
}
}
Create New Swift File Copy this Post Requests.
import Foundation
import Combine
let postUrl = "Your URl"
struct divisionList: Decodable, Identifiable {
let id: Int
let mesg: String
let list: [FDivision]
private enum CodingKeys: String, CodingKey {
case id = "err_code"
case mesg = "message"
case list = "list"
}
}
struct FDivision: Decodable, Hashable {
let forestDivision: String
private enum CodingKeys: String, CodingKey {
case forestDivision = "ForestDivision"
}
init(data:String) {
forestDivision = data
}
}
class viewModal: ObservableObject {
#Published var items = [FDivision]()
func postData() {
guard let serviceUrl = URL(string: postUrl) else { return }
let parameters: [String: Any] = [
"method": "Your Method Name"
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else {
return
}
request.httpBody = httpBody
request.timeoutInterval = 20
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
if let dictionary = json as? [String:Any] {
if let arrList = dictionary["list"] as? [[String:Any]]{
for data in arrList{
let model = FDivision(data: data["ForestDivision"] as! String)
self.items.append(model)
}
}
}
print(json)
} catch {
print(error)
}
}
}.resume()
}
}
Create Now New Swiftui File.
import SwiftUI
import UIKit
struct DivisionList: View {
#ObservedObject var vm = viewModal()
var body: some View {
NavigationView {
VStack {
List(vm.items, id: \.self) { item in
Button(action: {}, label: {
Text(item.forestDivision).foregroundColor(.customGreen)
})
}
}.navigationBarTitle("Data")
.onAppear(perform: {
vm.postData()
})
}
}
}
struct DivisionList_Previews: PreviewProvider {
static var previews: some View {
DivisionList()
}
}

I POST file upload(multipart) but it send empty data to web service in swift4

In my application I am trying to upload photos with web service but it send empty to service. There seems to be no errors in the code, but I do not know why it is.However, when I try a different method without photography, the data is full. I really do not understand what is the problem. How can solve this problem?
func apiIsGuvenligi ()
{
let imgData = UIImageJPEGRepresentation(imageView.image!, 0.2)!
var request = URLRequest(url: URL(string: "http://glcwebapi.azurewebsites.net/api/JobSecurity/JobSecurity")!)
request.httpMethod = "POST"
let boundary = generateBoundaryString()
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("Bearer \(self.token2)", forHTTPHeaderField: "Authorization")
payload = ["MessageBody": textView.text!,
"IsCallEmergencyTeam": acilDurum,
"IsFireExtinguishUsed": yangin,
"SendMyself": kendimeGonder,
"LocationParameter": "\(latitude)-\(longitude)"
] as [String : AnyObject]
if(imgData == nil) { return }
request.httpBody = createBodyWithParameters(parameters: payload as? [String : String], filePathKey: "file", imageDataKey: imgData as NSData, boundary: boundary) as Data
apiKontrol = true
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
self.hataMesaji = "Hata=\(String(describing: error))"
return
}
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]
let error = json["Data"] as? String
if error == nil
{
}
else
{
self.mesajVer2(mesaj: error!)
self.hataMesaji = "\(String(describing: error))"
}
}
catch let error as NSError {
print(error)
}
// Apiden gelen tüm keys-values, veriler parse edilip kullanılır.
let responseString = String(data: data, encoding: .utf8)
print("responseString iş güvenliği = \(String(describing: responseString))")
}
task.resume()
}
func createBodyWithParameters(parameters: [String: String]?, filePathKey: String?, imageDataKey: NSData, boundary: String) -> NSData {
let body = NSMutableData()
if payload != nil {
for (key, value) in payload {
body.appendString(string: "--\(boundary)\r\n")
body.appendString(string: "Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
body.appendString(string: "\(value)\r\n")
print("key \(key) \(value)")
}
}
let filename = "image.jpg"
let mimetype = "image/jpg"
body.appendString(string: "--\(boundary)\r\n")
body.appendString(string: "Content-Disposition: form-data; name=\"PhotoRequest\"; filename=\"\(filename)\"\r\n")
body.appendString(string: "Content-Type: \(mimetype)\r\n\r\n")
body.append(imageDataKey as Data)
body.appendString(string: "\r\n")
body.appendString(string: "--\(boundary)--\r\n")
return body
}
func generateBoundaryString() -> String {
return "Boundary-\(NSUUID().uuidString)"
}
// extension for image uploading
extension NSMutableData {
func appendString(string: String) {
let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true)
append(data!)
}
}

Bad Request: there is no photo in the request

I'm trying to send an image from my application to telegram bot like here
https://newfivefour.com/swift-form-data-multipart-upload-URLRequest.html
Here is the code
let BotToken = "12345"
let ChatID = "123"
func SendToTelegram()
{
var request = URLRequest(url: URL(string: "https://api.telegram.org/bot"+BotToken+"/sendPhoto")!)
request.httpMethod = "POST"
let boundary = "Boundary-\(UUID().uuidString)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let params = [:] as [String: String]
UIGraphicsBeginImageContextWithOptions(ScreenImage.bounds.size, true, 0.0)
ScreenImage.image?.draw(in: CGRect(x: 0, y: 0, width: ScreenImage.frame.size.width, height: ScreenImage.frame.size.height))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
request.httpBody = createBody(parameters: params,
boundary: boundary,
data: UIImageJPEGRepresentation(image!, 0.7)!,
mimeType: "image/jpg",
filename: "hello.jpg")
print(request.httpBody!)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
return
}
do {
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? AnyObject
if let parseJSON = json {
print("resp :\(parseJSON)")
}
} catch let error as NSError {
print("error : \(error)")
}
}
task.resume()
}
and get an error
Bad Request: there is no photo in the request";
"error_code" = 400;
ok = 0;
Where do i make a mistake? I'm new in SWIFT and sorry for my English
I know this question is old but the link provided pushed me in the right direction. This is my solution for server side Swift not iOS but you should be able to use it with minimal changes. Remember if you're using iOS, perform none of these operations on the main thread.
class NetworkManager {
func sendTelegramPhoto(_ photo: Data) {
let url = "https://api.telegram.org/bot\(Constants.Telegram.token)/sendPhoto"
let params: [String: Any] = [
"chat_id": Constants.Telegram.uid,
"photo": photo
]
let _ = sendMultiTypePostRequest(url, parameters: params)
}
private func sendMultiTypePostRequest(_ url: String, parameters: [String:String]) -> NetworkResponse {
var networkResponse = NetworkResponse()
let semaphore = DispatchSemaphore(value: 0)
guard let url = URL(string: url) else {
return networkResponse
}
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
let boundary = "Boundary-\(UUID().uuidString)"
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let httpBody = createBody(parameters: parameters,
boundary: boundary,
mimeType: "image/jpeg",
filename: "snapshot.jpg")
let config = URLSessionConfiguration.default
config.requestCachePolicy = .reloadIgnoringLocalCacheData
let session = URLSession(configuration: config)
let task = session.uploadTask(with: urlRequest, from: httpBody) { (data, response, error) in
networkResponse.data = data
networkResponse.response = response
networkResponse.error = error
semaphore.signal()
}
task.resume()
_ = semaphore.wait(timeout: .distantFuture)
return networkResponse
}
private func createBody(parameters: [String: String],
boundary: String,
mimeType: String,
filename: String) -> Data {
var body = Data()
let boundaryPrefix = "--\(boundary)\r\n"
for (key, value) in parameters {
if let data = value as? Data {
body.appendString(boundaryPrefix)
body.appendString("Content-Disposition: form-data; name=\"\(key)\"; filename=\"\(filename)\"\r\n")
body.appendString("Content-Type: \(mimeType)\r\n\r\n")
body.append(data)
body.appendString("\r\n")
} else if let string = value as? String {
body.appendString(boundaryPrefix)
body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
body.appendString("\(string)\r\n")
}
}
body.appendString("--".appending(boundary.appending("--")))
return body
}
}
private extension Data {
mutating func appendString(_ string: String) {
let data = string.data(using: String.Encoding.utf8, allowLossyConversion: false)
append(data!)
}
}

Swift - 8tracks.com API POST json data fails (422) everytime

I'm trying to talk with 8tracks open API in Swift iOS app. I need to make POST authorization request to http://8tracks.com/sessions.jsonwith AFNetworking but everytime I get 422 Unprocessable Entity error..
I tried this endpoint on the web and it works fine. Here is code that I'm using (subclassing AFHTTPSessionManager):
init() {
super.init()
self.responseSerializer = AFJSONResponseSerializer()
self.requestSerializer = AFJSONRequestSerializer()
self.requestSerializer.setValue(API_KEY, forHTTPHeaderField: "X-Api-Key")
self.requestSerializer.setValue("3", forHTTPHeaderField: "X-Api-Version")
}
func login(username: String, password: String, success: (NSURLSessionDataTask!, AnyObject!) -> Void, failure: ((NSURLSessionDataTask!, NSError!) -> Void)?) {
let credentials = ["username": username, "password": password] as Dictionary
self.POST(
API_URL.stringByAppendingString("/sessions.json"),
parameters: credentials,
success: success,
failure: failure
)
}
Error looks as follows:
{ URL: http://8tracks.com/sessions.json } { status code: 422, headers {
"Accept-Ranges" = bytes;
"Access-Control-Allow-Origin" = "*";
Age = 0;
"Cache-Control" = "max-age=0, private, must-revalidate";
Connection = "keep-alive";
"Content-Length" = 125;
"Content-Type" = "application/json; charset=utf-8";
Date = "Wed, 25 Jun 2014 19:29:12 GMT";
Server = "nginx/1.4.3";
Status = "422 Unprocessable Entity";
Via = "1.1 varnish";
"X-Action" = "sessions/create";
"X-Backend" = rails;
"X-Cache" = MISS;
"X-Data-Request" = 1;
"X-Request-Id" = 3040c8bf79936b27075731f634bfd534;
"X-Requests-Left" = 99;
"X-Runtime" = "0.257240";
"X-UA-Compatible" = "IE=Edge,chrome=1";
} }, NSLocalizedDescription=Request failed: client error (422),
NSErrorFailingURLKey=http://8tracks.com/sessions.json}
It might have something to do with subclass AFHTTPSessionManager without a baseURL. I've tested the following code and it works.
let path = "/sessions.json"
let params = ["login": login, "password": password, "api_version": "3"]
let success = {(task: NSURLSessionDataTask!, response: AnyObject!) -> Void in
println(response)
}
let failure = {(task: NSURLSessionDataTask!, error: NSError!) -> Void in
println(error)
}
var client = AFHTTPSessionManager(baseURL: NSURL(string: "https://8tracks.com"))
client.POST(path, parameters: params, success: success, failure: failure)