Decodable to JSON Swift 4 - json

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.

Related

Retaining unknown keys during JSON (de)serialization with Codable

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?

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.

How to make a swift Codable struct that will decode and encode a MongoDB _id ObjectId() in JSON

I'm a very new developer(this is my first dev job) building a Swift/iOS application for creating/processing orders, and the server is sending me a ObjectID() object in JSON with every product I look up. After some research, it seems like this is a MongoDB object.
The gentleman coding my API routes wants me to grab that object for every product the server sends me, so I can send it back to the server with any orders that include that product. He says that will make it much easier for him to access the product when processing new orders.
So far, I've had no trouble decoding the JSON the server is sending me, because it's been in formats like String, Int, Float, etc., or just another JSON object that needs a new Codable struct full of more of the same.
When it comes to creating a Codable struct for an ObjectID, I don't know what keys/value types (properties/value types, whatever terminology you want to use) to tell it to expect. Or if this is even the correct way to go about it.
This is what I have right now:
import Foundation
struct ProductData: Codable {
let _id : ObjectId
let productId : String
let description : String
let ...
}
The ObjectId type appearing above is a custom Codable struct that I haven't built yet, because I'm not sure how. I imagine it should look something like this:
import Foundation
struct ObjectId : Codable {
let someVariableName : SomeCodableType
let ...
}
I don't know what the variable name or the type would be. I understand that it has a timestamp and some other information inside of it, and I've read about it being represented as a string, but I get the feeling if I try something like let _id:String in my product Codable struct, it won't decode/encode the way I'm imagining.
I'm wondering how to build a "type" that will properly catch/decode the _id object that is being thrown at me. If there's a way to simply hold that data without decoding it, and just send it back when I need to later, that would also suit my purposes.
EDIT:
After some experimentation, I found this raw JSON for the _id object:
"_id":{"$id":"58071f9d3f791f4f4f8b45ff"}
Dollar signs are not allowed in Swift variable/property names, so I'm unsure how to proceed in a way that satisfies both the incoming AND outgoing - I could make a custom key by manually initializing the JSON so it will properly work with Swift, but I'm unsure if there's a way to reverse that when encoding the same object back into JSON to send back to the server.
Catching the JSON as a Dictionary of [String:String] seemed to do the trick.
import Foundation
struct ProductData: Codable {
let _id : [String:String]
let productId : String
let description : String
let ...
}
However, the server is struggling to convert this back into an OrderId() object - I'm guessing that the translation from "$id":OrderId("someid") to "$id":"someid" is not what should happen.

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.

Is it possible to have a struct with multiple JSON tags?

I post a request to a server and get a reply in JSON format. I'm able to unmarshal it to a struct. Then I need to create a new JSON file with the same data but different JSON tags.
Example:
In the following code, I get {"name":"Sam","age":20} from a server and unmarshal it to the struct Foo:
type Foo struct {
Name string `json:"name"`
Age int `json:"age"`
}
Then I need to change the tag name to employee_name and omit age:
type Bar struct {
Name string `json:"employee_name"`
Age int `json:"-"`
}
After that I send this modified data to another server.
I know I could just create a new Bar and copy all data into it, but there are a lot of fields. I was wondering if there is a way to attach multiple JSON tags like this:
type Foo struct {
Name string `json:"name" json:"employee_name"`
Age int `json:"age" json:"-"`
}
Thanks in advance.
It's not possible. The encoding/json package only handles the json key in struct tags. If the json key is listed multiple times (as in your example), the first occurrence will be used (this is implemented in StructTag.Get()).
Note that this is an implementation restriction of the encoding/json package and not that of Go. One could easily create a similar JSON encoding package supporting either multiple tag keys (e.g. json1, json2) or multiple occurrences of the same key (as in your example).
What is possible though, with 2 identically laid out structs (namin, types and ordering of fields needs to match exactly) is to cast from one to the other. I would be very cautious of doing this though and make sure the 2nd type (bar in your example) is unexported to prevent from being used elsewhere.
https://play.golang.org/p/y8EH1U9_3jN