URLTaskManager

public class URLTaskManager

This is URLSession wrapper that provides interception and reaction funcitonality. The ideas behind the URLTaskManager is to be able to control URLSession tasks at a more fine grained level, and to have a automatic mechanism to re-fire them should the need arise.

This is done by setting a URLProtocol on the URLSession object that is exposed to the client. Therefore, the URLSessionConfiguration object that you pass in to the URLTaskManager object will have its protocolClasses member changed.

One example of a use case is to be able to do OAuth2 refresh operations. Should a task come back with a 401 status code, a reactor can perform a refresh operation, reset the any user state to include the new authorization and refresh token, and the requeue the task.

Another use case if you want to enrich a URL tasks with headers, or if you want to batch url requests and release them in one go.

Intercepting tasks

Every request that is sent through URLTaskManager.session is run through any associated URLTaskInterceors or URLTaskReactors as a URLTask object that contain an accessible URLRequest object.

class Interceptor: URLTaskInterceptor {
  let user: User
  init(user: User) {
    self.user = user
  }
  func intercept(task: inout URLTask, currentBatchCount _: Int) -> InterceptCommand {
    // Add a field to the request before it's fired off
    task.request.addValue(self.user.authorization, forHTTPHeaderField: "Authorization")
    return .execute
  }
}

Reacting to tasks

The same principles apply as with intercepting tasks. To react to a a URLTask object you may implement a URLTaskReactor object.

class Reactor: URLTaskReactor {
  let user: User
  init(user: User) {
    self.user = user
  }

  func execute(done: @escaping (Error?) -> Void) {
    // For example one could refresh the authorization tokens here
    user.refreshAuthorizationToken { result in
      switch result {
      case .success:
        done(nil)
      case let .failure(value):
        done(value)
    }
  }

  func shouldExecute<T: Task>(after result: URLTask.Result, from task: URLTask, with _: Handle) -> Bool {
    if case let .success(value) = result {
      return value.(response as? HTTPURLResponse)?.statusCode == 401
    }
    return false
  }
}
  • And tasks executed through this URLSession can be intercetped and reacted to.

    Declaration

    Swift

    public let session: URLSession
  • Creates a URLTaskManager object

    Declaration

    Swift

    public init(interceptors: [URLTaskInterceptor] = [], reactors: [URLTaskReactor] = [], configuration: URLSessionConfiguration = .default)

    Parameters

    interceptors

    list of interceptors that will be run before each URLSessionTask is executed

    rectors

    list of reactors that will run upon completion of the URLSessionTask

    configuration

    passed on to the URLSession object