How to Make Http Request in Swift

How to make HTTP request in Swift?

You can use URL, URLRequest and URLSession or NSURLConnection as you'd normally do in Objective-C. Note that for iOS 7.0 and later, URLSession is preferred.

Using URLSession

Initialize a URL object and a URLSessionDataTask from URLSession. Then run the task with resume().

let url = URL(string: "http://www.stackoverflow.com")!

let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else { return }
print(String(data: data, encoding: .utf8)!)
}

task.resume()

Using NSURLConnection

First, initialize a URL and a URLRequest:

let url = URL(string: "http://www.stackoverflow.com")!
var request = URLRequest(url: url)
request.httpMethod = "POST"

Then, you can load the request asynchronously with:

NSURLConnection.sendAsynchronousRequest(request, queue: OperationQueue.main) {(response, data, error) in
guard let data = data else { return }
print(String(data: data, encoding: .utf8)!)
}

Or you can initialize an NSURLConnection:

let connection = NSURLConnection(request: request, delegate:nil, startImmediately: true)

Just make sure to set your delegate to something other than nil and use the delegate methods to work with the response and data received.

For more detail, check the documentation for the NSURLConnectionDataDelegate protocol

Testing on an Xcode playground

If you want to try this code on a Xcode playground, add import PlaygroundSupport to your playground, as well as the following call:

PlaygroundPage.current.needsIndefiniteExecution = true

This will allow you to use asynchronous code in playgrounds.

Making HTTP GET request with Swift 5

Right now, if there is an error, you are going to silently fail. So add some error logging, e.g.,

func httpRequest() {
let url = URL(string: "https://www.stackoverflow.com")! // note, https, not http

let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard
error == nil,
let data = data,
let string = String(data: data, encoding: .utf8)
else {
print(error ?? "Unknown error")
return
}

print(string)
}
task.resume()
}

That should at least give you some indication of the problem.

A few other considerations:

  1. If command line app, you have to recognize that the app may quit before this asynchronous network request finishes. One would generally start up a RunLoop, looping with run(mode:before:) until the network request finishes, as advised in the run documentation.

    For example, you might give that routine a completion handler that will be called on the main thread when it is done. Then you can use that:

    func httpRequest(completion: @escaping () -> Void) {
    let url = URL(string: "https://www.stackoverflow.com")! // note, https, not http

    let task = URLSession.shared.dataTask(with: url) { data, response, error in
    defer {
    DispatchQueue.main.async {
    completion()
    }
    }

    guard
    error == nil,
    let data = data,
    let string = String(data: data, encoding: .utf8)
    else {
    print(error ?? "Unknown error")
    return
    }

    print(string)
    }
    task.resume()
    }

    var finished = false

    httpRequest {
    finished = true
    }

    while !finished {
    RunLoop.current.run(mode: .default, before: .distantFuture)
    }
  2. In standard macOS apps, you have to enable outgoing (client) connections in the “App Sandbox” capabilities.

  3. If playground, you have to set needsIndefiniteExecution.

  4. By default, macOS and iOS apps disable http requests unless you enable "Allow Arbitrary Loads” in your Info.plist. That is not applicable to command line apps, but you should be aware of that should you try to do this in standard macOS/iOS apps.

    In this case, you should just use https and avoid that consideration altogether.

Swift 5, make http post request

Below is the code for Post Method,using URLSession

let Url = String(format: "http://10.10.10.53:8080/sahambl/rest/sahamblsrv/userlogin")
guard let serviceUrl = URL(string: Url) else { return }
let parameters: [String: Any] = [
"request": [
"xusercode" : "YOUR USERCODE HERE",
"xpassword": "YOUR PASSWORD HERE"
]
]
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else {
return
}
request.httpBody = httpBody
request.timeoutInterval = 20
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()
}

How can I make a http request on swift with authentication?

Here you go you just need to add the header for Authorization


Use Codable for JSON parsing don't use JSONSerialization and use this tool for converting the Json to the struct

let url = URL(string: "http://209.97.133.56/api/ucs")!
let token = "your token"
var request = URLRequest(url: url)
request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.httpMethod = "GET"


URLSession.shared.dataTask(with: request) { (data, response , error) in
guard let data = data else { return }
print(String(data: data, encoding: .utf8) ?? "Invalid JSON")
}.resume()

Edit

Use the tool that I have give to convert your json to the struct, JSON converted by the tool

struct UPS: Codable {
let data: [UPSData]

enum CodingKeys: String, CodingKey {
case data = "data"
}
}

