How to Assign Elements of a Dictionary to JSON Object in Vapor 3

How to assign elements of a dictionary to JSON object in Vapor 3?

This is basically, JSON serialization in swift. Decoding the JSON object to a Dictionary and then modifying the dictionary and creating a new JSON.

router.get("test") { req -> String in

let jsonDic = ["name":"Alan"]
let data = try JSONSerialization.data(withJSONObject: jsonDic, options: .prettyPrinted)
let jsonString = String(data: data, encoding: .utf8)
return jsonString ?? "FAILED"
}

router.get("test2") { req -> String in
do {
// Loading existing JSON
guard let url = URL(string: "http://localhost:8080/test") else {
return "Invalid URL"
}

let jsonData = try Data(contentsOf: url)
guard var jsonDic = try JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) as? [String:String] else {
return "JSONSerialization Failed"
}

// Apply Changes
jsonDic["name"] = "John"

// Creating new JSON object
let data = try JSONSerialization.data(withJSONObject: jsonDic, options: .prettyPrinted)
let jsonString = String(data: data, encoding: .utf8)
return jsonString ?? "FAILED"
}catch{
return "ERROR"
}
}

I strongly recommend to create struct or class for your data type. It would be much safer in casting using the codable protocol and much easier to convert between JSON and your objects type because of the content protocol in vapor version 3.

How to convert Dictionary to JSON in Vapor 3?

If you have a type like the struct that I have defined here you can simply return it, as long as it conforms to Content.

import Vapor
import FluentSQLite

struct Employee: Codable {
var id: Int?
var name: String

init(name:String) {
self.name = name
}
}

extension Employee: SQLiteModel {}

extension Employee: Migration {}

extension Employee: Parameter {}

extension Employee: Content { }

and then you can simply define a route and return it.

router.get("test") { req in
return Employee(name: "Alan")
}

if you want to use dictionary you can use the JSONSerialization and return a string.

router.get("test2") { req -> String in

let employeeDic: [String : Any] = ["name":"Alan", "age":27]

do {
let data = try JSONSerialization.data(withJSONObject: employeeDic, options: .prettyPrinted)
let jsonString = String(data: data, encoding: .utf8)
return jsonString ?? "FAILED"

}catch{
return "ERROR"
}
}

How to access the raw content from a response in Vapor 3 unit test?

You could write your own additional methods in Application+Testable like

func getRawResponse(to path: String) throws -> Response {
return try self.sendRequest(to: path, method: .GET)
}
func getStringResponse(to path: String) throws -> String {
let response = try self.getRawResponse(to: path)
guard let data = response.http.body.data,
let string = String(data: data, encoding: .utf8) else {
throw SomeError("Unable to decode response data into String")
}
return string
}

and then call them to get either raw Response or decoded String like

func testGettingHelloWorldStringFromTheAPI() throws {
let string = try app. getStringResponse(to: "some/endpoint")

XCTAssertEqual(string, "Hello world")
}

How to always return an array in Vapor 3 and Fluent (even for single entity requests)

final class AddressController {
func index(_ req: Request) throws -> Future<[Address]> {
if let id = try? req.query.get(UUID.self, at: "id") {
return Address.find(id, on: req).map {
guard let address = $0 else { return [] }
return [address]
}
} else {
return Address.query(on: req).all()
}
}
}


Related Topics



Leave a reply



Submit