Grab content from POST call URLSession - swift

I am trying to pull the cookie from this POST call to use for another call.
I have a URLSession response for a POST call here:
<NSHTTPURLResponse: 0x600000418120> { URL: https://example.com:443/Auth/ } { Status Code: 200, Headers {
Accept = (
"*/*"
);
"Accept-Encoding" = (
"br, gzip, deflate"
);
"Accept-Language" = (
"en-us"
);
Authorization = (
"Basic keyHere=="
);
"Content-Encoding" = (
gzip
);
"Content-Type" = (
"application/json"
);
Date = (
"Tue, 25 Sep 2018 18:17:38 GMT"
);
Host = (
"example.com:443"
);
"SMSESSION-Idle-Expire" = (
"Tue, 25-Sep-2018 20:17:38 GMT"
);
"SMSESSION-Session-Expire" = (
"Wed, 26-Sep-2018 04:17:38 GMT"
);
"Set-Cookie" = (
"SMSESSION=sessionKeyHere==;Domain=example.com;Path=/"
);
"Transfer-Encoding" = (
Identity
);
"User-Agent" = (
"Web%20Service%20Test/1 CFNetwork/974.2.1 Darwin/18.0.0"
);
"X-Forwarded-For" = (
"11.111.11.11"
);
} }
How would I pull the Set-Cookie SMSESSION key from here? Is there a correct way to do this? Or would I just parse through this response and pull the key from there?
Here is my function:
func test() {
let username = "myUsername"
let password = "myPassword"
let loginString = String(format: "%#:%#", username, password)
let loginData = loginString.data(using: String.Encoding.utf8)!
let base64LoginString = loginData.base64EncodedString()
let url = URL(string: "https://example.com:443/Auth/")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")
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: [])
print(json)
} catch {
print(error)
}
}
}.resume()
}
Thanks for the help!

Thanks #Cristik for the answer.
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
let httpResponse = response as! HTTPURLResponse // HTTPURLResponse is a subclass of URLResponse
print(httpResponse.allHeaderFields["Set-Cookie"] ?? "") // Cookie Value
}
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
} catch {
print(error)
}
}
}.resume()

Related

Post a json patch in Swift 5

I'm testing an api call in Swift with Patch to update an object partially.
It worked well with Postman
PATCH http://localhost:5000/api/accounts/eca9c1b05fb24ca192afe370aa5a1965
[
{
"op": "add",
"path": "/firstname",
"value": "wakaka"
}
]
Here's my playground:
let urlString = "http://localhost:5000/api/accounts/eca9c1b05fb24ca192afe370aa5a1965"
let url = URL(string: urlString)
var request = URLRequest(url: url!)
// guard var request = request else { return nil }
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("gzip, deflate, br", forHTTPHeaderField: "Accept-Encoding")
request.httpMethod = "PATCH"
let jsonPatch = "[{\"op\" : \"add\", \"path\" : \"/firstname\", \"value\": \"my first name\"}]"
do {
let encodedResult = try JSONEncoder().encode(jsonPatch)
print(encodedResult.debugDescription)
request.httpBody = encodedResult
print(request.httpBody?.description)
} catch let error {
print(error.localizedDescription)
}
// decoding
URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil {
print("err: ",error.debugDescription)
return
}
// handling api's errors
if let res = response as? HTTPURLResponse {
print(res.statusCode)
switch res.statusCode {
case 400:
print("400")
// completion(.failure(ApiError.badRequest))
return
case 409:
print("409")
return
case 422:
print("422")
print(res.debugDescription)
return
default:
break
}
}
// OK
do {
let result = try JSONSerialization.jsonObject(with: data!, options: [])
print("json:", result)
} catch let jsonError {
print("error:", jsonError.localizedDescription)
}
}
.resume()
The result I got:
<NSHTTPURLResponse: 0x600000921320> { URL: http://localhost:5000/api/accounts/eca9c1b05fb24ca192afe370aa5a1965 } { Status Code: 422, Headers {
"Content-Length" = (
350
);
"Content-Type" = (
"application/problem+json; charset=utf-8"
);
Date = (
"Thu, 10 Jun 2021 15:59:29 GMT"
);
Server = (
Kestrel
);
} }
That weird when it returns 422 while my call on Postman works well. Thanks for any advice!

Using POST and Auth with Firebase Database and Swift

