Moya: Send JSON parameter that has an array field

Created on 24 Oct 2019  路  2Comments  路  Source: Moya/Moya

Basically my question is similar as this one

I have an object like so:

struct Service: Codable {
        let id: String
        let completed: Bool
}

my Moya task has the following parameters:

return .requestParameters(parameters: ["work_id" : work.id, "services": work.services],
                                      encoding: JSONEncoding.prettyPrinted)

As you may guess work.services is an array [Service]. The services inside the JSON should be like:

services: [
    { id: String,
    completed: Boolean },
    ...
],

But I'm getting *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (_SwiftValue)'

How can I make it work?

Most helpful comment

The encoding JSONEncoding.prettyPrinted uses the given [String: Any] and converts it to JSON using Apple's JSONSerialization.data(withJSONObject:).
Here is the doc of this function:

If obj will not produce valid JSON, an exception is thrown. This exception is thrown prior to parsing and represents a programming error, not an internal error. You should check whether the input will produce valid JSON before calling this method by using isValidJSONObject(_:).

Your Service is not a valid JSON Object, hence it crashes.
However, as you Service object is Encodable you can use the task .requestJSONEncodable instead.

All 2 comments

The encoding JSONEncoding.prettyPrinted uses the given [String: Any] and converts it to JSON using Apple's JSONSerialization.data(withJSONObject:).
Here is the doc of this function:

If obj will not produce valid JSON, an exception is thrown. This exception is thrown prior to parsing and represents a programming error, not an internal error. You should check whether the input will produce valid JSON before calling this method by using isValidJSONObject(_:).

Your Service is not a valid JSON Object, hence it crashes.
However, as you Service object is Encodable you can use the task .requestJSONEncodable instead.

Thanks a lot @amaurydavid I didn't know about the .requestJSONEncodable. For those that don't wanna extend their object to Encodable you can map an array to a dictionary. In this case would be like so:

let dict = work.services.map { ["id": $0.id, "completed": $0.completed] }
return .requestParameters(parameters: ["work_id" : work.id, "services": dict],
                                      encoding: JSONEncoding.prettyPrinted)

it does also works

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cocoatoucher picture cocoatoucher  路  3Comments

geraldeersteling picture geraldeersteling  路  3Comments

ghost picture ghost  路  3Comments

JoeFerrucci picture JoeFerrucci  路  3Comments

sunshinejr picture sunshinejr  路  3Comments