This is the 13th day of my participation in the Gwen Challenge.More article challenges

What is Moya?

In fact, there is nothing particularly mysterious about Moya. As I said about Alamofire in the last article, it is just an encapsulation layer of Alamofire. However, it can encapsulate network requests to this extent, which can also show its great force.

Encapsulation is extreme, that’s it.

Star is up to 13.1K, can ordinary people do it?

Why Moya?

Here I have to quote the official:

You're a smart developer. You might use Alamofire to abstract access to URLSession and all those nasty details you don't care about. But then, like many smart developers, you write proprietary network abstraction layers, which may be called "APIManager" or "NetworkModel, "and they always end badly.

So the basic idea of Moya is to provide some layer of network abstraction that is fully encapsulated and calls Alamofire directly. They should be simple enough to handle common tasks easily, and comprehensive enough to handle complex tasks equally easily.

As early as when I was just engaged in iOS, all kinds of NetworkTool and HttpUtils written by predecessors made me admire. However, as I wrote more code and contacted different businesses, I felt more and more that those problems mentioned in Moya were really pain points and difficulties:

  • The network layer can only match one App, because it combines too much logic in the App.

  • Sometimes the network layer cannot match all the services, resulting in the need to write a separate Alamofire request for an interface.

  • The componentization effect of decoupling failed to achieve the desired effect. I also tried to encapsulate the network layer myself, feeling that I had exhausted my primordiousness, and then found that there were still some missing places, which was not satisfactory.

Two heads are better than one, let alone Moya, which was written by so many GitHub titans.

The use of Moya

  • First I would like to say that Moya is very friendly and has official Chinese documentation.

  • Moya’s programming is protocol-oriented, and once you comply with TargetType, the methods must be implemented, so the rigor of the code saves you a lot of mistakes.

Here I will use two interfaces to play Android as an example. Please pay attention to the comments in the code:

An Api for collating requests

Struct Api {/ / / baseUrl static let baseUrl = "https://www.wanandroid.com/" private init () {} / / / the public is a get request enum PublicNumber { static let tags = "wxarticle/chapters/json" static let tagList = "wxarticle/list/" } }Copy the code
  • Business Provider writing
Import Foundation import Moya /// generate a publicNumberProvider let publicNumberProvider: MoyaProvider<PublicNumberService> = { let stubClosure = { (target: PublicNumberService) -> StubBehavior in return .never } return MoyaProvider<PublicNumberService>(stubClosure: stubClosure, plugins: [RequestLoadingPlugin()])}() {// get all tags // case tags // single tags // Case tagList(_ id: Int, _ page: Int)} TargetType {/// return baseURL var baseURL: URL {return URL(string: api.baseurl)! Var path: String {switch self {case.tags: return Api.PublicNumber.tags case .tagList(let id, let page): Return api.publicNumber.taglist + id.tostring + "/" + page.tostring + "/json"}} Since both services are GET requests, there is no switch case statement var method: Moya.Method {return. Get} /// mock data is used for debugging. Data {return Data()} /// Switch case statement var task: Task { return .requestParameters(parameters: [:], encoding: Urlencoding. default)} /// request headers: [String: String]? {return nil}}Copy the code

In fact, before using Moya, it is very important to sort out the request interfaces in your App and classify different services. Only by finding common ground and classifying them together can they better reflect their value.

Since I’m using RxMoya, this is an example:

publicNumberProvider.rx.request(PublicNumberService.tags).map(BaseModel<[Tab]>.self)

publicNumberProvider.rx.request(PublicNumberService.tagList(id, page)).map(BaseModel<Page<Info>>.self)
Copy the code

For a general example of Moya, look at the official documentation:

provider = MoyaProvider<GitHub>()
provider.request(.zen) { result in
    switch result {
    case let .success(moyaResponse):
        let data = moyaResponse.data
        let statusCode = moyaResponse.statusCode
        // do something with the response data or statusCode
    case let .failure(error):
        // this means there was a network failure - either the request
        // wasn't sent (connectivity), or no response was received (server
        // timed out).  If the server responds with a 4xx or 5xx error, that
        // will be sent as a ".success"-ful response.
    }
}
Copy the code

Moya also supports Codable JSON and returns results. What about Swift’s enum?

  • The plug-in

By following the PluginType protocol of Moya, we can customize different plugins for different services to meet some pre-processing before request and after response. It is not particularly similar to other languages’ interceptor functions. Here are some plugins from the web:

import Moya import MBProgressHUD class RequestLoadingPlugin: PluginType { func prepare(_ request: URLRequest, target: TargetType) -> URLRequest { print("prepare") var mRequest = request mRequest.timeoutInterval = 20 return mRequest } func  willSend(_ request: RequestType, target: TargetType) {print (" began to request ") DispatchQueue. Main. The async {MBProgressHUD. BeginLoading ()}} func didReceive (_ the result: Result<Response, MoyaError>, target: TargetType) {print (" request ") / / off loading DispatchQueue. Main. The async {MBProgressHUD. StopLoading ()} switch result {case .success(let response): if response.statusCode == 200 { if let json = try? JSONSerialization.jsonObject(with: response.data, options: .mutableContainers), let data = try? JSONSerialization.data(withJSONObject: json, options: .prettyPrinted), let _ = try? String(data: data, encoding: .utf8) {print(json)}}else {dispatchqueue.main.async {mbProgresshud. showText("statusCode not 200")}} case .failure(let error): print(error.localizedDescription) } } func process(_ result: Result<Moya.Response, MoyaError>, target: TargetType) -> Result<Moya.Response, MoyaError> { return result } }Copy the code

The plug-in’s function is simple: loading begins at the request and ends after the request.

I’ve wrapped a little bit of MBProgressHUD here, so you can do whatever you want.

conclusion

  • Strict writing patterns
  • Simple way to call
  • Clear result callback,
  • Flexible plug-in combination

All of this is enough to give you a need for different businesses, and once you try Moya, I think you’ll get rid of the so-called network encapsulation layer and achieve great unification through Moya.

Tomorrow to continue

Dragon Boat Festival the second day more, tomorrow is going to talk about a small skill, although not practical but interesting, everyone refueling.