Tutorial/Mulai cepat Swift

Mengambil kurs valas di Swift dengan URLSession

Gunakan URLSession, Codable, dan URLComponents sambil menyimpan informasi waktu pembaruan.

ERexchangerate.dev·Sep 8, 2026·6 menit membaca

Gunakan URLSession untuk jaringan dan Codable untuk JSON. Simpan kunci di server, bukan di aplikasi iOS, macOS, atau watchOS.

Key points
Tentukan model respons: Simpan rates, source, market_session, dan data_updated_at; gunakan Decimal untuk perhitungan nilai uang.
Simpan kunci di server: Aplikasi mobile memanggil backend Anda, lalu backend menambahkan Authorization. Swift di server dapat membaca kunci dari environment.
Tangani status dan kesegaran: Periksa status HTTP sebelum decode dan bedakan 401 dari 429. Tampilkan waktu dan sumber pengamatan.

Tentukan model respons

Simpan rates, source, market_session, dan data_updated_at; gunakan Decimal untuk perhitungan nilai uang.

swift · ExchangeRateClient.swiftcopy
import Foundation

final class NoRedirects: NSObject, URLSessionTaskDelegate {
    func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
        completionHandler(nil)
    }
}

struct Latest: Decodable {
    let base: String
    let source: String
    let marketSession: String
    let dataUpdatedAt: String
    let rates: [String: Decimal]
}

struct ExchangeRateClient {
    let session: URLSession
    let apiKey: String?

    func latest(base: String) async throws -> Latest {
        let normalizedBase = base.uppercased()
        guard normalizedBase.count == 3, normalizedBase.allSatisfy({ $0.isASCII && $0.isLetter }) else {
            throw URLError(.badURL)
        }
        guard var components = URLComponents(string: "https://api.exchangerate.dev/v1/latest/\(normalizedBase)") else {
            throw URLError(.badURL)
        }
        components.queryItems = [URLQueryItem(name: "symbols", value: "EUR,GBP,JPY")]
        guard let url = components.url else { throw URLError(.badURL) }
        var request = URLRequest(url: url)
        request.timeoutInterval = 10
        if let apiKey { request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization") }

        let (data, response) = try await session.data(for: request)
        guard let http = response as? HTTPURLResponse, (200..<300).contains(http.statusCode) else {
            throw URLError(.badServerResponse)
        }
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        return try decoder.decode(Latest.self, from: data)
    }
}

Simpan kunci di server

Aplikasi mobile memanggil backend Anda, lalu backend menambahkan Authorization. Swift di server dapat membaca kunci dari environment.

swift · server setupcopy
let key = ProcessInfo.processInfo.environment["EXCHANGERATE_API_KEY"]
let session = URLSession(configuration: .ephemeral, delegate: NoRedirects(), delegateQueue: nil)
let client = ExchangeRateClient(
    session: session,
    apiKey: key
)
let latest = try await client.latest(base: "USD")
print(latest.rates["EUR"] as Any, latest.source, latest.dataUpdatedAt)

Tangani status dan kesegaran

Periksa status HTTP sebelum decode dan bedakan 401 dari 429. Tampilkan waktu dan sumber pengamatan.

Simpan konteks kurs
Laporan harian cukup sekali sehari, sedangkan dashboard operasional bisa tiap jam. Saat menerima 429, kurangi jadwal dan jangan membuat loop retry.
  • Simpan kurs bersama sumber dan waktu.
  • Gunakan untuk otomasi dan analisis.
  • Jangan perlakukan sebagai kuotasi eksekusi.
ER
exchangerate.dev
Panduan integrasi untuk developer.

Baca selanjutnya

ReferenceMulai cepat API kursBaca TutorialJavaScript / Node.jsBaca GuideSimpan konteks kursBaca
Perbandingan LainnyaFixer vs exchangerate.devOpen Exchange Rates vs exchangerate.devCurrencylayer vs exchangerate.dev
PanduanReading source and market_session in your pipelineIndicative vs executable FX rates: what a rates API actually gives youECB reference rates, explained
Kurs LangsungEUR/USDGBP/USDUSD/JPY