HTTP-Client in Swift: Anfragen richtig stellen

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum ein ordentlicher HTTP-Client für Ihre Swift-App wichtig ist

Moderne iOS- und macOS-Apps funktionieren selten ohne Interaktion mit entfernten Servern. Ob es darum geht, Daten von einer REST-API zu laden, Analysen zu senden oder mit Cloud-Diensten zu arbeiten — ein HTTP-Client in Swift ist die Grundlage der Netzwerkkommunikation. Viele Entwickler, insbesondere Anfänger, machen jedoch typische Fehler: Sie ignorieren die Fehlerbehandlung, nutzen keine modernen Sprachfunktionen (async/await) oder erzeugen aus Netzwerkaufrufen „Spaghetticode". In diesem Artikel zeigen wir, wie Sie unter Einhaltung der Best Practices einen zuverlässigen und leistungsstarken HTTP-Client in Swift schreiben.



1. URLSession-Grundlagen: Das Herzstück von Netzwerkanfragen

In der Swift-Standardbibliothek übernehmen das Foundation-Framework und die URLSession-Klasse die Netzwerkkommunikation. Dies ist ein leistungsstarkes Werkzeug, das Sitzungskonfiguration, Caching, Hintergrundanfragen und vieles mehr unterstützt.



1.1. Erstellen eines einfachen HTTP-Clients

Beginnen wir mit einer einfachen Struktur, die GET-Anfragen durchführt. Wir verwenden einen Enum zur Beschreibung möglicher Fehler und ein Protokoll für die Flexibilität:

import Foundation

enum HTTPClientError: Error { case invalidURL case noData case decodingError(Error) case networkError(Error) case statusCode(Int)}

protocol HTTPClientProtocol { func get<T: Decodable>(from urlString: String, responseType: T.Type) async throws -> T}

final class HTTPClient: HTTPClientProtocol { private let session: URLSession private let decoder: JSONDecoder init(session: URLSession = .shared, decoder: JSONDecoder = JSONDecoder()) { self.session = session self.decoder = decoder } func get<T: Decodable>(from urlString: String, responseType: T.Type) async throws -> T { guard let url = URL(string: urlString) else { throw HTTPClientError.invalidURL } var request = URLRequest(url: url) request.httpMethod = "GET" request.setValue("application/json", forHTTPHeaderField: "Accept") let (data, response) = try await session.data(for: request) guard let httpResponse = response as? HTTPURLResponse else { throw HTTPClientError.networkError(NSError(domain: "Invalid response", code: -1)) } guard (200...299).contains(httpResponse.statusCode) else { throw HTTPClientError.statusCode(httpResponse.statusCode) } do { return try decoder.decode(T.self, from: data) } catch { throw HTTPClientError.decodingError(error) } }}


1.2. Warum async/await?

Vor Swift 5.5 verwendeten Entwickler Closures (Completion-Handler) oder Bibliotheken von Drittanbietern (Alamofire). Async/await macht den Code linear, klar und leicht lesbar. Fehler werden mit do-catch behandelt, anstatt mit verschachtelten Closures.



2. POST, PUT, DELETE: Arbeiten mit verschiedenen HTTP-Methoden

Ein echter HTTP-Client sollte alle wichtigen Methoden unterstützen. Fügen wir dem Protokoll Methoden zum Senden von Daten und Aktualisieren von Ressourcen hinzu.



2.1. Erweiterung des Protokolls für POST und PUT

extension HTTPClientProtocol {    func post<T: Decodable, U: Encodable>(        to urlString: String,        body: U,        responseType: T.Type    ) async throws -> T {        guard let url = URL(string: urlString) else {            throw HTTPClientError.invalidURL        }                var request = URLRequest(url: url)        request.httpMethod = "POST"        request.setValue("application/json", forHTTPHeaderField: "Content-Type")        request.setValue("application/json", forHTTPHeaderField: "Accept")        request.httpBody = try JSONEncoder().encode(body)                return try a

Blogs

Buchempfehlungen