0

I'm looking to convert this Python request to a Swift script.

Here is my working python script that returns the accessToken!

#!/usr/bin/python

import requests
import json

#MAKE THE REQUEST
URL = "http://this/is/the/url"
headers = {
'Accept': "application/json",
"Accept-Language": "en_US"
}
data = {
    "grant_type": "password",
    "username" : "GROUP\SITE\USERNAME",
    "password" : "somepassword"
}
r = requests.get(url = URL, params = headers, data = data)
data = r.json()



accessToken = data['access_token']
print(accessToken)

When I run the Swift Playground for the code below nothing is returned! It seems the script exits at guard let data = data else { return }

How could I get the same results as the Python Script above. I've tried implementing URLComponents using this tutorial...

import UIKit

var url = "http://just/the/url"
extension Dictionary {
    func percentEncoded() -> Data? {
        return map { key, value in
            let escapedKey = "\(key)"
            let escapedValue = "\(value)"
            print(escapedKey + "=" + escapedValue)
            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
    }()
}

var request = URLRequest(url: URL(string:url)!)
   request.httpMethod = "GET"
let parameters: [String: String] = [
    "grant_type":"password",
    "username":"GROUP\\SITE\\USER",
    "password":"somePassword"
]
   request.httpBody = parameters.percentEncoded()
   request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
   request.setValue("application/XML", forHTTPHeaderField: "Accept")

let config = URLSessionConfiguration.default
    URLSession(configuration: config).dataTask(with: request) { (data, response, err) in

       guard let data = data else { return }
        print(data)
       guard let dataAsString = String(data: data, encoding: .utf8)else {return}
     print(dataAsString)

       guard let httpResponse = response as? HTTPURLResponse,
             (200...299).contains(httpResponse.statusCode) else {
           print("Bad Credentials")
           return
       }

       //HTTP Status Code!
        print("HTTP RESPONSE:"+"\(httpResponse.statusCode)")
//
           }.resume()
Mdoyle1
  • 121
  • 1
  • 12
  • 2
    You're over-writing `allHTTPHeaderFields` 3 times... You're going to want to set it once, with a dictioanry containing all 3 header key/values. – Alexander Mar 03 '20 at 18:43
  • OK,I've updated the above code, I'm still getting {"error":"unsupported_grant_type"} – Mdoyle1 Mar 03 '20 at 19:17
  • 1
    In the python script the grant_type, password, username are passed in the data not headers. Do they need to be sent as the body or url encoded in your URLRequest? – valosip Mar 03 '20 at 20:14
  • Yes @valosip check out the updated swift playground. Now nothing is being returned. – Mdoyle1 Mar 04 '20 at 02:21
  • @Mdoyle1 Is this a private api or a public third party api that you're trying to integrate with? – valosip Mar 04 '20 at 02:39
  • @VALOSIP private api, thanks for the help... I was able to find a solution. – Mdoyle1 Mar 04 '20 at 14:09

2 Answers2

1

If I remember correctly, starting in iOS 13, you cant have httpBody for a GET call, so you'll either need to switch to a POST/PUT or add the params into the url string (See below) You also had different Accept headers in your python vs. swift. One was xml the other was json.

var urlComponents = URLComponents(string: "http://this/is/the/url")
urlComponents?.queryItems = [
    URLQueryItem(name: "grant_type", value: "password"),
    URLQueryItem(name: "username", value: "username"),
    URLQueryItem(name: "password", value: "somepassword")
]

guard let url = urlComponents?.url else { return } // You can print url here to see how it looks
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("en_US", forHTTPHeaderField: "Accept-Language")

let task = URLSession.shared.dataTask(with: request) { data, response, error in
        guard let data = data,
            let response = response as? HTTPURLResponse,
            error == nil else {
            print("error", error ?? "Unknown error")
            return
        }
        print(response)
        guard (200 ... 299) ~= response.statusCode else {
            print("response = \(response)")
            return
        }

        let responseString = String(data: data, encoding: .utf8)
        print(responseString)
    }
    task.resume()
valosip
  • 3,167
  • 1
  • 14
  • 26
0

The problem was the following...

 request.httpMethod = "GET"

I had to change the get to "POST" and now I have the token!!!! I was confused because the python script used GET. I had a bash script that that used curl to get the token displayed the logged post.

In short my above Swift Playground now works by changing the request.httpMethod to "POST". THANKS FOR ALL THE HELP

Mdoyle1
  • 121
  • 1
  • 12