Git Product home page Git Product logo

moya-modelmapper's Introduction

Moya-ModelMapper

CocoaPods

ModelMapper bindings for Moya for easier JSON serialization with RxSwift and ReactiveCocoa bindings.

Installation

CocoaPods

pod 'Moya-ModelMapper', '~> 10.0'

The subspec if you want to use the bindings over RxSwift.

pod 'Moya-ModelMapper/RxSwift', '~> 10.0'

And the subspec if you want to use the bindings over ReactiveSwift.

pod 'Moya-ModelMapper/ReactiveSwift', '~> 10.0'

Carthage

Specify in Cartfile:

github "sunshinejr/Moya-ModelMapper" ~> 10.0

Carthage users can point to this repository and use whichever generated framework they'd like, Moya-ModelMapper, RxMoya-ModelMapper, or ReactiveMoya-ModelMapper.

Swift Package Manager

Add the following as a dependency to your Package.swift.

.package(url: "https://github.com/sunshinejr/Moya-ModelMapper.git", .upToNextMajor(from: "10.0.0"))

The bindings are available through Moya_ModelMapper module. If you are interested in reactive extensions, use ReactiveMoya_ModelMapper or RxMoya_ModelMapper respectively.

Usage

Create a model struct or class. It needs to implement protocol Mappable.

import Foundation
import Mapper

struct Repository: Mappable {

    let identifier: Int
    let language: String? // Optional property
    let url: String? // Optional property

    init(map: Mapper) throws {
        try identifier = map.from("id")
        language = map.optionalFrom("language")
        url = map.optionalFrom("url")
    }

}

Then you have methods that extends the response from Moya. These methods are:

map(to:)
map(to:keyPath:)
compactMap(to:)
compactMap(to:keyPath)

While using map(to:) tries to map whole response data to object/array, with map(to:keyPath:) you can specify nested object in a response to fetch. For example map(to: User.self, keyPath: "data.response.user") will go through dictionary of data, through dictionary of response to dictionary of user, which it will parse. compactMap is a variant of array map that doesn't fail the whole operation if one of the objects fails, it will just remove the object from the array. RxSwift and ReactiveCocoa extensions also have all of the methods, but RxSwift have optional mapping additionally. See examples below, or in a Demo project.

1. Normal usage (without RxSwift or ReactiveCocoa)

provider = MoyaProvider<GitHub>(endpointClosure: endpointClosure)
provider.request(GitHub.repos("mjacko")) { (result) in
    if case .success(let response) = result {
        do {
            let repos = try response.map(to: [Repository].self)
            print(repos)
        } catch Error.jsonMapping(let error) {
            print(try? error.mapString())
        } catch {
            print(":(")
        }
    }
}

2. RxSwift

provider = MoyaProvider<GitHub>(endpointClosure: endpointClosure)
provider.rx.request(GitHub.repo("Moya/Moya"))
    .map(to: User.self, keyPath: "owner")
    .subscribe { event in
        switch event {
        case .success(let user):
            print(user)
        case .error(let error):
            print(error)
        }
}

Additionally, modules for RxSwift contains optional mappings. It basically means that if the mapping fails, mapper doesn't throw errors but returns nil. For instance:

provider = MoyaProvider<GitHub>(endpointClosure: endpointClosure)
provider.rx.request(GitHub.repos("mjacko"))
    .mapOptional(to: [Repository].self)
    .subscribe { event in
        switch event {
        case .success(let repos):
            // Here we can have either nil or [Repository] object.
            print(repos)
        case .error(let error):
            print(error)
        }
}

3. ReactiveSwift

provider = MoyaProvider<GitHub>(endpointClosure: endpointClosure)
provider.reactive.request(GitHub.repos("mjacko"))
    .map(to: [Repository].self)
    .observeOn(UIScheduler())
    .start { event in
        switch event {
        case .value(let repos):
            print(repos)
        case .failed(let error):
            print(error)
        default: break
        }
}

Author

Sunshinejr, [email protected], @thesunshinejr

License

Moya-ModelMapper is available under the MIT license. See the LICENSE file for more info.

moya-modelmapper's People

Contributors

