Swift GET request with parameters
When building a GET
request, there is no body to the request, but rather everything goes on the URL. To build a URL (and properly percent escaping it), you can also use URLComponents
.
var url = URLComponents(string: "https://www.google.com/search/")!
url.queryItems = [
URLQueryItem(name: "q", value: "War & Peace")
]
The only trick is that most web services need +
character percent escaped (because they'll interpret that as a space character as dictated by the application/x-www-form-urlencoded
specification). But URLComponents
will not percent escape it. Apple contends that +
is a valid character in a query and therefore shouldn't be escaped. Technically, they are correct, that it is allowed in a query of a URI, but it has a special meaning in application/x-www-form-urlencoded
requests and really should not be passed unescaped.
Apple acknowledges that we have to percent escaping the +
characters, but advises that we do it manually:
var url = URLComponents(string: "https://www.wolframalpha.com/input/")!
url.queryItems = [
URLQueryItem(name: "i", value: "1+2")
]
url.percentEncodedQuery = url.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B")
This is an inelegant work-around, but it works, and is what Apple advises if your queries may include a +
character and you have a server that interprets them as spaces.
So, combining that with your sendRequest
routine, you end up with something like:
func sendRequest(_ url: String, parameters: [String: String], completion: @escaping ([String: Any]?, Error?) -> Void) {
var components = URLComponents(string: url)!
components.queryItems = parameters.map { (key, value) in
URLQueryItem(name: key, value: value)
}
components.percentEncodedQuery = components.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B")
let request = URLRequest(url: components.url!)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard
let data = data, // is there data
let response = response as? HTTPURLResponse, // is there HTTP response
200 ..< 300 ~= response.statusCode, // is statusCode 2XX
error == nil // was there no error
else {
completion(nil, error)
return
}
let responseObject = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any]
completion(responseObject, nil)
}
task.resume()
}
And you'd call it like:
sendRequest("someurl", parameters: ["foo": "bar"]) { responseObject, error in
guard let responseObject = responseObject, error == nil else {
print(error ?? "Unknown error")
return
}
// use `responseObject` here
}
Personally, I'd use JSONDecoder
nowadays and return a custom struct
rather than a dictionary, but that's not really relevant here. Hopefully this illustrates the basic idea of how to percent encode the parameters into the URL of a GET request.
See previous revision of this answer for Swift 2 and manual percent escaping renditions.
Swift GET request with url parameters
First off, you're doing a lot more work than is probably necessary. You're encoding your query string parameters into URLComponents
which is correct. Then, in your send you are decomposing your URL and parsing out the components then re-encoding them. You're also doing a lot of force-unwrapping, which is fragile and hides problems.
Here's your code simplified in a playground that works for me:
import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let sampleURL = "https://someserver.com/somepath"
func sendRequest(_ url: URL, completion: @escaping ([String: Any]?, Error?) -> Void) {
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, // is there data
let response = response as? HTTPURLResponse, // is there HTTP response
(200 ..< 300) ~= response.statusCode, // is statusCode 2XX
error == nil else { // was there no error, otherwise ...
completion(nil, error)
return
}
let responseObject = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any]
completion(responseObject, nil)
}
task.resume()
}
var urlComponents: URLComponents? {
let resultID = "resultID123"
let resultResponseID = "responseID456"
let questionIndex = "questionNumbers1"
var urlComponents = URLComponents(string: sampleURL)
urlComponents?.queryItems = [
URLQueryItem(name: "surveyResultsId", value: "\(String(describing: resultID))"),
URLQueryItem(name: "surveyResultsResponseId", value: "\(String(describing: resultResponseID))"),
URLQueryItem(name: "questions", value: "\(questionIndex)"),
URLQueryItem(name: "selectedAnswer", value: "\("storedAnswer1")")
]
return urlComponents
}
if let urlComponents = urlComponents, let url = urlComponents.url?.absoluteURL {
sendRequest(url) { (result, error) in
print("Got an answer: \(String(describing: result))")
}
}
When I run this against a server URL that returns valid JSON, I get:
Got an answer: Optional(["image": {
href = "https://example.com";
}, "object_types": {
card = {
fields = {
};
pollable = 1;
};
}])
GET request with parameters
Example how to use URLQueryItem
for the requests.
func getRequest(params: [String:String]) {
let urlComp = NSURLComponents(string: "https://my-side.com/data")!
var items = [URLQueryItem]()
for (key,value) in params {
items.append(URLQueryItem(name: key, value: value))
}
items = items.filter{!$0.name.isEmpty}
if !items.isEmpty {
urlComp.queryItems = items
}
var urlRequest = URLRequest(url: urlComp.url!)
urlRequest.httpMethod = "GET"
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) in
})
task.resume()
}
getRequest(params: ["token": "AS7F87SAD84889AD"])
(iOS/Swift) Simple GET Request with Path Variables Params
In Params tab, there is 'Path Variable' with an "id" key and a value
This means you can replace this :/id
with your actual id value in url.
func getRequestAPICall() {
let apiUrl : String = "your_server_url" + "/" + "yourIdValueHere"
Alamofire.request(apiUrl, method: .get, encoding: JSONEncoding.default)
.responseJSON { response in
print(response)
}
}
How to send Dictionary as parameter to the Get Request Swift
You can use URLComponents for this, URLComponents is defined in Foundation.
var components = URLComponents()
components.scheme = "http"
components.host = "ctesterst.net"
components.path = "/api/Customers/homeData"
let queryItemLat = URLQueryItem(name: "lat", value: "12.456")
let queryItemLong = URLQueryItem(name: "lng", value: "76.786")
let queryItemAppVersion = URLQueryItem(name: "current_app_version", value: "123")
let queryItemDevice = URLQueryItem(name: "current_device", value: "something")
let queryItemToken = URLQueryItem(name: "access_token", value: "Km3R2AbU0yzAcVkp9BCxmCmaoC5k20fBiQxfLhIBIAolwJGgYw5w5E8X0NZzlDh8")
components.queryItems = [queryItemLat, queryItemLong,queryItemAppVersion,queryItemDevice,queryItemToken]
print(components.url)
Passing an array of parameters as a request body in swift
Try do like this
func marcaAgua(parameters: [String: Any],
completion: @escaping (Result<[MarcaAguaResData], Error>)-> Void) {
let urlString = baseUrl + "events"
guard let url = URL(string: urlString) else {
completion(.failure(NetworkingError.badUrl))
return
}
var request = URLRequest(url: url)
request.httpBody = try? JSONSerialization.data(withJSONObject: parameters)
request.httpMethod = "POST"
request.setValue("Bearer \(token_login)", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let session = URLSession.shared
let task = session.dataTask(with: request) { (data, response, error) in
DispatchQueue.main.async {
guard let unwrappedResponse = response as? HTTPURLResponse else {
completion(.failure(NetworkingError.badResponse))
return
}
switch unwrappedResponse.statusCode {
case 200 ..< 300:
print("success")
default:
print("failure")
}
if let unwrappedError = error {
completion(.failure(unwrappedError))
return
}
if let unwrappedData = data {
do{
let json = try JSONSerialization.jsonObject(with: unwrappedData, options:.allowFragments)
if let successRes = try? JSONDecoder().decode([MarcaAguaResData].self, from: unwrappedData){
completion(.success(successRes))
}else{
let errorResponse = try JSONDecoder().decode([MarcaAguaErrorResponse].self, from: unwrappedData)
completion(.failure(errorResponse as! Error))
}
}catch{
completion(.failure(error))
}
}
}
}
task.resume()
}
Related Topics
Zooming Mkmapview to Fit Annotation Pins
How to Customize the Background Color of a Uitableviewcell
Getting a List of Files in a Directory With a Glob
Move a View Up Only When the Keyboard Covers an Input Field
Fade/Dissolve When Changing Uiimageview'S Image
Detect Current Device With Ui_User_Interface_Idiom() in Swift
Sqlite File Location Core Data
Converting Escaped Utf8 Characters Back to Their Original Form
Error: Error Installing Cocoapods: Error: Failed to Build Gem Native Extension
Nsinternalinconsistencyexception', Reason: 'Could Not Load Nib in Bundle: 'Nsbundle
Delete Keychain Items When an App Is Uninstalled
Looping a Video With Avfoundation Avplayer
How to Play a Local Video With Swift
Enabling Auto Layout in iOS 6 While Remaining Backwards Compatible With iOS 5
Cgcontextdrawimage Draws Image Upside Down When Passed Uiimage.Cgimage
iOS (Iphone, iPad, Ipodtouch) View Real-Time Console Log Terminal