Swift 3 How To Send A Multipart Post Request With Vapor - swift

I'm using vapor to host images for my app.I have the following code to recieve the image and print it.
drop.post("saveArt") { request in
if let contentType = request.headers["Content-Type"], contentType.contains("image/png"), let bytes = request.body.bytes {
let image = NSImage(data: Data(bytes))
print(image)
return JSON(["Testawesome":"awesome123"])
}
return JSON(["test":"123"])
}
How can I send a multipart request using just swift?.Here is the current post request code i'm using.
let tiffData = imagetosend?.tiffRepresentation
let imageRep = NSBitmapImageRep(data: tiffData!)
let image_data = imageRep?.representation(using: .JPEG, properties: [:])
print("Hi")
let url = NSURL(string: "http://localhost:8080/getArt")
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "POST"
//define the multipart request type
request.setValue("multipart/form-data", forHTTPHeaderField: "Content-Type")
let body = NSMutableData()
let mimetype = "image/png"
//define the data post parameter
body.append("Content-Type: \(mimetype)\r\n\r\n".data(using: String.Encoding.utf8)!)
body.append(image_data!)
body.append("\r\n".data(using: String.Encoding.utf8)!)
request.httpBody = body as Data
let session = URLSession.shared
let task = session.dataTask(with: request as URLRequest) {
(
data, response, error) in
guard let _:NSData = data as NSData?, let _:URLResponse = response , error == nil else {
print(error?.localizedDescription)
return
}
let dataString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print(dataString)
}
task.resume()

I solved it using this alamofire method.
Alamofire.request("YOUR URL", method: .post, parameters: parm, encoding: JSONEncoding.default).responseJSON(completionHandler: { json in
// If you want to return json.
print(json)
})

Related

Upload an .XML file with a name via POST method in SWIFT

As part of an HTTP server request I need to upload an .XML file in a POST request that includes query information. Yet simply using URLSession.shared.uploadTask(with:, fromFile:) doesn't seem to work. Like the following:
func reportRequest(url: URL) -> Void {
let fileURL: URL = URL(fileURLWithPath: ".../search_xml.xml")
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
urlRequest.setValue(authToken, forHTTPHeaderField: "authorization")
let task = URLSession.shared.uploadTask(with: urlRequest, fromFile: fileURL) {data, response, error in
print(String(data: data!, encoding: .utf8)!)
print(response)
}
task.resume()
I have achieved this on Python using the files parameters in the requests module, and passing a dictionary in it like the following:
headers = {'authorization': authToken, }
files = {'xmlRequest': open('.../search.xml', 'rb')}
response = requests.post(url, headers=headers, files=files)
I also achieved this in RestMan (a browser extension to manage REST APIs) by adding a form data in the body, with "xmlRequest" as key and choosing the .XML file as value.
It might seem like I have to build request body myself in SWIFT, but I have little knowledge in that, and the tutorials I find about it are mostly about uploading Images, which might be different.
Thanks in advance!
Here's a generic example to upload a file.
let headers = [
"content-type": "multipart/form-data;",
"authorization": "authToken",
]
let parameters = [
[
"name": "xmlfile",
"fileName": "search_xml.xml"
]
]
var body = ""
var error: NSError? = nil
for param in parameters {
let paramName = param["name"]!
body += "--\(boundary)\r\n"
body += "Content-Disposition:form-data; name=\"\(paramName)\""
if let filename = param["fileName"] {
let contentType = param["content-type"]!
let fileContent = String(contentsOfFile: filename, encoding: String.Encoding.utf8)
if (error != nil) {
print(error)
}
body += "; filename=\"\(filename)\"\r\n"
body += "Content-Type: \(contentType)\r\n\r\n"
body += fileContent
} else if let paramValue = param["value"] {
body += "\r\n\r\n\(paramValue)"
}
}
let request = NSMutableURLRequest(url: NSURL(string: "https://example.com/fileupload")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()

URL Session Post with form-data parameter in iOS Swift

I am trying to POST a parameter using form-data in swift.
I want to pass a mobile number with url session in form-data format. but I can't able to send data properly . please help me to pass data on form-data format in url session.
code I have Tried:
func registerService(){
print("register tapped")
let parameters: [String: Any] = [
"mobile" : mobileNumber
]
let url = URL(string: "http://54.251.198.30/api/user/login")
var req = URLRequest(url: url!)
req.httpMethod = "POST"
let boundary = "Boundary-\(UUID().uuidString)"
req.addValue("multipart/form-data : \(boundary)", forHTTPHeaderField: "Contet-Type")
req.addValue("multipart/form-data", forHTTPHeaderField: "Accept")
req.httpBody = NSKeyedArchiver.archivedData(withRootObject: parameters)
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) else {return}
req.httpBody = httpBody
let session = URLSession.shared
session.dataTask(with: req, completionHandler: {(data, response, error) in
if response != nil {
print(response)
}
if let jsonResponse = try? JSONDecoder().decode(LoginBase.self, from: data!) {
print(jsonResponse)
}else{
print("error")
}
}).resume()
}
I have added an image which parameter I want to pass. you Can see Here
thanks for your response
I have modified your function parameter as well as request-body in the correct syntax. Now you can use as follows:-
func Register(){
print("register tapped")
let parameters: [String: Any] = ["mobile" : mobileNumber] as Dictionary<String, Any>
var request = URLRequest(url: URL(string: "http://54.251.198.30/api/user/login")!)
request.httpMethod = "POST"
request.httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: [])
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let session = URLSession.shared
let task = session.dataTask(with: request, completionHandler: { data, response, error -> Void in
print(response!)
do {
let json = try JSONSerialization.jsonObject(with: data!) as! Dictionary<String, AnyObject>
print(json)
} catch {
print("error")
}
})
task.resume()
}