I need to use REST Api on my iOS app to post/retrieve data from my server. The app is set up with a key generator, which gets me a id token, and then I format my http request with the id. I know something about my url request is wrong, I just don't know what, but I get back a status code 400 whenever I run this. Any ideas where I went wrong?
func postToFB() {
let preURL = "https://myapp.firebaseio.com/"
let url = URL(string: "\(preURL)\(code)/calculatorDisplay.json?auth=\(idToken)")!
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "PUT"
let parameters: [String: Any] = [
"field1": env.field1,
"field2": env.field2
]
request.httpBody = parameters.percentEncoded()
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data,
let response = response as? HTTPURLResponse,
error == nil else { // check for fundamental networking error
print("postCalcDataButtons error", error ?? "Unknown error")
return
}
guard (200 ... 299) ~= response.statusCode else { // check for http errors
print("postCalcDataButtons = statusCode should be 2xx, but is \(response.statusCode)")
print("postCalcDataButtons response = \(response)")
return
}
let responseString = String(data: data, encoding: .utf8)
print("postCalcDataButtons responseString = \(String(describing: responseString))")
}
task.resume()
}
Here's the extensions that make the above code work:
extension Dictionary {
func percentEncoded() -> Data? {
return map { key, value in
let escapedKey = "\(key)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
let escapedValue = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
return escapedKey + "=" + escapedValue
}
.joined(separator: "&")
.data(using: .utf8)
}
}
extension CharacterSet {
static let urlQueryValueAllowed: CharacterSet = {
let generalDelimitersToEncode = ":#[]#" // does not include "?" or "/" due to RFC 3986 - Section 3.4
let subDelimitersToEncode = "!$&'()*+,;="
var allowed = CharacterSet.urlQueryAllowed
allowed.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
return allowed
}()
}
Here's the response from the server:
<NSHTTPURLResponse: 0x60000110a0a0> { URL: https://calculonapp.firebaseio.com/zlwxrx/calculatorButtons.json?auth=authCode } { Status Code: 400, Headers {
"Access-Control-Allow-Origin" = (
"*"
);
"Cache-Control" = (
"no-cache"
);
Connection = (
"keep-alive"
);
"Content-Length" = (
77
);
"Content-Type" = (
"application/json; charset=utf-8"
);
Date = (
"Fri, 21 Aug 2020 21:16:43 GMT"
);
Server = (
nginx
);
"Strict-Transport-Security" = (
"max-age=31556926; includeSubDomains; preload"
);
} }
I was able to fix this issue by changing the http method when writing data to firebase to "PATCH", then adding JSONSerialization to encode my my upload before running the URLSession...this is the code I used:
if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []) {
URLSession.shared.uploadTask(with: request, from: jsonData) { (data, response, error) in
if let httpResponse = response as? HTTPURLResponse {
completion(httpResponse.statusCode)
}
}
.resume()
}
You can keep in the guard statements while you test to catch for http error codes and report them to you, but once my code was working I removed them.

I want to upload image to server connect with soap using SWIFT

I want to upload the image to server connect with SOAP using SWIFT
but I have to respond value from soap below
Response: Optional(<NSHTTPURLResponse: 0x281a1a780> { URL: http://xxx.xx.xx.xx/Projectervice/imageService.asmx?op=Upload } { Status Code: 400, Headers {
"Cache-Control" = (
private
);
"Content-Length" = (
0
);
"Content-Type" = (
"text/xml; charset=utf-8"
);
Date = (
"Mon, 08 Jul 2019 07:37:10 GMT"
);
Server = (
"Microsoft-IIS/8.5"
);
"X-AspNet-Version" = (
"4.0.30319"
);
"X-Powered-By" = (
"ASP.NET"
);
} })
Body: Optional()
[![image for Soap web service][1]][1]
I don't understand this response... and why the body does not have value
func uploadImageToserver(photo: String) -> Void
{
let is_URL: String = "http://xx.xx.xx.xx/Projectervice/imageService.asmx?op=Upload"
let lobj_Request = NSMutableURLRequest(url: NSURL(string: is_URL)! as URL)
let session = URLSession.shared
lobj_Request.httpMethod = "POST"
lobj_Request.httpBody = is_SoapMessage.data(using: String.Encoding.utf8)
lobj_Request.addValue("xxx.xx.xx.xx", forHTTPHeaderField: "Host")
lobj_Request.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
lobj_Request.addValue(String(is_SoapMessage.count), forHTTPHeaderField: "Content-Length")
lobj_Request.addValue("http://tempuri.org/Upload", forHTTPHeaderField: "SOAPAction")
let task = session.dataTask(with: lobj_Request as URLRequest, completionHandler: {data, response, error -> Void in
print("Response: \(String(describing: response))")
let strData = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("Body: \(String(describing: strData))")
if error != nil
{
print("Error: " + error.debugDescription)
}
})
task.resume()
}
[1]: https://i.stack.imgur.com/KBJ7T.jpg

get error 401 when post request using XMLParsing swift library

