• 2.0.0 757d81615b

    v2.0.0 Stable

    daniel-loverde released this 2026-08-29 19:01:22 -03:00 | 19 commits to main since this release

    Breaking release. API was rebuilt around typed request bodies, first-class
    multipart uploads, and Swift structured concurrency. Consuming projects must
    update call sites — see the migration table below and
    Documentation/API.md.

    Projects targeting iOS 13–14 should stay on 1.1.2.


    Why this changed

    The previous API.request had grown unsafe and restrictive:

    • params: Any? — no compile-time checking. The form-url-encoded path
      silently dropped any non-String value.
    • File upload was a magic-string hackparams["file"] had to be a path
      string, one file only, and the whole file was read into memory.
    • @MainActor on the whole type forced every caller onto the main thread,
      and static var certData was an unprotected data race under Swift concurrency.
    • T: Codable on responses forced every DTO to also be Encodable when
      only decoding was needed.
    • ~10 force-unwraps plus as! / try! in the request path.
    • persistConnection recursed without bound on a permanent 4xx — an
      infinite loop.

    What changed

    API is now an actor

    No @MainActor. Calls run off the main thread; every call is await.

    await API.shared.setupCertification(certData: p12, password: "…")   // was setupCertificationRequest
    await API.shared.setPersistConnectionDelay(5)                        // was API.persistConnectionDelay = 5
    

    Typed request bodies

    params: and jsonEncoding: are gone. Pass an HTTPBody:

    try await API.shared.request(url: "…/users", method: .post, body: jsonBody(dto))
    try await API.shared.request(url: "…/token", method: .post,
                                 body: .form(["grant_type": "password"]))
    

    JSONBody, FormURLEncodedBody (percent-escapes values, never drops them),
    RawBody, or your own HTTPBody conformance — API needs no change to accept
    a new body type.

    First-class multipart uploads

    var form = MultipartForm()
    form.field("caption", "Sunset")
    form.file("photo", data: jpegData, filename: "p.jpg")
    form.file("video", url: localURL)          // streamed from disk, never fully in memory
    
    let result: UploadResult = try await API.shared.upload(url: "…/media", form: form)
    

    Plus an onProgress: overload for progress reporting.

    Response constraint relaxed

    T: CodableT: Decodable & Sendable, across API.request, API.upload,
    and all JSONDecoder.decode overloads.

    Other changes

    • URL templating: pathParams: ["id": "42"] fills {id} placeholders.
    • Custom headers now merge over the defaults (previously replaced them).
    • persistConnection retries are bounded by API.maxPersistRetries (3) — the
      old code could loop forever on a permanent 4xx.
    • Zero force operations (!, as!, try!) in the networking code.
    • Result enum and API.defaultParams removed.
    • Dictionary.toObjetct() now throws instead of try!.
    • Deployment target: iOS 15 / watchOS 8 (was iOS 13 / watchOS 6).

    Migration

    Before After
    API.shared.request(url:params: ["k": v], method: .post) API.shared.request(url:body: .form(["k": v]), method: .post) — or jsonBody(dto) for JSON
    params: ["file": "/path/f.png", "caption": "x"] var f = MultipartForm(); f.field("caption","x"); f.file("file", url: URL(fileURLWithPath: "/path/f.png")); try await API.shared.upload(url:form: f)
    params used for {id} URL templating pathParams: ["id": id]
    API.shared.setupCertificationRequest(certData:password:) await API.shared.setupCertification(certData:password:)
    API.persistConnectionDelay = 5 await API.shared.setPersistConnectionDelay(5)
    response type T: Codable T: Decodable & Sendable (non-Sendable classes break)
    LCEssentials.Result Swift.Result
    dict.toObjetct() as T try dict.toObjetct() as T
    jsonEncoding: argument removed — the body type decides its encoding

    Full usage guide: Documentation/API.md.


    Tests

    New LCEssentialsTests target — 30 XCTest cases covering request bodies,
    multipart serialisation, upload, actor isolation, error mapping, and retry
    bounding, run against a stub URLProtocol.

    Downloads