Alamofire
01 / 02

Requests, Validation & Decoding

Alamofire: Requests, Validation & Decoding

Alamofire is a Swift HTTP networking library built on top of URLSession — not a replacement for it. It adds a chainable, ergonomic API for requests, validation, response serialization, and common patterns like multipart uploads and auth interceptors.

Basic Requests

import Alamofire

struct User: Decodable {
    let id: Int
    let name: String
    let email: String
}

// AF is Alamofire's default shared Session instance
AF.request("https://api.example.com/users/1")
    .validate() // non-2xx status codes become errors, not silent "success"
    .responseDecodable(of: User.self) { response in
        switch response.result {
        case .success(let user):
            print(user.name)
        case .failure(let error):
            print("Request failed: \(error)")
        }
    }

// async/await style (Alamofire 5+)
func fetchUser(id: Int) async throws -> User {
    try await AF.request("https://api.example.com/users/\(id)")
        .validate()
        .serializingDecodable(User.self)
        .value
}

// Debugging: print an equivalent curl command for this exact request
AF.request("https://api.example.com/users/1").cURLDescription { description in
    print(description)
}

Parameters, Methods & Headers

struct NewPost: Encodable {
    let title: String
    let body: String
}

// POST with a JSON-encoded body
let post = NewPost(title: "Hello", body: "World")
AF.request(
    "https://api.example.com/posts",
    method: .post,
    parameters: post,
    encoder: JSONParameterEncoder.default,
    headers: ["Authorization": "Bearer \(token)"]
)
.validate()
.responseDecodable(of: Post.self) { response in }

// GET with query-string parameters
AF.request(
    "https://api.example.com/search",
    parameters: ["q": "swift", "page": 2],
    encoding: URLEncoding.default // -> ?q=swift&page=2
)

// Cancelling an in-flight request (e.g. superseded by a newer search)
var currentSearch: DataRequest?

func search(_ query: String) {
    currentSearch?.cancel()
    currentSearch = AF.request("https://api.example.com/search", parameters: ["q": query])
}

Structuring Endpoints with URLRequestConvertible

// Centralize endpoint definitions instead of scattering ad-hoc AF.request calls
enum API: URLRequestConvertible {
    case getUser(id: Int)
    case createPost(NewPost)

    var baseURL: URL { URL(string: "https://api.example.com")! }

    var path: String {
        switch self {
        case .getUser(let id): return "/users/\(id)"
        case .createPost: return "/posts"
        }
    }

    var method: HTTPMethod {
        switch self {
        case .getUser: return .get
        case .createPost: return .post
        }
    }

    func asURLRequest() throws -> URLRequest {
        var request = URLRequest(url: baseURL.appendingPathComponent(path))
        request.method = method
        if case .createPost(let post) = self {
            request = try JSONParameterEncoder.default.encode(post, into: request)
        }
        return request
    }
}

AF.request(API.getUser(id: 1)).responseDecodable(of: User.self) { response in }

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free