asmallteapot avatar bbqsrc avatar bchrobot avatar ivanmkc avatar josefdolezal avatar juliengdt avatar lswith avatar maxim-inv avatar readmecritic avatar solidfox avatar sunshinejr avatar teameh avatar wberger avatar

Stargazers

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

Watchers

 avatar  avatar  avatar

moya-modelmapper's Issues

Carthage : The file “Info.plist” couldn’t be opened because there is no such file.

I'm having trouble building with Carthage

error: could not read data from '/Users/.../Documents/.../Carthage/Checkouts/Moya-ModelMapper/Info.plist': The file “Info.plist” couldn’t be opened because there is no such file.

Cartfile

github "hackiftekhar/IQKeyboardManager" "v5.0.6"
github "SnapKit/SnapKit" ~> 4.0.0

github "onevcat/Kingfisher" ~> 4.2.0
github "jrendel/SwiftKeychainWrapper" ~> 3.0

github "realm/realm-cocoa" ~> 3.0.1

github "RxSwiftCommunity/RxSwiftExt"
github "RxSwiftCommunity/RxRealm"

github "sunshinejr/Moya-ModelMapper" "7.0.0"

github "melvitax/DateHelper"

Xcode 9 & Swift 3.2 problem

The following code which was working perfectly in swift 3.1 gives me the bellow error in swift 3.2!

Ambiguous use of 'map(to:keyPath:)'

Here is my code:

provider.rx .request(.stages) .map(to: Stage.self) .subscribe() .addDisposableTo(disposeBag)

Should I change something in my model or something else comparing to the older version?

Project won't build when using Carthage

I'm getting the following error when building with Carthage versions (6.0.0 and 6.0.0-beta.1):

*** Fetching mapper
*** Fetching Result
*** Fetching Alamofire
*** Fetching ReactiveSwift
*** Checking out Moya-ModelMapper at "6.0.0-beta.1"
*** Downloading RxSwift.framework binary at "37"
*** Checking out Moya at "10.0.0-beta.1"
*** Checking out mapper at "7.3.0"
*** Checking out ReactiveSwift at "2.0.1"
*** Checking out Alamofire at "4.5.1"
*** Checking out Result at "3.2.4"

*** Skipped installing RxSwift.framework binary due to the error:
"Incompatible Swift version - framework was built with 4.0 (swiftlang-900.0.65 clang-900.0.37) and the local version is 4.0.2 (swiftlang-900.0.69.2 clang-900.0.38)."
*** Checking out RxSwift at "4.0.0-rc.0"
*** xcodebuild output can be found in /var/folders/tw/7hw467y973v8432d55mfsr440000gn/T/carthage-xcodebuild.OBVFMS.log
*** Building scheme "Alamofire iOS" in Alamofire.xcworkspace
*** Building scheme "Mapper" in Mapper.xcodeproj
*** Building scheme "Result-iOS" in Result.xcodeproj
*** Building scheme "ReactiveSwift-iOS" in ReactiveSwift.xcworkspace
*** Building scheme "RxBlocking-iOS" in Rx.xcworkspace
*** Building scheme "RxSwift-iOS" in Rx.xcworkspace
*** Building scheme "RxTests-iOS" in Rx.xcworkspace
*** Building scheme "RxCocoa-iOS" in Rx.xcworkspace
*** Building scheme "Moya" in Moya.xcodeproj
*** Building scheme "RxMoya" in Moya.xcodeproj
*** Building scheme "ReactiveMoya" in Moya.xcodeproj
*** Building scheme "Moya-ModelMapper" in Moya-ModelMapper.xcworkspace
Build Failed
Task failed with exit code 65:
/usr/bin/xcrun xcodebuild -workspace /Users/lior/Desktop/test/Carthage/Checkouts/Moya-ModelMapper/Moya-ModelMapper.xcworkspace -scheme Moya-ModelMapper -configuration Release -derivedDataPath /Users/lior/Library/Caches/org.carthage.CarthageKit/DerivedData/9.1_9B55/Moya-ModelMapper/6.0.0-beta.1 -sdk iphonesimulator -destination platform=iOS\ Simulator,id=2D9F0ACE-E9BA-48EC-A1E7-BECA93F33B0A -destination-timeout 3 ONLY_ACTIVE_ARCH=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= CARTHAGE=YES build (launched in /Users/lior/Desktop/test/Carthage/Checkouts/Moya-ModelMapper)

