Vapor3 JSON encode & Decode

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP


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?





Can you edit your question to include a sample of the JSON you store?
– Nick
yesterday





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.

Popular posts from this blog

Makefile test if variable is not empty

Will Oldham

Visual Studio Code: How to configure includePath for better IntelliSense results