Vapor3 JSON encode & Decode
Vapor3 JSON encode & Decode
I'm having to use a FoundationDB database for a project. It stores data as a key:value pair stored as Bytes. I want to store a JSON object mapped to a struct I have. I want to be able save the data as an encoded JSON object and then be able to recreate the JSON object by reading the value Bytes from the DB.
In my CreateRecord function I pass a JSON in a request and use it to create my Country object. I need to convert the type Data into Bytes to store it.
So far I have come up with this.
let data: Bytes = try JSONEncoder().encode(country).base64URLEncodedString()
Then, when I read the record from the database I need to be able to reverse the process to create my Country object from the Bytes that store the JSON.
let mycountry:Country = try decoder.decode(Country.self, from: Data(bytes: DBrecord.value) )
The struct
is:
struct
struct Country: Content {
var country_name: String
var timezone: String
var default_PickUp_location: String = ""
init(country_name: String, timezone:String, default_PickUp_location: String?) {
self.country_name = country_name
self.timezone = timezone
if default_PickUp_location != nil {
self.default_PickUp_location = default_PickUp_location!
}
}
}
And a sample JSON is:
{ "country_name" : "Denmark", "timezone" : "Europe/Copenhagen", "default_pickup_location" : "Copenhagen" }
I cannot seem to be able to reverse the conversion. Any help please?
Yes, here it is:
{ "country_name" : "Denmark", "timezone" : "Europe/Copenhagen", "default_pickup_location" : "Copenhagen" }
– salongley
yesterday
{ "country_name" : "Denmark", "timezone" : "Europe/Copenhagen", "default_pickup_location" : "Copenhagen" }
And my Country struct
import Foundation import Vapor struct Country: Content { var country_name: String var timezone: String var default_PickUp_location: String = "" init(country_name: String, timezone:String, default_PickUp_location: String?) { self.country_name = country_name self.timezone = timezone if default_PickUp_location != nil { self.default_PickUp_location = default_PickUp_location! } } }
– salongley
yesterday
import Foundation import Vapor struct Country: Content { var country_name: String var timezone: String var default_PickUp_location: String = "" init(country_name: String, timezone:String, default_PickUp_location: String?) { self.country_name = country_name self.timezone = timezone if default_PickUp_location != nil { self.default_PickUp_location = default_PickUp_location! } } }
2 Answers
2
In your JSON, you use default_pickup_location
and in your struct
you use default_PickUp_location
. You need to settle on one version.
default_pickup_location
struct
default_PickUp_location
To discover this, I used the following test route:
router.get("json")
{
request throws -> String in
let json = "{ "country_name" : "Denmark", "timezone" : "Europe/Copenhagen", "default_pickup_location" : "Copenhagen" }"
let encoder = try JSONDecoder().decode(Country.self, from: json)
return "It works"
}
It returned:
{"error":true,"reason":"Value required for key
'default_PickUp_location'."}
Thanks. That was a silly mistake.
– salongley
22 hours ago
Where is the type "Bytes" declared, I don't recognize it as a SwiftLang or Foundation Type. I do recoginize Data(bytes: Array<UInt>)
? I would guess it is an encoding Decoding type inconsitency. Also for simplifying your encoding and decoding to JSON with out mangling Camel Case in swift you may want to try.
Data(bytes: Array<UInt>)
struct Country: Content {
let countryName: String
let timezone: String
let defaultPickupLocation: String
enum CodingKeys: String, CodingKey {
case countryName = "country_name"
case timezone
case defaultPickupLocation = "default_pickup_location"
}
}
I would further recommend that you grab then encoders and decoders from the container for reasons of type consistency. If for example all of your JSON was going to be snake case you could change the encoders and decoders for your container and skip the coding keys enum from above.
var encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
You can get the encoder and decoder from the container as follows
let contentCoders: ContentCoders = try worker.make()
let jsonEncoder = try contentCoders.requireDataEncoder(for: .json) as? JSONEncoder
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Can you edit your question to include a sample of the JSON you store?
– Nick
yesterday