This usually indicates that project itself failed to compile. Please check the xcodebuild log for more details: /var/folders/tw/7hw467y973v8432d55mfsr440000gn/T/carthage-xcodebuild.OBVFMS.log

Please advise.
Thank you!

Please Help Me!

json data is:

{
    "data": [
        {
            "type": 1,
            "portraitimgurl": "/upload/product/firstlevel/shushangzhuang.jpg",
            "landscapeimgurl": "/upload/product/firstlevel/henshangzhuang.jpg",
            "count": 0
        },
        {
            "type": 2,
            "portraitimgurl": "/upload/product/firstlevel/shuqunzhuang.jpg",
            "landscapeimgurl": "/upload/product/firstlevel/henqunzhuang.jpg",
            "count": 0
        },
        {
            "type": 3,
            "portraitimgurl": "/upload/product/firstlevel/shukuzhuang.jpg",
            "landscapeimgurl": "/upload/product/firstlevel/henkuzhuang.jpg",
            "count": 0
        }
    ],
    "errcode": 0,
    "errmsg": "ok"
}
JefenProvider.request(.firstLevel) { result in
    switch result {
    case let .success(response):
        do {
            let models = try response.mapArray(withKeyPath: "data") as [Model]
            print(models)
        } catch {
            print("转成模型数组失败\(error)")
        }
    case let .failure(error):
        print("获取数据失败\(error)")
    }
}

models is nil ,why?

Root Array

Hi guys,
Have a problem:
initial data:
[ { "field1": "Value1", "field2": "Value2 }, { "field1": "Value1", "field2": "Value2 }, .....
Mapping such json - don't have any problem using: Response.map(to: [Custom].self)
But if I have empty root array [ ] - we got "Failed to map data to JSON." But there is no Failing to map. It is just empty array. Is not better to return empty array instead of error? Or maybe I do something wrong and there is another way?
Thanks.

Using with Moya/RxSwift

I'm not sure if this is an issue with Moya or Moya-ModelMapper so pardon me if it's not this. Anyway, I'm trying to add both libraries to a project via CocoaPods. Here's my Podfile.

platform :ios, '8.0'

target 'GithubIssueFinder' do
  use_frameworks!

  pod 'Moya/RxSwift'
  pod 'Moya-ModelMapper/RxSwift'

end

It installs the following versions. This is taken from the CoocoaPods installation console output.

Installing Alamofire (3.5.1)
Installing ModelMapper (2.1.0)
Installing Moya (7.0.4)
Installing Moya-ModelMapper (3.0.0)
Installing Result (2.1.3)

When I build my project I get various compiler errors.

screen shot 2017-01-08 at 10 26 09 pm

I assume this is because CocoaPods is picking up an old source or something?

"Extraneous argument label 'to:' in call" on "map(to:"

Hello,

I am getting "Extraneous argument label 'to:' in call" error. It seems that does not see the Response extension. Do you know what is the reason of it?

screen shot 2018-07-09 at 18 30 39

screen shot 2018-07-09 at 18 30 48

Here are my func and method.
Thanks.

Xcode 9.4
Swift 4.1
ModelMapper 8.0.0
Moya 11.0.2
Moya-ModelMapper 7.1.0

New Release?

New Release?

I've been trying to get transform to work. but I think the new model mapper did some changes to how it is being returned. Thanks!

5.0.0 Release

I would love to do 5.0.0 release in a near future. This would be almost just after the Moya 9.0.0 release. It should include:

  • SPM compatibility
  • Carthage compatibility
  • Better method naming
  • Moya 9 compatibility
  • If possible Swift 3.1/3.2/4.0 compatibility (probably 4.0 right now without Rx/ReactiveSwift)
  • Better error handling #38

Swift 5 support

Are there any roadmap decisions on Swift 5 support? Would be awesome with some beta releases that targets the corresponding Moya beta releases and Swift 5 releases of sub dependencies like RxSwift.

ObservableType extensions force observeOn calls

First time looking at the ModelMapper code (Thank You for implementing & sharing it!) I noticed something that is a problem:

The four map* functions contain observeOn calls in the chain. These really shouldn't be applied at this level because a) they cannot be overridden with my own scheduler, and b) should probably be left up to the subscriber (at the Moya call level) to properly observeOn and subscribeOn the correct schedulers.

I'm happy to submit a PR for this change. If not, I'll need to use a fork of the project because of this.

Map Dictionary

{
    "args": {},
    "data": "{\n\t\"target\": \"facebook\",\n\t\"token\": \"djkshksgjksgk\",\n\t\"username\": \"thienhaole92\",\n\t\"password\": \"123456\"\n}",
    "files": {},
    "form": {},
    "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "Cache-Control": "no-cache",
        "Connection": "close",
        "Content-Length": "104",
        "Content-Type": "application/json",
        "Host": "httpbin.org",
        "Postman-Token": "6e85dedb-6b8c-49fe-8d82-e83e85ea1b1c",
        "User-Agent": "PostmanRuntime/7.1.1"
    },
    "json": {
        "password": "123456",
        "target": "facebook",
        "token": "djkshksgjksgk",
        "username": "thienhaole92"
    },
    "origin": "116.118.112.156",
    "url": "https://httpbin.org/post"
}