Swift: How to add Dictionary format in forHTTPHeaderField in GET request

In GET request, I am trying to add header.
request.setValue(value: String?, forHTTPHeaderField: "SessionInfo")
But, SessionInfo value is in [String : Any]
Attempt 1:
func SO_Function() {
let service_url = WebService.sharedManager().serviceURL
let getMenuURL = service_url + "/MyPage/FileDownload.ashx"
var convertedString = ""
do {
let data1 = try JSONSerialization.data(withJSONObject: WebService.sharedManager().mobInfoDict, options: [])
convertedString = String(data: data1, encoding: .utf8)!
print("\n\nconvertedJSONtoData ", convertedString)
} catch {
print("\n\nCAtcLL___Err ",error.localizedDescription)
}
let url = NSURL(string: getMenuURL)
let request = NSMutableURLRequest(url: url! as URL)
//Below line, If I can able to add [String:Any] then I will get
proper Image as output.
request.setValue(convertedString, forHTTPHeaderField: "SessionInfo")
request.setValue("67a2a6fb1d13450a", forHTTPHeaderField: "Flowid")
request.setValue("d29566ac42de4e99", forHTTPHeaderField: "Fileid")
request.setValue("LMS_LEAVEREQUEST", forHTTPHeaderField: "Form")
request.httpMethod = "GET"
let session = URLSession.shared
let mData = session.dataTask(with: request as URLRequest) { (data, response, error) -> Void in
if let res = response as? HTTPURLResponse {
DispatchQueue.main.async {
let img = UIImage(data: data!)
self.attachmentImgVw.image = img
}
}else{
print("\n\nError: \(String(describing: error))")
}
}
mData.resume()
}
Output
The data couldn’t be read because it isn’t in the correct format.
Error ScreenShot 1:
Postman Screenshot
In postman, I am giving SessionInfo value as in Dictionary format. Working fine.
How to solve this issue?

Swift 4.2 code equivalent for SAP's Leonardo API [duplicate]

