Skip to content

Latest commit

 

History

History
175 lines (132 loc) · 7.01 KB

Providers.md

File metadata and controls

175 lines (132 loc) · 7.01 KB

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.

But don't forget to keep a reference for it in property. If it gets deallocated you'll see -999 "cancelled" error on response.

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<MyTarget> in
    let url = target.baseURL.URLByAppendingPathComponent(target.path).absoluteString
    return Endpoint(URL: url, sampleResponseClosure: {.NetworkResponse(200, target.sampleData)}, method: target.method, parameters: target.parameters)
}
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!

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 NSURLRequest. 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 behaviour 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 behaviour 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 = NSURLSessionConfiguration.defaultSessionConfiguration()
    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: NSURLSessionConfiguration.defaultSessionConfiguration(),
    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) -> ()
    let networkActivityClosure: NetworkActivityClosure

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

    // MARK: Plugin

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

    /// Called by the provider as soon as a response arrives
    public func didReceiveResponse(data: NSData?, statusCode: Int?, response: NSURLResponse?, error: ErrorType?, target: TargetType) {
        networkActivityClosure(change: .Ended)
    }
}

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 activitiy indicator. Note that signature of this closure is (change: NetworkActivityChangeType) -> (), so you will only be notified when a request has .Began or .Ended – you aren't provided any other details about the request itself.