How can I map json above to an object model? My object model has a variable type is Dictionary. Please help me

let args: [String: Any]?
let headers: [String: Any]?
let origin: String
let url: String

Type 'String?' does not conform to protocol 'ExpressibleByStringLiteral'

Well Hi,
I am having a problem in this code ->

let provider = MoyaProvider<APIType>(endpointClosure: APIProviderClosure, plugins: [NetworkLoggerPlugin(verbose: true)])
    provider.request(APIType.categories()) { (result) in
      if case .success(let response) = result {
        do {
          let activity = try response.mapObject(withKeyPath: "data.activities")
          Logger.log(msgTitle: "categories COUNT-->", msg: activity)
        } catch MoyaError.jsonMapping(let error) {
          Logger.log(msgTitle: "ERROR-->", msg: error)
        } catch {
          print(":(")
        }
      }
    }

Here When I am trying mapObject or mapArray It shows the error
Type 'String?' does not conform to protocol 'ExpressibleByStringLiteral'

But it works with mapString
Can you please let me know the issue?

Using XCode 8.3.1
no objectMapper installed

macOS, etc. support

This should be doable since all dependencies have support for macOS, watchOS, tvOS and iOS.

I have a fork with some Works on my Machine™ code that my Carthage setup is happy with. I can submit a pull request if you want.

Notice, however, that I'm by no means a cross platform cocoapod/carthage/swiftpm expert and only tested this with Carthage.

Upgrade to Moya 15, RxSwift 6

Hi,

We would like to upgrade our project to RxSwift 6, and Moya-ModelMapper is the last dependency that still has to be upgraded for that to be possible. Are there any plans to upgrade this project still?

Kind regards,

Sjors

Issues mapping Int's

Trying to map Int but not working. Here is my Mapper:

import Mapper
struct Login: Mappable {
    let accessToken: String
    let expirationDate: String
    let userId: Int

    init(map: Mapper) throws {
        try accessToken = map.from("access_token")
        try expirationDate = map.from(".expires")
        try userId = map.from("userId")
    }
}

Here is my response as caught from NetworkLoggerPlugin:

{ "userId" : "2", ".issued" : "Sat, 06 Aug 2016 15:59:19 GMT", ".expires" : "Fri, 04 Nov 2016 15:59:19 GMT", "token_type" : "bearer", "access_token" : "R7fVvk8yvjTvQZZAg1-jmzTeANcQ2MEbqZ7CryoCAa4dVBxY4BdBU5BXH-h9lD6WR0tNYCCGJygEKztsfXkEdjq-CUnnV4ZVbdU6aeXVrb4CP7qeHi8T-tSDaL9hde0BXM_rwm9woowNczF-6mKq6zpwLrIJebBCm83fVNLJUUalmLoxR7yZdumW_ssRoJAyAxQKCXaNWj5vVX08lEyif5nQwZYLchouECO_MljMcT7Et727BUHzu3yTz1bsSdSsLLXERhd_Jfkf2Ch8RnAA6BX2zMM4XLowCRgmyf0MwsMTpIfBsroZi-VwLFrS6iNEOOneyVfotHd9k7bdPxrJiT3IMXjWheE_h2PzxNc-khYTjelnrv2JiXNcVtaLdyD5NFodA4syjeIyc8DcLpYugNU8D9sPeM-PmO5JsIMRU2LUC07XgldsfVquUae07dlHgY6MbPnMcV5-0aFtTVV496wxFlhE37G5ptaa_IM", "expires_in" : 7775999 }

This is the request:

loginResponse = input.loginTaps.flatMapLatest{ _ -> Observable<Login?> in
            return input.provider.request(.Login(email: "pau6l", password: "Password1!")).mapObjectOptional(Login.self)
        }

The response ends up being nil. As soon as I change from Int to String, everything works. As a side note any easy way to map dates? would be nice to map that .expires

Json parsing without array name

I have a Json Array as string without name and I want to parse it how can i do it i ? Thank you.

["abc","def","123","456", "890"].

Map object types

Ho do i map objects like this :

let kStreamFeedEntry    = "feed_entry"
let kStreamPrediction   = "prediction"
let kStreamMetadata     = "metadata"

struct FPStream : Mappable {

    var streamFeedEntry:FPFeedEntry
    
    init(map: Mapper) throws {
        try streamFeedEntry = map.from(kStreamFeedEntry)
    }
}

Please help me, im pretty new to Rx and im having a difficult time, you are lifesaver, if it wasnt for u i wouldnt reach this far. Thank you

"Missing argument for parameter 'transformation' in call"

Hi!

Every time I try to map to a NSNumber value, it gives me this error. For example:

struct User: Mappable {

let userId: NSNumber

init(map: Mapper){
   try userId = map.from("user_id")
}

If I changed the property from NSNumber to Int, it works fine. Am I missing something here?

iOS version 8.0

I have a problem with my not-too-old project updating to Swift 3.0.

The only dependancy that cannot be satisfied is the Moya-ModelMapper requiring minimum deployment target of 9.0 for iOS.
Looking through the .podspec file I cannot find any reason for this, because Moya and ModelMapper both require minimum deployment target of 8.0 for iOS. OSX minimum deployment target also could be lowered to 10.10

Maybe there is something that requires iOS 9.0. Could you confirm, please?

Mapping an array of garages (Google Places API)

Hi,

I'm consuming the Google Places API with Moya/RxSwift/RxCocoa/ModelMapper and trying to bind the results (garages) into a tableview/array.

Model:

import Mapper
struct Garage : Mappable {
    var id: Int!
    var name: String!
    var vicinity: String?
    var iconURL: String?
    var rating: Double?

    init(map: Mapper) throws {
        try id = map.from("id")
        try name = map.from("name")
        vicinity = map.optionalFrom("vicinity")
        iconURL = map.optionalFrom("icon")
        rating = map.optionalFrom("rating")
    }   
}

Controller:

override func viewDidLoad() {
    disposeBag = DisposeBag()
        provider = RxMoyaProvider<GooglePlaces>()
        garagesFromLosAngeles()
            .bindTo(tableView.rx.items(cellIdentifier: "GarageCell", cellType: GarageTableCell.self)) { (row, model, cell) in
                cell.nameLabel.text = model.name
            }
            .addDisposableTo(disposeBag)
}

func garagesFromLosAngeles() -> Observable<[Garage]> {
        return self.getGarages(location: "34.052235,-118.243683", type: "car_repair", radius: 5000, key: GooglePlacesAPI.token)
    }

    internal func getGarages(location: String, type: String, radius: Int, key: String) -> Observable<[Garage]> {
        return self.provider!
            .request(.getGarages(location: location, type: type, radius: radius, key: key))
            .mapArray(type: Garage.self, keyPath: "results")

    }

Moya TargetType protocol:

// MARK: - TargetType Protocol Implementation
enum GooglePlaces : TargetType {
    case getGarages(location: String, type: String, radius: Int, key: String)
    case getPhoto(photo: Photo, key: String)

