How to parse URL # fragments with query items in Swift - swift

Query parameters sometimes get passed as URL fragments instead of query parameters - e.g. during OAuth flows to provide client-only access to parameters.
What's the simplest way to parse a URL like:
https://example.com/auth-callback#access_token=mytoken&expires_in=36000&scope=zap+profile
into key values for:
access_token, expires_in, scope

Simply pass the fragment property as a query string to a new URLComponent and read the parsed query objects:
let url = URL(string: "https://example.com/auth-callback#access_token=mytoken&expires_in=36000&scope=zap+profile")
var components = URLComponents()
components.query = url.fragment
for item in components.queryItems! {
print("\(item.name): \(item.value)")
}

Related

Swfit URLRequest POST How to make a request with duplicated parameter keys

I'm currently working on a project which uses Inoreader APIs, and there is one required post request with duplicated parameter keys.
https://www.inoreader.com/reader/api/0/edit-tag?a=user/-/state/com.google/read&i=12345678&i=12345679
As you can see duplicated i parameters. I've tried below to set httpBody of URLRequest, failed silently.
var parameters = [String: Any]()
parameters["i"] = idArray
parameters["a"] = "user/-/state/com.google/read"
let jsonData = try JSONSerialization.data(withJSONObject: parameters, options: [])
request.httpBody = jsonData
// I omitted other codes for simplicity
Then I've tried to chain every element of idArray with "&i=", assigned it to parameters["i"], also failed silently.
// chainedID was something like 123&i=456&i=789, to make it looks like as url example given by documentation
parameters["i"] = chainedID
How can I do that? This API is working perfectly with one item, but I can't get it work on multiple items. It claims will work with multiple items.
Based on the example that you posted and the ones that the documentation mentions, although the request is POST can accept parameters in the URL's query.
So, the solution would be to compose your request using URLComponents:
var components = URLComponents(string: "https://www.inoreader.com/reader/api/0/edit-tag")
var queryItems = [
URLQueryItem(name: "a", value: "user/-/state/com.google/read")
]
idArray.forEach {
queryItems.append(URLQueryItem(name: "i", value: $0))
}
components?.queryItems = queryItems
guard let url = components?.url else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
and not use JSON parameters in the request's body.

Is there a way to use Foursquare's API to search including category ID and price parameter?

I'm trying to use the Foursquare API to search, but specify both category ID's and a price. Using the request GET https://api.foursquare.com/v2/venues/explore I can specify a price but not category ID's, however I can enter a query - which makes me wonder, what exactly does the query parameter do?
If I use the request GET https://api.foursquare.com/v2/venues/search I can specify category IDs, however I can't specify a price parameter.
Finally, I'm using Swift with the pods FoursquareAPI & SwiftyJSON so my relevant code looks something like this:
func getObject(limit: Int, category: String){
let client = FoursquareAPIClient(clientId: "JMBLK0SDZ0N2NF5TG3UCLMOF4FA5FKA14AIOZ4P4TS4MHEWO", clientSecret: "<my client secret>")
let parameter: [String: String] = [
"near": destination!,
"limit": "1",
"query": category!,
"price": String(describing: budget!),
];
client.request(path: "venues/explore", parameter: parameter) { result in
switch result {
case let .success(data):
print("Success")
guard let json = try? JSON(data: data) else{
print("\(#function): Unable to retrieve json object")
return
}
if json["meta"]["code"] == 200{
self.parse(jsonObject: json)
}
case let .failure(error):
// Error handling
switch error {
case let .connectionError(connectionError):
print(connectionError)
case let .responseParseError(responseParseError):
print(responseParseError) // e.g. JSON text did not start with array or object and option to allow fragments not set.
case let .apiError(apiError):
print(apiError.errorType) // e.g. endpoint_error
print(apiError.errorDetail) // e.g. The requested path does not exist.
}
}//end switch
}//end client.request
}
It appears there are two options:
Use /explore endpoint, with the price, and section params, where section is one of - food, drinks, coffee, shops, arts, outdoors, sights, etc
Use /explore endpoint, with the price and query params, where query is a string matching the Foursquare category name
In my limited tests, this 2nd option produced decent results. For example, a GET request to:
api.foursquare.com/v2/venues/explore?near=SOME,%20LOCATION&price=3&query=Deli%20/%20Bodega
// client_id, client_secret, and v params will all be needed as well
returns venues in the 3 price range, and only venues in the "Deli / Bodega" category.
Similar searches for the "Coffee Shop" category produced relevant results.
To anyone reading this thread, I've found a better solution than Brett's:
The /search/recommendations endpoint. I guess it's new so it's not listed with the other API docs, but it allows the specification of categories, price, as well as localTime and localDay which allow you to specify venues that are open at a specific time.
There are many other cool parameters, such as features which I believe are exclusive to this endpoint, and it's worthwhile to check out.

