Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.prism.byescaleira.com/llms.txt

Use this file to discover all available pages before exploring further.

PrismNetwork is the transport layer of the Prism SDK. It gives you a type-safe way to declare HTTP endpoints as Swift enums or structs, an actor-based LRU response cache, configurable retry policies, a GraphQL client, multipart upload with progress streaming, request deduplication, and an offline queue that flushes automatically when connectivity returns.

Installation

import PrismNetwork

Defining endpoints

You describe each API call by conforming to PrismNetworkEndpoint. Every property has a sensible default so you only override what you need.
enum UsersEndpoint: PrismNetworkEndpoint {
    case list(page: Int)
    case create(name: String, email: String)
    case delete(id: String)

    var host: String { "api.example.com" }

    var path: String {
        switch self {
        case .list:           return "/v1/users"
        case .create:         return "/v1/users"
        case .delete(let id): return "/v1/users/\(id)"
        }
    }

    var method: PrismNetworkMethod {
        switch self {
        case .list:   return .get
        case .create: return .post
        case .delete: return .delete
        }
    }

    var queryItems: [URLQueryItem]? {
        switch self {
        case .list(let page):
            return [URLQueryItem(name: "page", value: "\(page)")]
        default:
            return nil
        }
    }

    var body: (any Encodable)? {
        switch self {
        case .create(let name, let email):
            return ["name": name, "email": email]
        default:
            return nil
        }
    }

    // Cache GET responses for 5 minutes
    var cacheInterval: TimeInterval? {
        switch self {
        case .list: return 300
        default:    return nil
        }
    }
}

// Build and send a request
let request = try UsersEndpoint.list(page: 1).request
let (data, _) = try await URLSession.shared.data(for: request)

Protocol reference

PropertyTypeDefaultPurpose
schemePrismNetworkScheme.httpsURL scheme
hostStringHostname (required)
pathStringPath component (required)
methodPrismNetworkMethod.getHTTP method
queryItems[URLQueryItem]?nilQuery parameters
headers[String: String][:]Request headers
body(any Encodable)?nilRequest body
timeoutIntervalTimeInterval?nil (system default)Per-request timeout
cacheIntervalTimeInterval?nilGET response TTL

HTTP methods

PrismNetworkMethod covers the five standard methods:
PrismNetworkMethod.get     // "GET"
PrismNetworkMethod.post    // "POST"
PrismNetworkMethod.put     // "PUT"
PrismNetworkMethod.patch   // "PATCH"
PrismNetworkMethod.delete  // "DELETE"

Response caching

PrismResponseCache is an actor-based LRU cache with configurable capacity and per-entry TTL. It evicts the least-recently-used entry when the cache is full, and it automatically invalidates expired entries on access.
let cache = PrismResponseCache(maxSize: 200)

// Store a response with a 10-minute TTL
let entry = PrismCacheEntry(
    data: responseData,
    statusCode: 200,
    headers: ["Content-Type": "application/json"],
    ttl: .seconds(600)
)
await cache.set(entry, for: "GET:/v1/users?page=1")

// Retrieve it (returns nil if expired or absent)
if let cached = await cache.get(for: "GET:/v1/users?page=1") {
    // use cached.data
}

// Invalidate a specific key or the whole cache
await cache.invalidate(key: "GET:/v1/users?page=1")
await cache.clear()
Four cache policies give you fine-grained control:
PolicyBehaviour
.networkOnlyAlways fetch from the network; ignore cached data
.cacheFirstReturn cached data if present; otherwise fetch
.cacheThenNetworkReturn cached data immediately, then revalidate
.staleWhileRevalidateServe stale data while revalidating in the background

Retry policies

Wrap any async throwing operation in PrismRetryableRequest and attach a policy.
let retryable = PrismRetryableRequest(
    policy: PrismExponentialBackoff(
        baseDelay: .seconds(1),
        maxDelay: .seconds(30),
        maxAttempts: 3
    )
) {
    try await URLSession.shared.data(for: request)
}

let (data, response) = try await retryable.execute()
PrismExponentialBackoff adds jitter (up to 0.5 s) to each delay to prevent thundering-herd scenarios. Both built-in policies conform to PrismRetryPolicy, so you can provide your own implementation.

Request deduplication

PrismRequestDeduplicator coalesces identical in-flight requests. When multiple callers trigger the same endpoint at once, only one network call is made and all callers receive the same result.
let deduplicator = PrismRequestDeduplicator()

let key = PrismRequestDeduplicator.key(
    url: url,
    method: "GET"
)

let data: Data = try await deduplicator.deduplicate(
    { try await URLSession.shared.data(for: request).0 },
    key: key
)

Offline queue

PrismOfflineQueue stores requests when the device is offline and flushes them—in priority order—when connectivity is restored.
let queue = PrismOfflineQueue(autoFlush: true) { requests in
    for queued in requests {
        _ = try? await URLSession.shared.data(for: queued.urlRequest)
    }
}

// Enqueue a request
let queued = PrismQueuedRequest(urlRequest: request, priority: 10)
await queue.enqueue(queued)
Set autoFlush: true to let PrismConnectivityMonitor handle the flush automatically. You can also call dequeueAll() manually and process the requests yourself.

GraphQL

PrismGraphQLClient sends queries and mutations to any GraphQL endpoint and decodes typed responses.
let client = PrismGraphQLClient(
    endpointURL: URL(string: "https://api.example.com/graphql")!,
    additionalHeaders: ["Authorization": "Bearer \(token)"]
)

let query = PrismGraphQLQuery(
    query: """
    query GetUser($id: ID!) {
        user(id: $id) { id name email }
    }
    """,
    variables: ["id": "42"]
)

let response: PrismGraphQLResponse<UserData> = try await client.execute(query)

if let user = response.data {
    // use user
}

if let errors = response.errors {
    // handle errors
}

Multipart upload

PrismMultipartFormData builds multipart/form-data bodies from Data parts and string fields. PrismUploadTask wraps a URLSession upload task and streams progress updates via AsyncStream.
var form = PrismMultipartFormData()
form.append(data: imageData, name: "avatar", fileName: "photo.jpg", mimeType: "image/jpeg")
form.append(string: "Jane", name: "displayName")

let (body, contentType) = form.build()

var request = URLRequest(url: uploadURL)
request.httpMethod = "POST"
request.setValue(contentType, forHTTPHeaderField: "Content-Type")

let task = PrismUploadTask(request: request, data: body)

for await progress in await task.upload() {
    print("\(Int(progress.fractionCompleted * 100))% uploaded")
}
PrismUploadTask is an actor, so call task.upload() with await to enter its isolation domain.