Protocol-Oriented Networking
-
Upload
mostafa-amer -
Category
Engineering
-
view
219 -
download
0
Transcript of Protocol-Oriented Networking
![Page 1: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/1.jpg)
Protocol-Oriented Networking@mostafa_amer
![Page 2: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/2.jpg)
Starting Point#import <AFNetworking/AFNetworking.h>
@interface GHAPIClient : AFHTTPSessionManager
+ (instancetype)sharedClient; -(void)fetchGitHubUserWithName:(NSString *)name
completionHandler:(void(^)(id result, NSError *error))handler; @end
![Page 3: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/3.jpg)
Starting Point#import <AFNetworking/AFNetworking.h>
@interface GHAPIClient : AFHTTPSessionManager
+ (instancetype)sharedClient; -(void)fetchGitHubUserWithName:(NSString *)name
completionHandler:(void(^)(id result, NSError *error))handler; @end
• Client has too many responsibilities
![Page 4: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/4.jpg)
Starting Point#import <AFNetworking/AFNetworking.h>
@interface GHAPIClient : AFHTTPSessionManager
+ (instancetype)sharedClient; -(void)fetchGitHubUserWithName:(NSString *)name
completionHandler:(void(^)(id result, NSError *error))handler; @end
• Client has too many responsibilities• Client is tightly coupled to the network library
![Page 5: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/5.jpg)
Starting Point#import <AFNetworking/AFNetworking.h>
@interface GHAPIClient : AFHTTPSessionManager
+ (instancetype)sharedClient; -(void)fetchGitHubUserWithName:(NSString *)name
completionHandler:(void(^)(id result, NSError *error))handler; @end
• Client has too many responsibilities• Client is tightly coupled to the network library• Client is hard to test
![Page 6: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/6.jpg)
Starting Point#import <AFNetworking/AFNetworking.h>
@interface GHAPIClient : AFHTTPSessionManager
+ (instancetype)sharedClient; -(void)fetchGitHubUserWithName:(NSString *)name
completionHandler:(void(^)(id result, NSError *error))handler; @end
• Client has too many responsibilities• Client is tightly coupled to the network library• Client is hard to test• Implementation details is not hidden
![Page 7: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/7.jpg)
Decouplingprotocol NetworkServiceType { func requestEndpoint(path: String, method: HTTPMethod, parameters: [String: Any]?, handler: (Data?, Error?) -> ()) }
![Page 8: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/8.jpg)
Decouplingclass NetworkService: AFHTTPSessionManager, NetworkServiceType { func requestEndpoint(path: String, method: HTTPMethod, parameters: [String : Any]?, handler: (Data?, Error?) -> ()) {
} }
![Page 9: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/9.jpg)
Decouplingclass NetworkService: AFHTTPSessionManager, NetworkServiceType { func requestEndpoint(path: String, method: HTTPMethod, parameters: [String : Any]?, handler: (Data?, Error?) -> ()) { switch method { case .GET: get(path, parameters: parameters, success: {_, result in handler(result, nil) }, failure: {_, error in handler(nil, error) } ) } } }
![Page 10: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/10.jpg)
Hide Implementation
@interface GHAPIClient : AFHTTPSessionManager
+ (instancetype)sharedClient; - (void)fetchListWithCompletionHandler:(void(^)(id result, NSError *error))handler; @end
#import <AFNetworking/AFNetworking.h>
![Page 11: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/11.jpg)
Hide Implementation
@interface GHAPIClient : NSObject
+ (instancetype)sharedClient; - (void)fetchListWithCompletionHandler:(void(^)(id result, NSError *error))handler; @end
![Page 12: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/12.jpg)
@interface GHAPIClient()
@end
@implementation GHAPIClient
- (instancetype)initWithBaseURL:(NSURL *)baseURL { self = [super init]; if(self) {
} return self; }
+ (instancetype)sharedClient { static GHAPIClient *_instance = nil; if(! _instance) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{
_instance = [[GHAPIClient alloc] init]; }); } return _instance; }
Refactoring Client
![Page 13: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/13.jpg)
Refactoring Client@interface GHAPIClient() @property (nonatomic, strong) id<NetworkServiceType> network; @end
@implementation GHAPIClient
- (instancetype)initWithBaseURL:(NSURL *)baseURL { self = [super init]; if(self) {
} return self; }
+ (instancetype)sharedClient { static GHAPIClient *_instance = nil; if(! _instance) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{
_instance = [[GHAPIClient alloc] init]; }); } return _instance; }
![Page 14: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/14.jpg)
Refactoring Client@interface GHAPIClient() @property (nonatomic, strong) id<NetworkServiceType> network; @end
@implementation GHAPIClient
- (instancetype)initWithNetworkService:(id<NetworkServiceType>)service { self = [super init]; if(self) { _network = service; } return self; }
+ (instancetype)sharedClient { static GHAPIClient *_instance = nil; if(! _instance) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{
_instance = [[GHAPIClient alloc] init]; }); } return _instance; }
![Page 15: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/15.jpg)
Refactoring Client@interface GHAPIClient() @property (nonatomic, strong) id<NetworkServiceType> network; @end
@implementation GHAPIClient
- (instancetype)initWithNetworkService:(id<NetworkServiceType>)service { self = [super init]; if(self) { _network = service; } return self; }
+ (instancetype)sharedClient { static GHAPIClient *_instance = nil; if(! _instance) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSURL *baseURL = [NSURL URLWithString:@"https://api.github.com"]; NetworkService *service = [[NetworkService alloc] initWithBaseURL:baseURL]; _instance = [[GHAPIClient alloc] initWithNetworkService:service]; }); } return _instance; }
![Page 16: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/16.jpg)
Testing Clientclass NetworkMock: NetworkServiceType { var response: Data? var error: Error? func requestEndpoint(path: String, method: HTTPMethod, parameters: [String : Any]?, handler: (Data?, Error?) -> ()) { handler(response, error) } }
![Page 17: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/17.jpg)
class APIClientSpecs: QuickSpec { override func spec() { var mock: NetworkMock! var sut: GHAPIClient! beforeEach { mock = NetworkMock() sut = GHAPIClient(networkService: mock) }
} }
Testing Clientclass NetworkMock: NetworkServiceType { var response: Data? var error: Error? func requestEndpoint(path: String, method: HTTPMethod, parameters: [String : Any]?, handler: (Data?, Error?) -> ()) { handler(response, error) } }
![Page 18: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/18.jpg)
Testing Clientclass NetworkMock: NetworkServiceType { var response: Data? var error: Error? func requestEndpoint(path: String, method: HTTPMethod, parameters: [String : Any]?, handler: (Data?, Error?) -> ()) { handler(response, error) } }
class APIClientSpecs: QuickSpec { override func spec() { var mock: NetworkMock! var sut: GHAPIClient! beforeEach { mock = NetworkMock() sut = GHAPIClient(networkService: mock) } it("handle error") { mock.data = // Data from JSON file sut.fetchGitHubUser(loginName: "mosamer") { (_, error) in expect(error).notTo(beNil()) } } } }
![Page 19: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/19.jpg)
Client Again
- (void)fetchGitHubUser:(NSString *)name completionHandler:(void (^)(id, NSError *))handler {
[self.network requestEndpointWithPath:[NSString stringWithFormat:@“users/%@”,name] method:HTTPMethodGET parameters:nil handler:^(id result, NSError *error) { handler(result, error); }]; }
![Page 20: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/20.jpg)
Client Again
- (void)fetchGitHubUser:(NSString *)name completionHandler:(void (^)(id, NSError *))handler {
[self.network requestEndpointWithPath:[NSString stringWithFormat:@“users/%@”,name] method:HTTPMethodGET parameters:nil handler:^(id result, NSError *error) { handler(result, error); }]; }
• Client still has too many responsibilities
![Page 21: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/21.jpg)
Client Again
- (void)fetchGitHubUser:(NSString *)name completionHandler:(void (^)(id, NSError *))handler {
[self.network requestEndpointWithPath:[NSString stringWithFormat:@“users/%@”,name] method:HTTPMethodGET parameters:nil handler:^(id result, NSError *error) { handler(result, error); }]; }
• Client still has too many responsibilities• Client lacks general handlers
![Page 22: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/22.jpg)
More Protocols
![Page 23: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/23.jpg)
More Protocols
protocol Resource { var path: String { get } var method: HTTPMethod { get } var parameters: [String: Any]? { get }
}
![Page 24: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/24.jpg)
More Protocolsprotocol Response {} protocol Resource { var path: String { get } var method: HTTPMethod { get } var parameters: [String: Any]? { get }
associatedtype ResponseType: Response
}
![Page 25: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/25.jpg)
More Protocolsprotocol Response {} protocol Resource { var path: String { get } var method: HTTPMethod { get } var parameters: [String: Any]? { get }
associatedtype ResponseType: Response func parse(response: Data) -> (ResponseType?, Error?) }
![Page 26: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/26.jpg)
Define Endpointsstruct GitHubUserEndpoint: Resource { private let name: String init(loginName: String) { name = loginName } var path: String { return "users/\(name)" } var method: HTTPMethod { return .GET } var parameters: [String : Any]? { return nil } func parse(response: Data) -> ( GitHubUser?, Error?) {
// Parse JSON -> data model object } }struct GitHubUser: Response { // Define data model
}
![Page 27: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/27.jpg)
Testing Endpointsclass GitHubUserEndpointSpecs: QuickSpec { override func spec() {
var sut: GitHubUserEndpoint! beforeEach { sut = GitHubUserEndpoint(loginName: "mosamer") }
} }
![Page 28: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/28.jpg)
Testing Endpointsclass GitHubUserEndpointSpecs: QuickSpec { override func spec() {
var sut: GitHubUserEndpoint! beforeEach { sut = GitHubUserEndpoint(loginName: "mosamer") } it("build path") { expect(sut.path) == "users/mosamer" }
} }
![Page 29: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/29.jpg)
Testing Endpointsclass GitHubUserEndpointSpecs: QuickSpec { override func spec() {
var sut: GitHubUserEndpoint! beforeEach { sut = GitHubUserEndpoint(loginName: "mosamer") } it("build path") { expect(sut.path) == "users/mosamer" } it("GET method") { expect(sut.method) == HTTPMethod.GET }
} }
![Page 30: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/30.jpg)
Testing Endpointsclass GitHubUserEndpointSpecs: QuickSpec { override func spec() {
var sut: GitHubUserEndpoint! beforeEach { sut = GitHubUserEndpoint(loginName: "mosamer") } it("build path") { expect(sut.path) == "users/mosamer" } it("GET method") { expect(sut.method) == HTTPMethod.GET } it("without parameters") { expect(sut.parameters).to(beNil()) }
} }
![Page 31: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/31.jpg)
Testing Endpointsclass GitHubUserEndpointSpecs: QuickSpec { override func spec() {
var sut: GitHubUserEndpoint! beforeEach { sut = GitHubUserEndpoint(loginName: "mosamer") } it("build path") { expect(sut.path) == "users/mosamer" } it("GET method") { expect(sut.method) == HTTPMethod.GET } it("without parameters") { expect(sut.parameters).to(beNil()) } it("parse response") { let userJSON = Data() /* Data from JSON file */ let (user, _) = sut.parse(response: userJSON) /* Check user properties are fetched correctly */ } } }
![Page 32: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/32.jpg)
Client One More Time
- (void)fetchGitHubUser:(NSString *)name completionHandler:(void (^)(id, NSError *))handler {
[self.network requestEndpointWithPath:[NSString stringWithFormat:@“users/%@”,name] method:HTTPMethodGET parameters:nil handler:^(id result, NSError *error) { handler(result, error); }]; }
![Page 33: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/33.jpg)
Client One More Time
- (void)fetchGitHubUser:(NSString *)name completionHandler:(void (^)(id, NSError *))handler {
[self.network requestEndpointWithPath:[NSString stringWithFormat:@“users/%@”,name] method:HTTPMethodGET parameters:nil handler:^(id result, NSError *error) { handler(result, error); }]; }
func user(loginName: String, completionhandler: (GitHubUser?, Error?) -> ()) { let endpoint = GitHubUserEndpoint(loginName: loginName) request(endpoint, handler: completionhandler) }
![Page 34: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/34.jpg)
Client - General Handlers
private func request<R: Resource>(_ endpoint: R, handler:(R.ResponseType?, Error?) -> ()) {
} } }
extension GHAPIClient { func user(loginName: String, completionhandler: (GitHubUser?, Error?) -> ()) { let endpoint = GitHubUserEndpoint(loginName: loginName) request(endpoint, handler: completionhandler) }
![Page 35: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/35.jpg)
Client - General Handlers
private func request<R: Resource>(_ endpoint: R, handler:(R.ResponseType?, Error?) -> ()) {
network.requestEndpoint(path: endpoint.path, method: endpoint.method, parameters: endpoint.parameters) { (data, error) in if let _ = error { handler(nil, error) return } guard let data = data else { handler(nil, nil) return } let (result, error) = endpoint.parse(response: data) handler(result, error) } } }
extension GHAPIClient { func user(loginName: String, completionhandler: (GitHubUser?, Error?) -> ()) { let endpoint = GitHubUserEndpoint(loginName: loginName) request(endpoint, handler: completionhandler) }
![Page 36: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/36.jpg)
Summary
![Page 37: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/37.jpg)
Summary• Client has too many responsibilities
![Page 38: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/38.jpg)
Summary• Client has too many responsibilities
![Page 39: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/39.jpg)
Summary• Client has too many responsibilities• Client is tightly coupled to the network library
![Page 40: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/40.jpg)
Summary• Client has too many responsibilities• Client is tightly coupled to the network library
![Page 41: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/41.jpg)
Summary• Client has too many responsibilities• Client is tightly coupled to the network library• Client is hard to test
![Page 42: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/42.jpg)
Summary• Client has too many responsibilities• Client is tightly coupled to the network library• Client is hard to test
![Page 43: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/43.jpg)
Summary• Client has too many responsibilities• Client is tightly coupled to the network library• Client is hard to test• Implementation details is not hidden
![Page 44: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/44.jpg)
Summary• Client has too many responsibilities• Client is tightly coupled to the network library• Client is hard to test• Implementation details is not hidden
![Page 45: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/45.jpg)
Summary• Client has too many responsibilities• Client is tightly coupled to the network library• Client is hard to test• Implementation details is not hidden• Client still has too many responsibilities
![Page 46: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/46.jpg)
Summary• Client has too many responsibilities• Client is tightly coupled to the network library• Client is hard to test• Implementation details is not hidden• Client still has too many responsibilities
![Page 47: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/47.jpg)
Summary• Client has too many responsibilities• Client is tightly coupled to the network library• Client is hard to test• Implementation details is not hidden• Client still has too many responsibilities• Client lacks general handlers
![Page 48: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/48.jpg)
Summary• Client has too many responsibilities• Client is tightly coupled to the network library• Client is hard to test• Implementation details is not hidden• Client still has too many responsibilities• Client lacks general handlers
![Page 49: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/49.jpg)
@mostafa_amer
Questions?
![Page 50: Protocol-Oriented Networking](https://reader031.fdocuments.us/reader031/viewer/2022021922/589bceec1a28ab92618b548f/html5/thumbnails/50.jpg)
Thank You@mostafa_amer
Questions?