This question already has answers here:
Upload image with parameters in Swift
(3 answers)
Closed 4 years ago.
Getting HTTP 400 error while connecting with SAP Leonardo sandbox server using scene text recognition API
SAP provides boilerplate code in older version of swift. I have used curl command and the API and works. But its not working when I try and convert the code into swift 4.2 version. I am attaching the code below.
func connectWithSAP(photoURL : URL, photoData : String, sentImageData : Data){
if let myNewURL = URL(string: "https://sandbox.api.sap.com/ml/scenetextrecognition/scene-text-recognition") {
var myRequest = URLRequest(url: myNewURL)
myRequest.addValue("multipart/form-data; --\(boundary)", forHTTPHeaderField: "Content-Type")
myRequest.addValue("application/json", forHTTPHeaderField: "Accept")
myRequest.addValue("xxxxxxxxxxx", forHTTPHeaderField: "APIKey")
myRequest.httpMethod = "POST"
myRequest.cachePolicy = .reloadIgnoringLocalCacheData
myRequest.timeoutInterval = 60.0
// Constructing the body of the request.
var data = Data()
var dataString = ""
dataString.append("--\(boundary)\r\n")
dataString.append(contentsOf: "Content-Disposition:form-data; name=\"files\"; filename=\"Image1.jpeg\" \r\n")
dataString.append(contentsOf: ";Content-Type:image/jpeg \r\n\r\n")
dataString.append(photoData)
dataString.append("--\(boundary) ----- \r\n")
data = dataString.data(using: .utf8)!
myRequest.httpBody = data
let task = URLSession.shared.dataTask(with: myRequest) { (data, response, error) in
if let error = error {
print(error)
}
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
print(error as Any)
// Getting output at this stage, which is shown below
return }
if let mimeType = httpResponse.mimeType,
mimeType == "application/json",
let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String:Any]
print(json as Any)
}catch {
print(error)
}
}
}
task.resume()
}
I am getting a following details in my response object
{ URL: https://sandbox.api.sap.com/ml/scenetextrecognition/scene-text-recognition } { Status Code: 400, Headers {\n Connection = (\n \"keep-alive\"\n );\n \"Content-Length\" = (\n 131\n );\n \"Content-Type\" = (\n \"application/json\"\n );\n Date = (\n \"Sat, 16 Feb 2019 11:56:37 GMT\"\n );\n Server = (\n \"Werkzeug/0.14.1 Python/3.5.5\"\n );\n \"Strict-Transport-Security\" = (\n \"max-age=31536000; includeSubDomains; preload;\"\n );\n \"X-Vcap-Request-Id\" = (\n \"fea7037c-4e48-49d2-4be1-53b0dad0ee46\"\n );\n}
As you would see the status code is HTTP 400. Need some help in getting the right response and data from the server.
Most probably, the body data got messed up. Here's the working code:
let boundaryConstant = "----WebKitFormBoundary7MA4YWxkTrZu0gW"
let headers = [
"APIKey": "YourAPIKEY"
]
let contentType = "multipart/form-data; boundary=" + boundaryConstant
//API endpoint for API sandbox
var request = URLRequest(url: URL(string: "https://sandbox.api.sap.com/ml/scenetextrecognition/scene-text-recognition")!)
//setting request method
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let path1 = Bundle.main.path(forResource: "your_image", ofType: "png")!
let url = URL(fileURLWithPath: path1)
let fileName = url.lastPathComponent
let data = try? Data(contentsOf: url)
let imageData = UIImage.init(data: data!)!
let pngData = UIImagePNGRepresentation(imageData)!
let mimeType = "image/png"
let boundaryStart = "--\(boundaryConstant)\r\n"
let boundaryEnd = "--\(boundaryConstant)--\r\n"
let fieldName = "files"
let contentDispositionString = "Content-Disposition: form-data; name=\"\(fieldName)\"; filename=\"\(fileName)\"\r\n"
let contentTypeString = "Content-Type: \(mimeType)\r\n\r\n"
var body = Data()
body.append(boundaryStart.data(using: .utf8)!)
body.append(contentDispositionString.data(using: .utf8)!)
body.append(contentTypeString.data(using: .utf8)!)
body.append(pngData)
body.append("\r\n".data(using: .utf8)!)
body.append(boundaryEnd.data(using: .utf8)!)
request.httpBody = body
request.setValue(contentType, forHTTPHeaderField: "Content-Type")
request.setValue(String(body.count), forHTTPHeaderField: "Content-Length")
let dataTask = session.dataTask(with: request) { (data, response, error) in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
}
dataTask.resume()
You can also use Alamofire to upload image. It's way cleaner, don't need to play around with "body" much:
let headers: HTTPHeaders = [
"APIKey": "<<Your API KEY>>",
"Content-type": "multipart/form-data"
]
let parameters:[String: String] = [:] //any other parameters you need to send
let path1 = Bundle.main.path(forResource: "<<your_image>>", ofType: "<<png or jpeg>>")!
let url = URL(fileURLWithPath: path1)
let fileName = url.lastPathComponent
let data = try? Data(contentsOf: url)
let imageData = UIImage.init(data: data!)!
//converting it into png data
let pngData = UIImagePNGRepresentation(imageData)
let mimeType = "image/png"
let fieldName = "files"
Alamofire.upload(multipartFormData: { (multipartFormData) in
for (key, value) in parameters {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
if let data = pngData{
multipartFormData.append(data, withName: fieldName, fileName: fileName, mimeType: mimeType)
}
}, usingThreshold: UInt64.init(), to: "https://sandbox.api.sap.com/ml/scenetextrecognition/scene-text-recognition" , method: .post, headers: headers) { (result) in
switch result{
case .success(let upload, _, _):
upload.responseJSON { response in
print("Succesfully uploaded")
}
case .failure(let error):
print("Error in upload: \(error.localizedDescription)")
}
}

How to convert this to a POST call with a JSON serialized Object

I have tried Alamofire, I have tried it with all my heart. It just does not work for me. I finally got http GET working, but I need to get http POST working. Our POST API's take a Request object that has all the necessary data in it. I have requested the backend developers to provide me with a KEY-VALUE pair JSON (no embedded objects/arrays) so that I can use a Dictionary in my swift code convert that to json and send the request. All I need is now to convert the below code to POST.
My earlier questions that did not help much.
NSInvalidArgumentException Invalid type in JSON write DemographicsPojo
Swift 3.0, Alamofire 4.0 Extra argument 'method' in call
I have given up on Alamofire. I want to use Foundation classes. Simple basic and fundamental way of life :).
func callWebService(url : String) {
// Show MBProgressHUD Here
var config :URLSessionConfiguration!
var urlSession :URLSession!
config = URLSessionConfiguration.default
urlSession = URLSession(configuration: config)
// MARK:- HeaderField
let HTTPHeaderField_ContentType = "Content-Type"
// MARK:- ContentType
let ContentType_ApplicationJson = "application/json"
//MARK: HTTPMethod
let HTTPMethod_Get = "GET"
let callURL = URL.init(string: url)
var request = URLRequest.init(url: callURL!)
request.timeoutInterval = 60.0 // TimeoutInterval in Second
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
request.addValue(ContentType_ApplicationJson, forHTTPHeaderField: HTTPHeaderField_ContentType)
request.httpMethod = HTTPMethod_Get
let dataTask = urlSession.dataTask(with: request) { (data,response,error) in
if error != nil{
print("Error **")
return
}
do {
let resultJson = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:AnyObject]
print("Result",resultJson!)
} catch {
print("Error -> \(error)")
}
}
dataTask.resume()
print("..In Background..")
}
Just pass JSON string and the API URL to this function. Complete code for POST.
func POST(api:String,jsonString:String,completionHandler:#escaping (_ success:Bool,_ response:String?,_ httpResponseStatusCode:Int?) -> Void) {
let url = URL(string: api)
var request: URLRequest = URLRequest(url: url!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField:"Content-Type")
request.timeoutInterval = 60.0
//additional headers
if let token = Helper.readAccessToken() {
request.setValue("\(token)", forHTTPHeaderField: "Authorization")
}
let jsonData = jsonString.data(using: String.Encoding.utf8, allowLossyConversion: true)
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) {
(data: Data?, response: URLResponse?, error: Error?) -> Void in
var responseCode = 0
if let httpResponse = response as? HTTPURLResponse {
responseCode = httpResponse.statusCode
print("responseCode \(httpResponse.statusCode)")
}
if error != nil {
completionHandler(false, error?.localizedDescription,nil)
} else {
let responseString = String(data: data!, encoding: .utf8)
completionHandler(true, responseString, responseCode)
}
}
task.resume()
}