Пример HTTP POST запроса в Swift

В этом уроке, вы изучите как отправлять HTTP POST запрос в Swift и как читать HTTP ответ и тело ответа. Этот урок включает в себя:

  • Отправка HTTP POST запрос
  • Конверкация параметров Query строки в JSON
  • Rонвертация структуры Swift в JSON
  • Установка хедеров HTTP запроса
  • Чтение HTTP ответа
  • Чтение HTTP хедеров ответа
  • Чтение HTTP тела ответа как строки
  • Чтение HTTP тела ответа как JSON

Чтобы узнать как отправить HTTP GET запрос пожалуйста прочтите урок: HTTP GET Request Example in Swift или переведенную версию

Общедоступный веб сервис RESTful

В этом уроке, вы увидите общедоступный и бесплатный на момент написания этого урока веб сервис RESTful: https://jsonplaceholder.typicode.com. Это сервис позволяет мне отправлять HTTP запросы на него и получать обратно JSON ответ. На пример, если вы откроете URL в браузере: https://jsonplaceholder.typicode.com/todos/1 вы получите следующий JSON документ:

{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

Я так же могу отправить HTTP POST запрос на https://jsonplaceholder.typicode.com/todos и получить обратно созданную запись. На пример, если послать HTTP POST запрос содержащий JSON с полезными данными в теле запроса:

{
  "userId": 300,
  "title": "delectus aut autem",
  "completed": false
}

То мы получим обратно ответ похожий на этот:

{
  "userId": "300",
  "title": "My urgent task",
  "completed": "false",
  "id": 201
}

Итак давай те попробуем посмотреть как это работает в Swift.

Отправка HTTP POST запроса

Ниже очень простой пример того как вы можете отправить HTTP POST запрос в Swift. Пожалуйста обратите внимание на комментарии в коде.

// Prepare URL 
let url = URL(string: "https://jsonplaceholder.typicode.com/todos")
guard let requestUrl = url else { fatalError() }
// Prepare URL Request Object
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
 
// HTTP Request Parameters which will be sent in HTTP Request Body 
let postString = "userId=300&title=My urgent task&completed=false";
// Set HTTP Request Body
request.httpBody = postString.data(using: String.Encoding.utf8);
// Perform HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
        
        // Check for Error 
        if let error = error {
            print("Error took place \(error)")
            return
        }
 
        // Convert HTTP Response Data to a String
        if let data = data, let dataString = String(data: data, encoding: .utf8) {
            print("Response data string:\n \(dataString)")
        }
}
task.resume()

Пожалуйста обратите как в этом фрагменте кода мы конвертируем объект Даты в строку. Результат HTTP POST запроса приведен ниже, он должен вывести следующую JSON строку:

{
  "userId": "300",
  "title": "My urgent task",
  "completed": "false",
  "id": 201
}

Ниже здесь как выглядит код в моем Xcode плейграунде:

Установка хедеров HTTP запроса

Если ваш запрос HTTP должен содержать конкретные хедеры HTTP запроса, тогда ниже приведен привет как вы можете это сделать.

var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
// Set HTTP Request Header
request.setValue("application/json", forHTTPHeaderField: "Accept")

Вы можете указать больше чем один хедер

request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")

Чтение хедеров HTTP ответа

Как только вы получили HTTP ответ, вы можете читать все хедеры из ответа HTTP из HTTPURLResponse объекта

Чтение всех хедеров

let allHeaderFields:[AnyHashable : Any] = response.allHeaderFields
print("All headers: \(allHeaderFields)")

Чтение конкретных значений хедера HTTP

let contentTypeHeader = response.value(forHTTPHeaderField: "Content-Type")

и здесь как вы можете использовать ответ HTTP когда он получен:

let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
 
    if let response = response as? HTTPURLResponse {
        // Read all HTTP Response Headers
        print("All headers: \(response.allHeaderFields)")
        // Read a specific HTTP Response Header by name
        print("Specific header: \(response.value(forHTTPHeaderField: "Content-Type") ?? " header not found")")
    }
     
}
task.resume()

Чтение тела HTTP ответа

Когда HTTP ответ пришел, вам вероятно нужно прочитать тело HTTP ответа. Используйте фрагмент кода ниже для конвертации тела/даты HTTP ответа в человеко читаемые строковые значения.

if let data = data, let dataString = String(data: data, encoding: .utf8) {
    print("Response data string:\n \(dataString)")
}

Вот как выглядит код если используем URLSession dataTesk

let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
  
    if let data = data, let dataString = String(data: data, encoding: .utf8) {
        print("Response data string:\n \(dataString)")
    }
    
}
task.resume()

Swift структура как тело ответа

Вы так же можете отправить Swift структуру в теле HTTP ответа. На пример, вместо отправки параметра HTTP запроса как мы делали в примере выше userId=300&title=My urgent task&completed=false, мы можем создать Swift структуру и отправить как тело HTTP ответа.

Следующие параметры строк запроса так же могут бы представлены следующим образом:

struct ToDoResponseModel: Codable {
    var userId: Int
    var id: Int?
    var title: String
    var completed: Bool
}
let newTodoItem = ToDoResponseModel(userId: 300, title: "Urgent task 2", completed: true)

Используя JSONEncoder() мы можем закодировать Swift структуру ниже в JSON дату и отправить как тело запроса.

let jsonData = try JSONEncoder().encode(newTodoItem)
request.httpBody = jsonData

Обратите внимание: Не забудьте установить хедеры HTTP: Accept и Content-Type to application/json.

// Set HTTP Request Headers 
request.setValue("application/json", forHTTPHeaderField: "Accept") 
request.setValue("application/json", forHTTPHeaderField: "Content-Type")

На пример:

struct ToDoResponseModel: Codable {
    var userId: Int
    var id: Int?
    var title: String
    var completed: Bool
}
let url = URL(string: "https://jsonplaceholder.typicode.com/todos")
guard let requestUrl = url else { fatalError() }
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"
// Set HTTP Request Header
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let newTodoItem = ToDoResponseModel(userId: 300, title: "Urgent task 2", completed: true)
let jsonData = try JSONEncoder().encode(newTodoItem)
request.httpBody = jsonData 
    let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
        
        if let error = error {
            print("Error took place \(error)")
            return
        }
        guard let data = data else {return}
        do{
            let todoItemModel = try JSONDecoder().decode(ToDoResponseModel.self, from: data)
            print("Response data:\n \(todoItemModel)")
            print("todoItemModel Title: \(todoItemModel.title)")
            print("todoItemModel id: \(todoItemModel.id ?? 0)")
        }catch let jsonErr{
            print(jsonErr)
       }
 
}
task.resume()

Конвертация даты Ответа в Swift структуру

Когда HTTP ответ получен, мы можем его данные JSON декодировать в Swift структуру. В примере кода ниже мы уже это сделали. Для конвертации объекта даты из JSON мы будем использовать JSONDecoder(). На пример:

do{
    let todoItemModel = try JSONDecoder().decode(ToDoResponseModel.self, from: data)
    print("Response data:\n \(todoItemModel)")
    print("todoItemModel Title: \(todoItemModel.title)")
    print("todoItemModel id: \(todoItemModel.id ?? 0)")
}catch let jsonErr{
    print(jsonErr)
}

Вот как выглядит мой код в Xcode плейграунде сейчас:

Я надеюсь этот урок был полезным для вас. Проверьте другие уроки Swift и вы найдете много полезного кода и примеры для использования.

Чтобы узнать как отправить HTTP GET запрос пожалуйста прочтите урок: HTTP GET Request Example in Swift или переведенную версию