Airtable API API in Swift

Airtable API API in Swift

This guide shows you how to integrate the Airtable API into your Swift application. Spreadsheet-database hybrid API with CRUD on bases, records, and attachments.

Prerequisites

Installation

// Use URLSession (built-in) or Swift Package Manager:
// .package(url: "https://github.com/Alamofire/Alamofire", from: "5.0.0")

Basic Usage

import Foundation

let apiKey = ProcessInfo.processInfo.environment["API_KEY"] ?? "YOUR_API_KEY"
let baseURL = "https://api.airtable.com"
let url = URL(string: "\(baseURL)/v1/resources")!

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

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let error = error {
        print("Error: \(error)")
        return
    }
    if let httpResponse = response as? HTTPURLResponse {
        print("Status: \(httpResponse.statusCode)")
    }
    if let data = data, let body = String(data: data, encoding: .utf8) {
        print(body)
    }
}

task.resume()
RunLoop.main.run(until: Date(timeIntervalSinceNow: 10))

Error Handling

import Foundation

func callAPIWithRetry(url: URL, headers: [String: String]) {
    func attemptRequest() {
        var request = URLRequest(url: url)
        request.httpMethod = "GET"
        for (k, v) in headers { request.setValue(v, forHTTPHeaderField: k) }
        URLSession.shared.dataTask(with: request) { data, response, error in
            if let error = error { print("Error: \(error)"); return }
            if let httpResponse = response as? HTTPURLResponse {
                if httpResponse.statusCode == 429 {
                    print("Rate limited. Waiting 60s...")
                    DispatchQueue.global().asyncAfter(deadline: .now() + .seconds(60)) { attemptRequest() }
                    return
                }
                print("Status: \(httpResponse.statusCode)")
            }
            if let data = data, let body = String(data: data, encoding: .utf8) { print(body) }
        }.resume()
    }
    attemptRequest()
    RunLoop.main.run(until: Date(timeIntervalSinceNow: 60))
}

let apiKey = ProcessInfo.processInfo.environment["API_KEY"] ?? "YOUR_API_KEY"
let url = URL(string: "https://api.airtable.com/v1/resources")!
callAPIWithRetry(url: url, headers: ["Authorization": "Bearer \(apiKey)", "Content-Type": "application/json"])

Advanced Usage

import Foundation

class AirtableClient {
    let apiKey: String
    let baseURL: String
    let session: URLSession

    init(apiKey: String, baseURL: String = "https://api.airtable.com") {
        self.apiKey = apiKey
        self.baseURL = baseURL.hasSuffix("/") ? String(baseURL.dropLast()) : baseURL
        self.session = URLSession.shared
    }

    func request(method: String, path: String, completion: @escaping (Result<Data, Error>) -> Void) {
        let urlString = "\(baseURL)/v1\(path)"
        guard let url = URL(string: urlString) else {
            completion(.failure(NSError(domain: "InvalidURL", code: 0)))
            return
        }
        var request = URLRequest(url: url)
        request.httpMethod = method
        request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        session.dataTask(with: request) { data, response, error in
            if let error = error { completion(.failure(error)); return }
            if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode >= 400 {
                completion(.failure(NSError(domain: "APIError", code: httpResponse.statusCode))); return
            }
            completion(.success(data ?? Data()))
        }.resume()
    }

    func listResources(completion: @escaping (Result<Data, Error>) -> Void) {
        request(method: "GET", path: "/resources", completion: completion)
    }
}

let client = AirtableClient(apiKey: ProcessInfo.processInfo.environment["API_KEY"] ?? "YOUR_API_KEY")
client.listResources { result in
    switch result {
    case .success(let data): print("Got \(data.count) bytes")
    case .failure(let error): print("Error: \(error)")
    }
}
RunLoop.main.run(until: Date(timeIntervalSinceNow: 10))

Best Practices

  • Store your API key in an environment variable, never in source code
  • Implement retry logic with exponential backoff for 429 and 5xx errors
  • Set reasonable timeouts (10-30 seconds) for all API calls
  • Log request IDs from response headers for debugging
  • Cache responses where appropriate to reduce API calls

Other languages