Providers

When using Moya, you make all API requests through a MoyaProvider instance, passing in a value of your enum that specifies which endpoint you want to call. After setting up your Endpoint, you’re basically all set for basic usage:

let provider = MoyaProvider<MyService>()

After that simple setup, you’re off to the races:

provider.request(.zen) { result in
    // `result` is either .success(response) or .failure(error)
}

That’s it! The request() method returns a Cancellable, which has only one public function, cancel(), which you can use to cancel the request. See Examples for more information about the Result type.

Remember, where you put your target and the provider, are completely up to you. You can check out Artsy’s implementation for an example.

Always remember to retain your providers, as they will get deallocated if you fail to do so. Deallocation will return a -999 "canceled" error on response.

The same reminder applies also to Moya Reactive implementations, but you will not receive any response because the whole Observable will be disposed, releasing any subscription that you may have configured.

Advanced Usage

To explain all configuration options you have with a MoyaProvider we will cover each parameter one by one in the following sections.

endpointClosure:

The first (optional) parameter for the MoyaProvider initializer is an endpoints closure, which is responsible for mapping a value of your enum to a concrete Endpoint instance. Let’s take a look at what one might look like.

let endpointClosure = { (target: MyTarget) -> Endpoint in
    let url = URL(target: target).absoluteString
    return Endpoint(url: url, sampleResponseClosure: {.networkResponse(200, target.sampleData)}, method: target.method, task: target.task, httpHeaderFields: target.headers)
}
let provider = MoyaProvider(endpointClosure: endpointClosure)

Notice that we don’t have to specify the generic type in the MoyaProvider initializer anymore, since Swift will infer it from the type of our endpointClosure. Neat!

You may also notice the URL(target:) initializer, Moya provides a convenient extension to create a URL from any TargetType.

This endpointClosure is about as simple as you can get. It’s actually the default implementation, too, stored in MoyaProvider.defaultEndpointMapping. Check out the Endpoints documentation for more on why you might want to customize this.

requestClosure:

The next optional initializer parameter is requestClosure, which resolves an Endpoint to an actual URLRequest. Again, check out the Endpoints documentation for how and why you’d do this.

stubClosure:

The next option is to provide a stubClosure. This returns one of either .never (the default), .immediate or .delayed(seconds), where you can delay the stubbed request by a certain number of seconds. For example, .delayed(0.2) would delay every stubbed request. This can be good for simulating network delays in unit tests.

What’s nice is that if you need to stub some requests differently than others, you can use your own closure.

let provider = MoyaProvider<MyTarget>(stubClosure: { target: MyTarget -> Moya.StubBehavior in
    switch target {
        /* Return something different based on the target. */
    }
})

But usually you want the same stubbing behavior for all your targets. There are three class methods on MoyaProvider you can use instead.

MoyaProvider.neverStub
MoyaProvider.immediatelyStub
MoyaProvider.delayedStub(seconds)

So, in the above example, if you wanted immediate stubbing behavior for all targets, either of the following would work.

let provider = MoyaProvider<MyTarget>(stubClosure: { (_: MyTarget) -> Moya.StubBehavior in return .immediate })
let provider = MoyaProvider<MyTarget>(stubClosure: MoyaProvider.immediatelyStub)

manager:

Next, there’s the manager parameter. By default you’ll get a custom Alamofire.Manager instance with basic configurations.

public final class func defaultAlamofireManager() -> Manager {
    let configuration = URLSessionConfiguration.default
    configuration.httpAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders

    let manager = Alamofire.Manager(configuration: configuration)
    manager.startRequestsImmediately = false
    return manager
}

There is only one particular thing: since construct an Alamofire.Request in AF will fire the request immediately by default, even when stubbing the requests for unit testing. Therefore in Moya, startRequestsImmediately is set to false by default.

If you’d like to customize your own manager, for example, to add SSL pinning, create one and pass it in, all requests will route through the custom configured manager.

let policies: [String: ServerTrustPolicy] = [
    "example.com": .PinPublicKeys(
        publicKeys: ServerTrustPolicy.publicKeysInBundle(),
        validateCertificateChain: true,
        validateHost: true
    )
]

let manager = Manager(
    configuration: URLSessionConfiguration.default,
    serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies)
)

let provider = MoyaProvider<MyTarget>(manager: manager)

plugins:

Finally, you may also provide an array of plugins to the provider. These receive callbacks before a request is sent and after a response is received. There are a few plugins included already: one for network activity (NetworkActivityPlugin), one for logging all network activity (NetworkLoggerPlugin), and another for HTTP Authentication.

For example you can enable the logger plugin by simply passing [NetworkLoggerPlugin()] alongside the plugins parameter of your Endpoint. Note that a plugin can also be configurable, for example the already included NetworkActivityPlugin requires a networkActivityClosure parameter. The configurable plugin implementation looks like this:

public final class NetworkActivityPlugin: PluginType {

    public typealias NetworkActivityClosure = (_ change: NetworkActivityChangeType, _ target: TargetType) -> Void
    let networkActivityClosure: NetworkActivityClosure

    public init(networkActivityClosure: @escaping NetworkActivityClosure) {
        self.networkActivityClosure = networkActivityClosure
    }

    // MARK: Plugin

    /// Called by the provider as soon as the request is about to start
    public func willSend(_ request: RequestType, target: TargetType) {
        networkActivityClosure(.began, target)
    }

    /// Called by the provider as soon as a response arrives, even if the request is canceled.
    public func didReceive(_ result: Result<Moya.Response, MoyaError>, target: TargetType) {
        networkActivityClosure(.ended, target)
    }
}

The networkActivityClosure is a closure that you can provide to be notified whenever a network request begins or ends. This is useful for working with the network activity indicator. Note that signature of this closure is (_ change: NetworkActivityChangeType, _ target: TargetType) -> Void, so you will only be notified when a request has .began/.ended and for which target – you aren’t provided any other details about the request itself.