    var baseURL: URL { return URL(string: "https://maps.googleapis.com/maps/api/place")! }

    var path: String {
        switch self {
        case .getGarages:
            return "/nearbysearch/json"
        case .getPhoto:
            return "/photo"
        }
    }
    var method: Moya.Method {
        switch self {
        case .getGarages, .getPhoto:
            return .get
        }
    }
    var parameters: [String: Any]? {
        switch self {
        case .getGarages(let location, let type, let radius, let key):
            return ["location": location, "type": type, "radius": radius, "key": key]
        case .getPhoto(let photo, let key):
            return ["maxwidth": photo.w, "maxheight": photo.h, "photoreference": photo.reference, "key": key]
        }
    }
    var sampleData: Data { return Data() }

    var task: Task {
        switch self {
        case .getGarages, .getPhoto:
            return .request
        }
    }
}

JSON: https://maps.googleapis.com/maps/api/place/nearbysearch/json?key=AIzaSyDffA3hy-NGKiioEwNg6jtSFI3qaOsxCpA&location=34.052235,-118.243683&radius=5000&type=car_repair

I'm getting the result: Binding error to UI: jsonMapping(Status Code: 200, Data Length: 35369)

Regards
VVL

Rx extensions broken?

The source files Single+ModelMapper.swift (and ObservableAvailability.swift) are not included in the Moya-ModelMapper Xcode project. As a consequence, .mapOptional(to:keyPath:) is not found. (I can work around this by copying Response+ModelMapper.swift and Single+ModelMapper.swift to my own project instead of linking the Moya-ModelMapper framework)

screen shot 2017-09-13 at 02 08 24

Conforming to the Swift API Guidelines.

So I didn't really have time to check all the functions for proper conformation to new Swift API Guidelines, and because of #26 we will have another major bump, so this is the best time to make a PR with naming changes in the functions. If anyone is up for a starter task, this is the link to the guidelines I'm talking about.

Map header of response

Hello, could you please help me,
How can I map header of response?
For example:

Response: <NSHTTPURLResponse: 0x60c000229a00> { URL: http://some.com/api/v1/auth/sign_in } { status code: 200, headers {
    "Cache-Control" = "";
    Connection = "";
    "Content-Type" = "";
    Date = "";
    Etag = "";
}

How can I map from header all this fileds? Of course if it possible.
Do you have some examples?

Thank you!

RealmSwift

Is there a way to make this work with Realm?
At the moment Realm use ObjectMapper which also implement the Mappable protocol.
Would it be possible to have them work together?

I've attempted to use the transform struct to create my own conversion without luck so far.

public static func transformToList<T: Object>() -> (_ object: Any) throws -> List<T> where T: Mappable
	{
		return { object in
			guard let objects = object as? [String: Any] else {
				throw MapperError.convertibleError(value: object, type: Any.self)
			}

			var result = List<T>()
			for entry in objects {
				let model = try! T(map: Mapper(JSON: entry))
				result.append(model)
			}

			return result
		}
	}

for some reasons the let model = try! T(map: Mapper(JSON: entry)) method isn't recognize.

Carthage Support

Do you have any plans to add support for Carthage? Would love to add this nice mapper into an existing project that doesn't have the option to use CocoaPods.

How do you convert a mappable object to json?

I'm able to deserialize just fine, but can't seem to figure out how to serialize TO json. Would love some guidance. I'd like to use this json in a POST request body. The examples aren't that clear to me.

Thanks in advance

Better error handling

Hi @sunshinejr! While using this awesome library (now with Swift PM, haha), we sometimes have a really hard times debugging the mapping errors. Usually when the backend API spec is not clear about types or fields requirement, the mapping fails. When this happens, the Mapper throws message like this:

jsonMapping(Status Code: 200, Data Length: 11762)

Now it's pretty hard to say what and why happened - you have to use debugger and/or debug prints. Yay!

I propose small update of Mapper extension to rethrow Mapper errors as associated values of MoyaError.underlaying.

The code (referencing Response+ModelMapper.swift) would look like:

public func mapObject<T: Mappable>() throws -> T {
    guard let jsonDictionary = try mapJSON() as? NSDictionary else {
        throw MoyaError.jsonMapping(self)
    }

    do {
        return try T(map: Mapper(JSON: jsonDictionary))
    } catch {
        throw MoyaError.underlying(error)
    }
}

Which is just a little bit more complex but gives nice and clear errors:

underlying(Mapper.MapperError.missingFieldError("tags"))

The change is not breaking in sense of source compatibility, but requires to observe for both .jsonMapping and .underlying errors. Would you be interested in PR?

Skipping unsuccessful mappings

Hello,

sometimes I need to skip unsuccessful mappings. For example I have a message model and get an array of messages from the server, which I want to map into an Array of message objects via Moya Modelmapper. I know the response shouldn't response wrong values like in the example below (messageid 50), but in case if, I want to skip this message and go on. Actual my mapping ends in the catch-Block, and doesn't receive only the messages who are successful.
Is there a possibility to skip these mappings, so that I can return a array only with message 1?

Here is my Example:

Response:

[ 
   { "messageid": 1,
     "sender": { "id": 1, ... },
     "message": "hello",
     "created": "2017-09-06T16:52:32.596Z"  
   }, 
   { "messageid": "50",
     "sender": { "id": 1, ... },
     "message": "hello",
     "created": "2017-09-06T16:52:32.596Z"  
   }
]

Model:

class Message: Mappable {
  
