vadymmarkov / Malibu

:surfer: Malibu is a networking library built on promises

Home Page:https://vadymmarkov.github.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Proposal: Adding `RequestBehaviour`s to Malibu

codeOfRobin opened this issue · comments

commented

Hey!

I've been reading about RequestBehaviour recently and I think it'd be a great addition to Malibu, especially for things like Logging, NetworkActivityIndicators, authentication, caching etc.

Here's what the protocol looks like

protocol RequestBehavior {

	func beforeSend()

	func afterSuccess(result: Any)

	func afterFailure(error: Error)

	func adapt(_ request: URLRequest) -> URLRequest

}

// default implementations
extension RequestBehavior {
	func beforeSend() {

	}

	func afterSuccess(result: Any) {

	}

	func afterFailure(error: Error) {

	}

	func adapt(_ request: URLRequest) -> URLRequest {
		return request
	}
}

And Auth can be implemented as follows:

struct TokenAuthBehaviour: RequestBehavior {
	let token: String

	func adapt(_ request: URLRequest) -> URLRequest {
		var copy = request
		var headers = copy.allHTTPHeaderFields ?? [:]
		headers["Authorization"] = "Bearer \(token)"
		copy.allHTTPHeaderFields = headers
		return copy
	}
}

struct CustomAuthBehaviour: RequestBehavior {

	let key: String
	let value: String

	func adapt(_ request: URLRequest) -> URLRequest {
		var copy = request
		var headers = copy.allHTTPHeaderFields ?? [:]
		headers[key] = value
		copy.allHTTPHeaderFields = headers
		return copy
	}
}

struct CustomAuthBehaviour: RequestBehavior {

	let key: String
	let value: String

	func adapt(_ request: URLRequest) -> URLRequest {
		var copy = request
		var headers = copy.allHTTPHeaderFields ?? [:]
		headers[key] = value
		copy.allHTTPHeaderFields = headers
		return copy
	}
}

There's other examples in the blog post, but this would be an excellent starting point (Logging could be in both before and after function calls, for example)

PS: Discussed this with @vadymmarkov on Twitter recently: https://twitter.com/vadymmarkov/status/956075029736894465

commented

Another advantage to this approach is, you can compose Request Behaviours, making Malibu incredibly explicit!

struct CombinedRequestBehavior: RequestBehavior {

	let behaviors: [RequestBehavior]

	func adapt(_ request: URLRequest) -> URLRequest {
		return behaviors.reduce(request) { (req, behaviour) in
			return behaviour.adapt(req)
		}
	}

	func beforeSend() {
		behaviors.forEach({ $0.beforeSend() })
	}

	func afterSuccess(result: Any) {
		behaviors.forEach({ $0.afterSuccess(result: result) })
	}

	func afterFailure(error: Error) {
		behaviors.forEach({ $0.afterFailure(error: error) })
	}
}

I think it would be a great addition to the library. What are your thoughts @onmyway133 @zenangst ?

commented

@codeOfRobin @vadymmarkov Good idea. I see Malibu has customisation points where we can configure request already, but this is a nice refactoring around it.

commented

I'll start working on some changes. Thank you for the feedback guys!

commented

Hey folks! So sorry I’ve not been able to give it much thought over the past week + (Been dealing with some work stuff). Will get to this tomorrow 👍

commented

Hey @vadymmarkov I've been considering retaining the beforeEach and preProcessRequest semantics in the RequestBehaviour protocol. Could you check this out and tell me what you think: codeOfRobin@51c6036

I think it should work @codeOfRobin