Delete parameter from URL with swift

I have an URL that looks like myapp://jhb/test/deeplink/url?id=4567 .
I want to delete every thing after the ? char. At the end the URL should look like myapp://jhb/test/deeplink/url. how. can I achieve that? convert the url to a string? Regex?
Use URLComponents to separate the different URL parts, manipulate them and then extract the new url:
var components = URLComponents(string: "myapp://jhb/test/deeplink/url?id=4567")!
components.query = nil
print(components.url!)
myapp://jhb/test/deeplink/url
A convenient extension on URL
private extension URL {
var removingQueries: URL {
if var components = URLComponents(string: absoluteString) {
components.query = nil
return components.url ?? self
} else {
return self
}
}
}
can I achieve that? convert the url to a string? Regex?
When working with URLs, it would be better to treat it as URLComponent:
A structure that parses URLs into and constructs URLs from their
constituent parts.
therefore, referring to URLComponent what are you asking is to remove the the query subcomponent from the url:
if var componenets = URLComponents(string: "myapp://jhb/test/deeplink/url?id=4567") {
componenets.query = nil
print(componenets) // myapp://jhb/test/deeplink/url
}
Note that query is an optional string, which means it could be nil (as mentioned in the code snippet, which should leads to your desired output).
You can do like this
let values = utl?.components(separatedBy: "?")[0]
It will break the string with ? and return the array.
The first object of values give you your resultant string.
You can get each URL component separated from URl using
print("\(url.host!)") //Domain name
print("\(url.path)") // Path
print("\(url.query)") // query string

How to make an HTTP GET Request with Parameters. SwiftyJSON Swift

Below mentioned snippet is working just fine. It queries JSON data. I just want to know how can I pass parameters with this.
let filePath = NSURL(string: "http://localhost:2403/postedjob")
let jsonData = NSData(contentsOfURL:filePath!)
let json = JSON(data: jsonData!, options: NSJSONReadingOptions.AllowFragments, error: nil)
I want to pass this parameters:
let params = ["$limit": 2, "$sort": ["id":"+1"]] as Dictionary<String, AnyObject>
Alamofire may be a good option for you to pass the parameters.
https://github.com/Alamofire/Alamofire
For a GET request pass parameters in the query string (the part after the "?" mark).
For a POST request parameters can be sent in the body in a number of ways. Raw data, form data and JSON among other methods.
Of course the server has to match the method used.

Send a [[String:AnyObject]] using SwiftyJSON

I am requesting to an API using SwiftyJSON. I want to pass a value to a key which is in [[String: AnyObject]]:
var params = [String: AnyObject]()
parameters["paymentOptions"] = [["billingId": 1]]
So, directly passing it like this and making a request gave no response. So, I tried it like this:
var params = [String: AnyObject]()
parameters["paymentOptions"] = "\([["billingId": 1]])"
This gives an error from the API. I think I am doing something wrong here. How should I be sending the array?
This is how I make a request.
request(.POST, pathUrl, parameters: params)