  // MARK: - Stored Properties
  var messageId: Int
  var sender: User
  var message: String
  var created: Date
  
  // MARK: - Initializer
  required init(map: Mapper) throws {
    try messageID = map.from("messageid")
    try sender = map.from("sender")
    try message = map.from("message")
    try created = map.from("created", transformation: map.toDate)
  }
}

DataService:

class DataService {

static func getMessages(userid: Int, success successCallback: @escaping successCallback, error errorCallback: @escaping errorCallback, failure failureCallback: @escaping failureCallback) {
    
    provider.request(.getMessages(userid: userid)) { (result) in
      
      switch result {
        case .success(let response):
          do {
            if response.statusCode >= 200 && response.statusCode <= 300 {
              let messages: [Message] = try response.map(to: [Message].self) // here I want to skip unsuccessful mappings and return a message array only with the successful mappings
              successCallback(messages)
            } else {
              errorCallback(Error.parsing(Class: "DataService", Method: "getMessages.else"))
            }
          } catch {
            // generate parsing error and send it to errorCallback
            errorCallback(Error.parsing(Class: "DataService", Method: "getMessages.catch"))
          }
        case .failure(let error):
          failureCallback(error)
        }
      }
    }
}

No ability to inject own scheduler

I'm using RxTest to test my network services which makes use of a virtual time TestScheduler. However, in Single+ModelMapper, you have fixed schedulers which are incompatible with RxTest as they would have to be replaced by the TestScheduler for unit tests. Similar discussion is here: ReactiveX/RxSwift#1100

Fix would be to do dependency injection of schedulers, perhaps with a default value.

Problematic code here:

public func map<T: Mappable>(to type: T.Type, keyPath: String? = nil) -> Single<T> {
        return observeOn(ConcurrentDispatchQueueScheduler(qos: .background))
            .flatMap { response -> Single<T> in
                return Single.just(try response.map(to: type, keyPath: keyPath))
            }
            .observeOn(MainScheduler.instance)
    }

Handling of null values of respones?

I'm mapping this JSON object:

{
...
"completedDate": null,
...
}

struct TaskResult : Mappable{
.....
let completedDate : Int?
}
return MyProvider.rx.request(.request005())
.debug()
.mapOptional(to: [TaskResult].self, keyPath: "data")

I got a nil mapping result ,any idea?

Scheduler choice

Hi there
I was looking at the code of this extension and was wondering if you could explain why you chose to use a SerialDispatchQueueScheduler here:

Why is this a better choice than a ConcurrentDispatchQueueScheduler?

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.