Giter Club home page Giter Club logo

mhnetwork's Introduction

MHNetwork

Protocol Oriented Network Layer Aim to avoid having bloated singleton NetworkManager

Build Status Coverage Status

Philosophy

the main philosophy behind MHNetwork is to have a single responsibility. it makes it much easier to determine where is the problem located in your code if every class in your code have only one task and one task only to do. so in the beginning..

install

$ pod install MHNetwork

or in your podfile

pod 'MHNetwork'

also you can use Swift Package Manager

usage

let's say you have movies API .. and you need to make a request call to get the movies list..

you will need to create two files for your feature MoviesRequests.swift and MoviesTasks.swift

in the request it should be something like this


import Foundation
import MHNetwork

enum MoviesRequests: Request {
    case getMoviesList

    var path: String {
        return "movies/list/"
    }

    var method: HTTPMethod {
        switch self {
        case .getRandomQuote:
            return .get
        }
    }

    var parameters: RequestParams {
        return .url(["year" : "2018"])
        // can use .body(["year": "20018"]) if the api require body parameters
    }

    var headers: [String : Any]? {
        return ["Authorization": "xyz"]
    }
}

then add your task


class MovieTasks <T: Codable>: Operations {

    var request: Request {
        return MoviesRequests.getMoviesList
    }

    func execute(in dispatcher: Dispatcher, completed: @escaping (Result<T, NetworkError>) -> Void) {

        do {
            try dispatcher.execute(request: self.request, completion: { (result) in
               switch result {
                               case .success(let response):
                                   switch response {
                                       case .data(let data):
                                           do {

                        let decoder = JSONDecoder()
                        //                        decoder.keyDecodingStrategy = .convertFromSnakeCase
                        //                        uncomment this in case you have some json properties in Snake Case and you just want to decode it to camel Case... workes only for swift 4.1 or higher
                        let object = try decoder.decode(T.self, from: data)
                                               completed(.success(object))
                                           } catch let error {
                                               print("error Parsing with Error: \(error.localizedDescription)")
                                           }
                                           break
                                       case .error(let error):
                                           completed(.failure(error))
                                           break
                                       }
                               case .failure(let error):
                                   completed(.failure(error))
                               }
            })
        } catch {
          completed(.failure(.error(code: nil, error: error, data: nil)))
        }
    }
}

that's it you finished your basic setup for the request.. now you can call it from your code like that

func getMoviesList(onComplete: @escaping (Movie) -> Void, onError: @escaping (Error) -> Void) {
    let environment = Environment(host: "https://imdb.com/api")
    let networkDispatcher = NetworkDispatcher(environment: environment, session: URLSession(configuration: .default))
    let moviesTask = MoviesTasks<Movie>() // Movie Model should be codable
    moviesTask.execute(in: networkDispatcher) { (result) in
          switch result {
            case .success(let users):
                onCompletion(movies)
            case .failure(let error):
                onError(error)
            }
         })
}

that's it.. one last note.. when creating the instance of MoviesTask you noticed the comment that Movie Model should be Codable well.. it's not a must but my preferable way.. just suit yourself in the task itself and make it less restricted if you like but you'll need to handle the returned data in another way.

TODO://

  • need to support JSON return type without depending on any 3rd party
  • need to fix & clean the example test cases and code

Contribute://

fork / edit / and Pull request to Develop Branch... you know what to do ;)

mhnetwork's People

Contributors

emadhegab avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

mhnetwork's Issues

Misprint in code

execute
missed "c" button in protocol declaration so class which implements this protocol should use the same mistaken name

Feature request - optional params

For example I need a library to collect rss from different websites. I need to specify single url only and get/post method only for each website. You library requires to setup all params even if they are not necessary

Broken CocoaPods

[!] Error installing MHNetwork
[!] /usr/bin/git clone https://github.com/emadhegab/MHNetwork.git /var/folders/sy/4_wxmzmj75j733p9k30rms7d7rjblp/T/d20191121-37386-1mduuyp --template= --single-branch --depth 1 --branch 1.1

Cloning into '/var/folders/sy/4_wxmzmj75j733p9k30rms7d7rjblp/T/d20191121-37386-1mduuyp'...
warning: Could not find remote branch 1.1 to clone.
fatal: Remote branch 1.1 not found in upstream origin

Feature request - add log

Currently I try to connect to API with GET requests. The problem is when I get an error I don't see the final request URL - it is hidden somewhere inside this library.
What about to add some log (at least for visible url part)?

I could inherit from NetworkDispatcher but:
Cannot inherit from non-open class 'NetworkDispatcher' outside of its defining module

How to create a request with varying params?

For example in your code with getMoviesList I want to pass an additional param - "year".
I send the same requests but with different year value specified from outside.
How to implement it?

Bug in NetworkDispatcher

return URLQueryItem(name: element.key, value: element.value as? String)
This allows to pass string params only. But if you replace element.value as? String with \(element.value) it will accept for example int and bool values too.

Additionally NetworkDispatcher is protected from inheritance and I should create a copy of it

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.