struct UPSData: Codable {
let id: String
let unidadeCurricularID: Int
let unidadeCurricularNome: String
let unidadeCurricularAbreviatura: String
let unidadeCurricularAtivo: Int
let unidadeCurricularIDMapSiges: Int
let anoCurricularID: Int
let anoCurricularNome: String
let anoCurricularAbreviatura: String?
let anoCurricularAtivo: Int
let anoCurricularIDMapSiges: Int
let periodoTempoID: Int
let periodoTempoNome: String
let periodoTempoAvreviatura: String
let periodoTempoOrdem: Int
let periodoTempoAtivo: Int
let periodoTempoIDMapSiges: String
let numeroEstudante: Int
let idAnoLetivo: Int
let idUnidadeCurricular: Int
let idEstadoInscricao: Int
let idAnoCurricular: Int
let numeroCreditos: Int

enum CodingKeys: String, CodingKey {
case id = "id"
case unidadeCurricularID = "unidadeCurricularId"
case unidadeCurricularNome = "unidadeCurricularNome"
case unidadeCurricularAbreviatura = "unidadeCurricularAbreviatura"
case unidadeCurricularAtivo = "unidadeCurricularAtivo"
case unidadeCurricularIDMapSiges = "unidadeCurricularIdMapSiges"
case anoCurricularID = "anoCurricularId"
case anoCurricularNome = "anoCurricularNome"
case anoCurricularAbreviatura = "anoCurricularAbreviatura"
case anoCurricularAtivo = "anoCurricularAtivo"
case anoCurricularIDMapSiges = "anoCurricularIdMapSiges"
case periodoTempoID = "periodoTempoId"
case periodoTempoNome = "periodoTempoNome"
case periodoTempoAvreviatura = "periodoTempoAvreviatura"
case periodoTempoOrdem = "periodoTempoOrdem"
case periodoTempoAtivo = "periodoTempoAtivo"
case periodoTempoIDMapSiges = "periodoTempoIdMapSiges"
case numeroEstudante = "numeroEstudante"
case idAnoLetivo = "idAnoLetivo"
case idUnidadeCurricular = "idUnidadeCurricular"
case idEstadoInscricao = "idEstadoInscricao"
case idAnoCurricular = "idAnoCurricular"
case numeroCreditos = "numero_creditos"
}
}

Add all of your network request code in this class

class NetworkRequest {


func auth<T: Decodable>(with url: URL, token: String, completion: @escaping (T) -> Void) {

var request = URLRequest(url: url)
request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.httpMethod = "GET"

URLSession.shared.dataTask(with: request) { (data, response , error) in
guard let data = data else { return }
do {
completion(try JSONDecoder().decode(T.self, from: data))
} catch let error {
print(error)
}
}.resume()

}


}

use this code any where in your class

NetworkRequest().auth(with: url, token: token) { (ups: UPS) in
print("do what do want to you")
}

How to build Http Request with IP address in Swift?(Moya)

var baseURL: URL = URL(string: "http://github.com/apple/swift")

try this ?

HTTP Request in Swift with POST method

The key is that you want to:

  • set the httpMethod to POST;
  • optionally, set the Content-Type header, to specify how the request body was encoded, in case server might accept different types of requests;
  • optionally, set the Accept header, to request how the response body should be encoded, in case the server might generate different types of responses; and
  • set the httpBody to be properly encoded for the specific Content-Type; e.g. if application/x-www-form-urlencoded request, we need to percent-encode the body of the request.

E.g., in Swift 3 and later you can:

let url = URL(string: "https://httpbin.org/post")!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.httpMethod = "POST"
let parameters: [String: Any] = [
"id": 13,
"name": "Jack & Jill"
]
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("error", error ?? URLError(.badServerResponse))
return
}

guard (200 ... 299) ~= response.statusCode else { // check for http errors
print("statusCode should be 2xx, but is \(response.statusCode)")
print("response = \(response)")
return
}

// do whatever you want with the `data`, e.g.:

do {
let responseObject = try JSONDecoder().decode(ResponseObject<Foo>.self, from: data)
print(responseObject)
} catch {
print(error) // parsing error

if let responseString = String(data: data, encoding: .utf8) {
print("responseString = \(responseString)")
} else {
print("unable to parse response as string")
}
}
}

task.resume()

Where the following extensions facilitate the percent-encoding request body, converting a Swift Dictionary to a application/x-www-form-urlencoded formatted Data:

extension Dictionary {
func percentEncoded() -> Data? {
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
}()
}

And the following Decodable model objects facilitate the parsing of the application/json response using JSONDecoder:

// sample Decodable objects for https://httpbin.org

struct ResponseObject<T: Decodable>: Decodable {
let form: T // often the top level key is `data`, but in the case of https://httpbin.org, it echos the submission under the key `form`
}

struct Foo: Decodable {
let id: String
let name: String
}

This checks for both fundamental networking errors as well as high-level HTTP errors. This also properly percent escapes the parameters of the query.

Note, I used a name of Jack & Jill, to illustrate the proper x-www-form-urlencoded result of name=Jack%20%26%20Jill, which is “percent encoded” (i.e. the space is replaced with %20 and the & in the value is replaced with %26).


See previous revision of this answer for Swift 2 rendition.

HTTP Requests in Swift 3

There are a couple problems with your code:

  1. By default, your app cannot connect to insecure (i.e. HTTP) site. It's a feature called App Transport Security. You need to make an exception in your app's Info.plist file to connect to HTTP sites.
  2. This: dataTask(urlwith: ! as URL). What are you trying to unwrap with the exclamation mark (!)? What's the variable name?

A lot of class names have changed between Swift 2 and 3 so those answers you've found may not be applicable. Below is an example that connects to httpbin.org to get your IP address:

import PlaygroundSupport
import Foundation

let url = URL(string: "https://httpbin.org/ip")

let task = URLSession.shared.dataTask(with: url!) { data, response, error in
guard error == nil else {
print(error!)
return
}
guard let data = data else {
print("Data is empty")
return
}

let json = try! JSONSerialization.jsonObject(with: data, options: [])
print(json)
}

task.resume()
PlaygroundPage.current.needsIndefiniteExecution = true


Related Topics



Leave a reply



Submit