Retaining unknown keys during JSON (de)serialization with Codable - json

I'm using Codable to convert between JSON and a Swift object. The process goes like this:
JSON -> Swift object
Modify the Swift object
Swift object -> JSON
The issue is that if the original JSON contains unknown keys, they are removed during the conversion to the Swift object and then back to JSON. Is there a way to retain these unknown keys during the conversion process?

Related

How do you efficiently handle highly dynamic JSON structures in Swift?

I am writing a Swift program to interact with our backend Database. These database tables can change format, and each row is from DynamoDB and is represented by a JSON object. Within the program, it will grab the cache from the server which contains the Database structures and then the current contents of the database. I don't want to hardcode the database structures into the app as that would obviously make this too very hard to maintain. What is the best way to read in these rows into a generic dictionary object with dynamic names that can hold any of the JSON types?
One way you can handle parsing dynamic JSON is to have a key or a set of keys that gives information about which type of model to decode. For example, you can have a key type in your JSON objects:
{
...
"type": "some type"
...
}
and an intermediate model:
struct IntermediateModel: Codable {
let type: String // or enum
}
you first decode all your JSON objects to the intermediate model and then decode them to the actual model type based on the value of type.
I have written some helper protocols that make this easier here.

Is it possible to deserialize data that looks like JSON (but isn't) using serde_json?

I have a hard time deserializing (using Rust's serde and serde_json v1.0) the following JSON I receive:
{
["string content"]
}
The object's array is not identified by a key, so the following doesn't work:
#[derive(Deserialize)]
struct Data {
key: Vec<String>
}
I've also tried using #[serde(flatten)] on the key field but I get an error:
can only flatten structs and maps (got a sequence)
The data I receive doesn't look like valid JSON. Is it still possible using serde_json?
The input you show is not valid JSON. You will not be able to use serde_json to deserialize that input because serde_json only accepts JSON.
If you find out what format the data is intended to be in, consider using (or writing) a Rust library dedicated to that specific format.

Decodable to JSON Swift 4

I was convert DATA to Decodable struct. Now I have to store "Decodable struct" in KeyChain. But There is no way to store decodable struct in keychain. Is there any way?
I was used
https://medium.com/ios-os-x-development/securing-user-data-with-keychain-for-ios-e720e0f9a8e2 for keychain. and this for https://roadfiresoftware.com/2018/02/how-to-parse-json-with-swift-4/ Json parsing. I want to store Decodable object in Keychain.
You can store JSON or Property List data as secure note.
In the query dictionary pass an appropriate string identifier as value for key kSecAttrService and "secure note" as value for key kSecAttrDescription.

UnmarshalJSON any type from []interface{} possible?

When you unmarshal JSON to []interface{} is there any way to automatically detect the type besides some standard types like bool, int and string?
What I noticed is the following, Let's say I marshal [uuid.UUID, bool] then the JSON I get looks like:
[[234,50,7,116,194,41,64,225,177,151,60,195,60,45,123,106],true]
When I unmarshal it again, I get the types as shown through reflect:
[]interface{}, bool
I don't understand why it picked []interface{}. If it cannot detect it, shouldn't it be at least interface{}?
In any case, my question is, is it possible to unmarshal any type when the target is of type []interface{}? It seems to work for standard types like string, bool, int but for custom types I don't think that's possible, is it? You can define custom JSON marshal/unmarshal methods but that only works if you decode it into a target type so that it can look up which custom marshal/unmarshal methods to use.
You can unmarshal any type into a value of type interface{}. If you use a value of type []interface{}, you can only unmarshal JSON arrays into it, but yes, the elements of the array may be of any type.
Since you're using interface{} or []interface{}, yes, type information is not available, and it's up to the encoding/json package to choose the best it sees fit. For example, for JSON objects it will choose map[string]interface{}. The full list of default types is documented in json.Unmarshal():
To unmarshal JSON into an interface value, Unmarshal stores one of these in the interface value:
bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null
Obviously if your JSON marshaling/unmarshaling logic needs some pre- / postprocessing, the json package will not miraculously find it out. It can know about those only if you unmarshal into values of specific types (which implement json.Unmarshaler). The json package will still be able to unmarshal them to the default types, but custom logic will obviously not run on them.

Validate and parsing JSON with Argonaut

I need parse some JSON into Scala instance or into error JSON.
For example if I have next JSON:
{"user":"us","password":"pass"}
and I have constraint that "user" shouldn't be less than 3. And then I should get next error JSON:
{"user":"us", "_error_user":"Username length shouldn't be less than 3","password":"pass"}
But for JSON {"user":"user","password":"pass"} I should get some Scala instanse like User("user","pass").
Is it possible using Argonaut?