i'm testing XMLParsing library
(that use Codable protocol with XML request)
XMLParsing library link :
https://github.com/ShawnMoore/XMLParsing
with https://openweathermap.org API
the API link is
"http://api.openweathermap.org/data/2.5/weather"
my model is
struct weather:Codable {
let q : String
let appid : String
let mode : String
}
and the request is
var request = URLRequest(url: URL(string: "http://api.openweathermap.org/data/2.5/weather")!)
request.httpMethod = "POST"
let post2 = weather(q: "london", appid: "f4be702b940e5073d765cb2473f0b31b", mode: "xml")
do{
let body = try XMLEncoder().encode(post2, withRootKey: "current")
request.httpBody = body
} catch{}
let session = URLSession.shared
let task = session.dataTask(with: request) { data, response, error in
if error != nil {
print("error: \(String(describing: error))")// Handle error…
return
}
guard let data = data else {return }
print("response: \(response)")
print("data: \(data)")
}
task.resume()
I don't know where is the problem !
I always get error code 401
response: Optional(<NSHTTPURLResponse: 0x600003bdedc0> { URL: http://api.openweathermap.org/data/2.5/weather } { Status Code: 401, Headers {
"Access-Control-Allow-Credentials" = (
true
);
"Access-Control-Allow-Methods" = (
"GET, POST"
);
"Access-Control-Allow-Origin" = (
"*"
);
Connection = (
"keep-alive"
);
"Content-Length" = (
107
);
"Content-Type" = (
"application/json; charset=utf-8"
);
Date = (
"Mon, 14 Jan 2019 07:14:16 GMT"
);
Server = (
openresty
);
"X-Cache-Key" = (
"/data/2.5/weather?"
);
} })
data: 107 bytes
but on PostMan it working fine and get current data
Thanks to #OOPer
I put it as Parameters on the link and change the request to GET
it working fine now
import UIKit
import XMLParsing
struct current:Codable {
let city : City?
}
struct City:Codable {
let id : String?
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let request = URLRequest(url: URL(string: "http://api.openweathermap.org/data/2.5/weather?q=london&appid=f4be702b940e5073d765cb2473f0b31b&mode=xml")!)
let session = URLSession.shared
let task = session.dataTask(with: request) { (data, response, error) in
do{
guard (error == nil) else {
print("There is error")
return
}
guard let data = data else {return}
let newData = try XMLDecoder().decode(current.self, from: data)
print((newData.city?.id)!)
}catch let error {
print("there is error",error)
}
}
task.resume()
}
}

How to get store one specific element of a JSON post response in Swift

I have a swift program that creates a successful JSON post to a rails application. This is the response:
Optional(<NSHTTPURLResponse: 0x604000226280> { URL: http://groupsyncenv.rtimfc7m2.eu-west-1.elasticbeanstalk.com/login_post } { Status Code: 200, Headers {
"Cache-Control" = (
"max-age=0, private, must-revalidate"
);
Connection = (
close
);
"Content-Length" = (
618
);
"Content-Type" = (
"application/json; charset=utf-8"
);
Date = (
"Wed, 24 Jan 2018 17:57:52 GMT"
);
Etag = (
"W/\"c34b1ba0f3cfbd53ef65a30eddd47c50\""
);
Server = (
"nginx/1.12.1"
);
Via = (
"1.1 m00180A4E4E3C (squid/3.5.23)"
);
"X-Cache" = (
"MISS from m00180A4E4E3C"
);
"X-Cache-Lookup" = (
"MISS from m00180A4E4E3C:3128"
);
"X-Content-Type-Options" = (
nosniff
);
"X-Frame-Options" = (
SAMEORIGIN
);
"X-Request-Id" = (
"9bf3c1fa-e362-4d59-8396-8540981f1d36"
);
"X-Runtime" = (
"0.092878"
);
"X-XSS-Protection" = (
"1; mode=block"
);
All I need from this code is the number associated with the response "X-Request-Id" but I'm not sure how to do it. My swift program is below:
func loginPost(){
let headers = [
"Content-Type": "application/json",
"Cache-Control": "no-cache",
"Postman-Token": "b5468cec-292a-6c60-d195-6e270909e54b"
]
let parameters = [
"email": "sample#email.com",
"password": "password123"
] as [String : Any]
let postData = try? JSONSerialization.data(withJSONObject: parameters, options: [])
guard let data = postData else {
return
}
let request = NSMutableURLRequest(url: NSURL(string: "http://groupsyncenv.rtimfc7um2.eu-west-1.elasticbeanstalk.com/login_post")! 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()
}
As you can see I'm just printing the Http response which I know is wrong but I can't figure out how to access individual elements here. Thanks in advance for any help!
You can simply access the HTTP headers after casting the URLResponse object to HTTPURLResponse by calling response.allHeaderFields, which is a Dictionary, so you can use subscription to get the value corresponding to a specific key.
Some generic advice: don't use old Foundation data types unless you have a very good reason to do so. Use their native Swift alternatives. This is especially true when you are casting the Foundation objects to their Swift alternatives right after creating them, since the Swift APIs expect Swift types, such as URLRequest rather than NSMutableURLRequest and URL instead of NSURL.
let headers = [
"Content-Type": "application/json",
"Cache-Control": "no-cache"
]
let parameters = [
"email": "sample#email.com",
"password": "password123"
] as [String : Any]
let postData = try? JSONSerialization.data(withJSONObject: parameters, options: [])
var request = URLRequest(url: URL(string: "http://groupsyncenv.rtimfc7um2.eu-west-1.elasticbeanstalk.com/login_post")!, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData
URLSession.shared.dataTask(with: request, completionHandler: { data, response, error in
if (error != nil) {
print(error!)
} else if let response = response as? HTTPURLResponse {
let requestId = response.allHeaderFields["X-Request-Id"] as? String
print(requestId)
}
}).resume()