Consumo de servicios
Ejemplo completo
let baseURLComponents = URLComponents(string: "https://example.com")
func request(_ method: String, path: String, body: Data?, authToken: String?, successHandler: dataHandler?) {
var requestURLComponents = baseURLComponents
requestURLComponents.path = path
var request = URLRequest(url: requestURLComponents.url!)
request.httpMethod = method
request.httpBody = body
if let token = authToken {
request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
}
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil { return }
let httpResponse = response as! HTTPURLResponse
if httpResponse.statusCode == 200, let handler = successHandler {
handler(data)
}
}
task.resume()
}
URLSession
La clase URLSession y las clases relacionadas proporcionan una API para descargar contenido. Esta API proporciona un amplio conjunto de métodos delegados para admitir la autenticación y le da a su aplicación la capacidad de realizar descargas en segundo plano.
Ejemplo
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
...
}
task.resume()
Tipos de URLSession
URLSession cuenta con una sesión shared singleton (que no tiene ningún objeto de configuración) para requests básicos. No es tan configurable, pero sirve como punto de partida con requisitos muy limitados. Para otros tipos de sesiones, crea una instancia de URLSession con uno de tres tipos de configuraciones:
- default similar a shared, pero permite más configuración y le permite obtener datos de forma incremental con un delegado.
- Ephemeral similar a shared, pero sin cache, cookies o credenciales en el disco.
- Background permite realizar downloads y uploads de contenido en segundo plano mientras su aplicación no se está ejecutando.
Tipos de URLSessionTask
Dentro de una sesión, usted crea tareas que opcionalmente cargan datos en un servidor y luego recuperan datos del servidor como un archivo en disco o como uno o más objetos NSData en la memoria. La API de URLSession proporciona tres tipos de tareas:
- DataTask envían y reciben datos utilizando objetos NSData. Las tareas de datos están destinadas a solicitudes cortas, a menudo interactivas, a un servidor.
- UploadTask son similares a las DataTask, pero también envían datos (a menudo en forma de un archivo) y admiten cargas de fondo mientras la aplicación no se está ejecutando.
- DownloadTask recuperan datos en forma de un archivo y admiten descargas y cargas de fondo mientras la aplicación no se está ejecutando.
URLComponents
Es una estructura que parsea URLS y construlle URLs a partir de sus componentes.
URLComponents
port
el puerto como Stringquery
el query como StringqueryItmes
el query representado como un Array de URLQueryItem
Ejemplo
var components = URLComponents()
components.scheme = "https"
components.host = "example.com"
components.path = "/api/path"
components.url
URLRequest
Encapsula dos elementos basicos al cargar un request: la URL y la politica de cache a usar mientras consulta el contenido de la URL.
URLRequest
httpMethod
es un attributo String de URLRequest que debe conformar cualquier metodo del protocolo de http: GET, POST, PUT, PATCH, DELETE, HEADER, OPTIONShttpBody
es un atributo Data que contiene el contenido del cuerpo
Ejemplo
var request = URLRequest(url: URL(string: "https://example.com"))
request.httpMethod = "GET"
request.httpBody = body
request.addValue("Bearer secrettoken123", forHTTPHeaderField: "Authorization")
Request body
Todo objeto que puede ser casteado a Data puede añadirse a un request httpBody
Texto plano
request.httpBody = "Lorem ipsum dolor sit amet".data(using: .utf8)!
JSON con Codable
request.httpBody = try? JSONEncoder().encode(<Compliant with Encodable Protocol>)
Multipart
Extend Data para agregar strings
extension Data {
mutating func append(string: String) {
if let data = string.data(using: .utf8) {
append(data)
}
}
}
Establecer boundary(limite) en el header de Contet-Type
let boundary = NSUUID().uuidString // the boundary act as a separator per field
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
Construir el cuerpo multipart para una imagen
class func multipartImage(data imageData: Data, boundary: String, fileName: String) -> Data {
var bodyData = Data()
// 1 - Data should start with boundary
bodyData.append(string: "--\(boundary)\r\n")
// 2 - image png format for avatar field
bodyData.append(string: "Content-Disposition: form-data; name=\"avatar\"; filename=\"\(fileName)\"\r\n")
bodyData.append(string: "Content-Type: image/png\r\n\r\n")
bodyData.append(imageData)
bodyData.append(string: "\r\n")
// 3 - Data should end with boundary
bodyData.append(string: "--\(boundary)--\r\n")
return bodyData
}
Asignar httpBody con multipart
let image = UIImage(named: "tacocat")!
let imageData = UIImagePNGRepresentation(image)! // transforms the PNG image into the binary
let multipartData = multipartBody(data: imageData, boundary: boundary, fileName: "tacocat.png")
// multipart requires content length
req.setValue("\(multipartData.count)", forHTTPHeaderField: "Content-Length")
req.httpBody = multipartData
// END multipart construction