kean/Get

Add `MultiAPIClientDelegate`, a delegate that forwards calls to multiple underlying delegates.

Closed this issue · 2 comments

Hi @kean hope you're doing great, first thanks for this awesome library, I'm using it on a lot of my projects.

And one thing I find myself always implementing is this MultiAPIClientDelegate.

An APIClientDelegate implementation that forwards calls to multiple underlying delegates, below is the implementation I use.

if you find this useful for adding to the library, I can PR it.

/// An ``APIClientDelegate`` that forward calls to multiple delegates in order.
public struct MultiAPIClientDelegate: APIClientDelegate {
    let delegates: [APIClientDelegate]

    public init(_ delegates: [APIClientDelegate]) {
        self.delegates = delegates
    }

    public func client(_ client: APIClient, willSendRequest request: inout URLRequest) async throws {
        for delegate in delegates {
            try await delegate.client(client, willSendRequest: &request)
        }
    }

    public func client(_ client: APIClient, shouldRetry task: URLSessionTask, error: Error, attempts: Int) async throws -> Bool {
        for delegate in delegates {
            if try await delegate.client(client, shouldRetry: task, error: error, attempts: attempts) {
                return true
            }
        }
        return false
    }

    public func client(_ client: APIClient, validateResponse response: HTTPURLResponse, data: Data, task: URLSessionTask) throws {
        for delegate in delegates {
            try delegate.client(client, validateResponse: response, data: data, task: task)
        }
    }

    public func client<T>(_ client: APIClient, makeURLForRequest request: Request<T>) throws -> URL? {
        for delegate in delegates {
            if let url = try delegate.client(client, makeURLForRequest: request) {
                return url
            }
        }
        return nil
    }

    public func client<T>(_ client: APIClient, encoderForRequest request: Request<T>) -> JSONEncoder? {
        for delegate in delegates {
            if let encoder = delegate.client(client, encoderForRequest: request) {
                return encoder
            }
        }
        return nil
    }

    public func client<T>(_ client: APIClient, decoderForRequest request: Request<T>) -> JSONDecoder? {
        for delegate in delegates {
            if let decoder = delegate.client(client, decoderForRequest: request) {
                return decoder
            }
        }
        return nil
    }
}
kean commented

Thanks, @GRSouza! Yeah, I've done that before for other delegates. But I think it's a niche use-case for Get. One of the main advantages of Get is how small and focused the API is, so I'd prefer to avoid adding new APIs unless it's something that can't be implemented "outside" of the framework.

I created a new repository for holding some common extensions to Get library, and added this type to it https://github.com/binaryscraping/GetExtensions

Will close this, thanks.