I am able to decode straight forward json responses but as the JSON gets more nested, I'm struggling.
To decode JSON that looks like this:
[
{
"id": "string",
"username": "string",
"firstName": "string",
"lastName": "string",
"fullName": "string",
"email": "string",
"isInActivity": true,
"activeEventId": "string",
"initials": "string"
}
]
My struct is:
struct FriendsStruct: Decodable, Hashable {
var initials: String
var username: String
var firstName: String
var lastName: String
var fullName: String
var email: String
var isInActivity: Bool
var activeEventId: String
var id: String
}
And to decode:
func getFriends(token: String, force: Bool) async throws -> Int {
var request = EndPoints().getFriendsEndPoint(force: force)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: request)
let httpResponse = response as? HTTPURLResponse
guard (response as? HTTPURLResponse)?.statusCode == 200 else {return httpResponse?.statusCode ?? 0}
let decodedFriends = try JSONDecoder().decode([FriendsStruct].self, from: data)
self.updateCoreDataFriendsRecords(friendsData: decodedFriends)
return httpResponse?.statusCode ?? 1000
}
Can someone advise as to how I might decode with the same approach but with a nested response such as:
{
"members": [
{
"memberId": "string",
"memberName": "string",
"memberUsername": "string",
"memberType": 0,
"isMyFriend": true,
"initials": "string"
}
],
"name": "string",
"owner": "string",
"description": "string",
"groupType": 0,
"expiryDate": "2023-02-06T20:00:03.834Z",
"readOnly": true,
"isDeleted": true,
"approvalRequired": true,
"joinWithCode": true,
"numberOfMembers": 0,
"groupAssociation": 0,
"id": "string",
"etag": "string"
}
You need two structs: a Member struct with properties in the JSON (as you did for the simple example) and an outer level struct for the base data that includes a property which is an array of Member. For example:
struct Member: Decodable {
let memberId: String
let memberName: String
let memberUsername: String
let memberType: Int
let isMyFriend: Bool
let initials: String
}
struct Group: Decodable {
let members: [Member]
let name: String
let owner: String
let description: String
let groupType: Int
let expiryDate: String
let readOnly: Bool
let isDeleted: Bool
let approvalRequired: Bool
let joinWithCode: Bool
let numberOfMembers: Int
let groupAssociation: Int
let id: String
let etag: String
}
This is treating the data exactly as it is in the JSON. You'd probably want to go further and use a CodingKeys enum to map some of the json fields onto more suitable property names, and maybe, depending on needs, use a Date for the expiry date and decode the date string.
EDIT
As a follow up I mentioned the next step might be decoding the expiryDate field into a Date property. The answer passed over this as it appeared to be an .iso8601 date format, in which case all that is required is to set the date decoding strategy on the decoder accordingly:
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(DateFormatter.iso8601)
let group = decoder.decode(Group.self, from: json.data(using: .utf8)!) // force unwrapping for brevity. Don't ;-)
However this won't work as the date field contains fractional seconds and Swift's decoder only supports whole seconds. This makes it a bit more interesting :-) as you'll need to define a custom decoder:
extension DateFormatter {
static let iso8601WithFractionalSeconds: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
formatter.calendar = Calendar(identifier: .iso8601)
formatter.timeZone = TimeZone(secondsFromGMT: 0)
return formatter
}()
}
This then lets you decoder the expiryDate string to a Date within the decoder. Change the expiry date field to a Date and decode as below.
struct Group: Decodable {
//...
let expiryDate: Date
//...
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(DateFormatter.iso8601WithFractionalSeconds)
let group = try! decoder.decode(Group.self, from: data)
Related
I'm trying to read this JSON data with Combine but I cannot make it work if I try to read the release field.
The address https://amiiboapi.com/api/ returns something like this:
{
"amiibo": [
{
"amiiboSeries": "Super Smash Bros.",
"character": "Mario",
"gameSeries": "Super Mario",
"head": "00000000",
"image": "https://raw.githubusercontent.com/N3evin/AmiiboAPI/master/images/icon_00000000-00000002.png",
"name": "Mario",
"release": {
"au": "2014-11-29",
"eu": "2014-11-28",
"jp": "2014-12-06",
"na": "2014-11-21"
},
"tail": "00000002",
"type": "Figure"
},
{
"amiiboSeries": "Super Mario Bros.",
"character": "Mario",
"gameSeries": "Super Mario",
"head": "00000000",
"image": "https://raw.githubusercontent.com/N3evin/AmiiboAPI/master/images/icon_00000000-00340102.png",
"name": "Mario",
"release": {
"au": "2015-03-21",
"eu": "2015-03-20",
"jp": "2015-03-12",
"na": "2015-03-20"
},
"tail": "00340102",
"type": "Figure"
}
]
}
I have my model like this:
// MARK: - Amiibo List
struct AmiibosList: Codable {
let amiibo: [Amiibo]
}
// MARK: - Amiibo
struct Amiibo: Codable {
let amiiboSeries: String
let character: String
let gameSeries: String
let head: String
let image: String
let name: String
let release: Release
let tail: String
let type: String
}
// MARK: - Release
struct Release: Codable {
let au : String?
let eu : String?
let jp : String?
let na : String?
}
And I'm trying to fetch the data like this:
guard let url = URL(string: "https://amiiboapi.com/api/") else {
fatalError("Invalid URL")
}
var publisher = URLSession.shared.dataTaskPublisher(for: url)
.receive(on: RunLoop.main)
.map(\.data)
.decode(type: AmiiboList.self, decoder: JSONDecoder())
.sink(receiveCompletion: { completion in
if case .failure(let err) = completion {
print("Failed with error \(err)")
}
}, receiveValue: { value in
print("Received \(value)")
// print(" Received \(value.amiibo[0].release)")
})
If I comment/remove the release from my amiibo struct, everything works. For some reason I cannot retrieve the data with the release dates and I can't figure why.
Do I need to do anything else for nested JSON data?
With the below, you can simply do: response.amiibo[0].release to get the release object. Note that the release object contains Date objects rather than Strings. That should be helpful.
func example(data: Data) throws -> Response {
let data = jsonString.data(using: .utf8)!
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(dateFormatter)
return try decoder.decode(Response.self, from: data)
}
struct Response: Codable {
let amiibo: [Amiibo]
}
struct Amiibo: Codable {
let amiiboSeries: String
let character: String
let gameSeries: String
let head: String
let image: URL?
let name: String
let release: Release
let tail: String
let type: String
}
struct Release: Codable {
let au: Date?
let eu: Date?
let jp: Date?
let na: Date?
}
I'm trying to parse this JSON response
{
"payload": {
"bgl_category": [{
"number": "X",
"name": "",
"parent_number": null,
"id": 48488,
"description": "Baustellenunterk\u00fcnfte, Container",
"children_count": 6
}, {
"number": "Y",
"name": "",
"parent_number": null,
"id": 49586,
"description": "Ger\u00e4te f\u00fcr Vermessung, Labor, B\u00fcro, Kommunikation, \u00dcberwachung, K\u00fcche",
"children_count": 7
}]
},
"meta": {
"total": 21
}
}
What I'm interested to view in my TableViewCell are only the number and description
here is what I tried to far:
//MARK: - BGLCats
struct BGLCats: Decodable {
let meta : Meta!
let payload : Payload!
}
//MARK: - Payload
struct Payload: Decodable {
let bglCategory : [BglCategory]!
}
//MARK: - BglCategory
struct BglCategory: Decodable {
let descriptionField : String
let id : Int
let name : String
let number : String
let parentNumber : Int
}
//MARK: - Meta
struct Meta: Decodable {
let total : Int
}
API request:
fileprivate func getBgls() {
guard let authToken = getAuthToken() else {
return
}
let headers = [
"content-type" : "application/json",
"cache-control": "no-cache",
"Accept" : "application/json",
"Authorization": "\(authToken)"
]
let request = NSMutableURLRequest(url: NSURL(string: "https://api-dev.com")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)
request.allHTTPHeaderFields = headers
let endpoint = "https://api-dev.com"
guard let url = URL(string: endpoint) else { return }
URLSession.shared.dataTask(with: request as URLRequest) {(data, response, error) in
guard let data = data else { return }
do {
let BGLList = try JSONDecoder().decode(BglCategory.self, from: data)
print(BGLList)
DispatchQueue.main.sync { [ weak self] in
self?.number = BGLList.number
self?.desc = BGLList.descriptionField
// self?.id = BGLList.id
print("Number: \(self?.number ?? "Unknown" )")
print("desc: \(self?.desc ?? "Unknown" )")
// print("id: \(self?.id ?? 0 )")
}
} catch let jsonError {
print("Error Serializing JSON:", jsonError)
}
}.resume()
}
But I'm getting error:
Error Serializing JSON: keyNotFound(CodingKeys(stringValue: "childrenCount", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"childrenCount\", intValue: nil) (\"childrenCount\").", underlyingError: nil))
There are a few issues here.
You created the model (mostly) correctly, but there're just two mismatches:
struct BglCategory: Decodable {
let description : String // renamed, to match "description" in JSON
let parentNum: Int? // optional, because some values are null
// ...
}
Second issue is that your model properties are camelCased whereas JSON is snake_cased. JSONDecoder has a .convertFromSnakeCase startegy to automatically handle that. You need to set it on the decoder prior to decoding.
Third issue is that you need to decode the root object BGLCats, instead of BglCategory.
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase // set the decoding strategy
let bglCats = try decoder.decode(BGLCats.self, from: data) // decode BGLCats
let blgCategories = bglCats.payload.bglCategory
The problem is that JSONDecoder doesn't know that for example bglCategory is represented in JSON payload as bgl_category. If the JSON name isn't the same as the variable name you need to implement CodingKeys to your Decodable
In your case:
struct BglCategory: Decodable {
let descriptionField : String
let id : Int
let name : String
let number : String
let parentNumber : Int?
enum CodingKeys: String, CodingKey {
case id, name, number
case descriptionField = "description"
case parentNumber = "parent_number"
}
}
struct Payload: Decodable {
let bglCategory : [BglCategory]!
enum CodingKeys: String, CodingKey {
case bglCategory = "bgl_category"
}
}
The JSON I have to post:
{
"quizId": 1,
"quizQuestionBanks": [
{
"quizQuestionBankId": 4,
"question": "string",
"option1": "string",
"option2": "string",
"option3": "string",
"option4": "string",
"answer": "Guy de Maupassant",
"explanation": "string"
}
]
}
I did the URLSession Post part. But don't know how to post this kind of JSON. Earlier I have posted JSON like this.
let json: [String: Any] = ["key": "value"]
But it's a bit complex for me.
The code I did for posting is given below
let url = URL(string: postUrl)! //PUT Your URL
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("\(String(describing: jsonData?.count))", forHTTPHeaderField: "Content-Length")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("Token \(String(describing: token))", forHTTPHeaderField: "Authorization")
// insert json data to the request
request.httpBody = jsonData
URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON) //Code after Successfull POST Request
}
}.resume()
Prepare JSON data for upload
struct Quiz: Codable {
let quizId: Int
let quizQuestionBanks: [QuizQuestionBank]
}
struct QuizQuestionBank: Codable {
let quizQuestionBankId: Int
let question: String
let option1: String
let option2: String
let option3: String
let option4: String
let answer: String
let explanation: String
}
let quiz = Quiz(quizId: 1, quizQuestionBanks: [QuizQuestionBank(quizQuestionBankId: 4, question: "string", option1: "string", option2: "string", option3: "string", option4: "string", answer: "Guy de Maupassant", explanation: "string")])
guard let uploadData = try? JSONEncoder().encode(quiz) else {
return
}
Configure URL request
let url = URL(string: "https://example.com/post")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
Use upload task
let task = URLSession.shared.uploadTask(with: request, from: uploadData) { data, response, error in
if let error = error {
print ("error: \(error)")
return
}
guard let response = response as? HTTPURLResponse,
(200...299).contains(response.statusCode) else {
print ("server error")
return
}
if let mimeType = response.mimeType,
mimeType == "application/json",
let data = data,
let dataString = String(data: data, encoding: .utf8) {
print ("got data: \(dataString)")
}
}
task.resume()
See this link from Apple developer site for more detailed information.
https://developer.apple.com/documentation/foundation/url_loading_system/uploading_data_to_a_website
With JSONSerialization:
let params: [String: Any] = ["quizId": 1,
"quizQuestionBanks": [["quizQuestionBankId": 4,
"question": "string",
"option1": "string",
"option2": "string",
"option3": "string",
"option4": "string",
"answer": "Guy de Maupassant",
"explanation": "string"]]]
let jsonData = try? JSONSerialization.data(withJSONObject: params)
But, since Swift 4, we can use Codable:
struct Quiz: Codable {
let id: Int
let questions: [Question]
enum CodingKeys: String, CodingKey {
case id = "quizId"
case questions = "quizQuestionBanks"
}
}
struct Question: Codable {
let id: Int
let question: String
let option1: String
let option2: String
let option3: String
let option4: String
let answer: String
let explanation: String
enum CodingKeys: String, CodingKey {
case id = "quizQuestionBankId"
case question
case option1
case option2
case option3
case option4
case answer
case explanation
}
}
let questions = [Question(id: 4, question: "string", option1: "string", option2: "string", option3: "string", option4: "string", answer: "Guy de Maupassant", explanation: "string")]
let quiz = Quiz(id: 1, questions: questions)
let jsonData = try JSONEncoder().encode(quiz)
option1, option2, option3, option4, could be an array in struct (that would need a custom encoding/decoding).
Hi my url of request is:
http://MYDOMAIN/jsonrpc?request=
{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "filter": {"field": "playcount", "operator": "is", "value": "0"}, "limits": { "start" : 0, "end": 75 }, "properties" : ["art", "rating", "thumbnail", "playcount", "file"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libMovies"}
How can I parse result in swift?
Use Codable to parse JSON. Try with your demo input.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var myView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let someString = """
{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "filter": {"field": "playcount", "operator": "is", "value": "0"}, "limits": { "start" : 0, "end": 75 }, "properties" : ["art", "rating", "thumbnail", "playcount", "file"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libMovies"}
"""
let data = someString.data(using: .utf8)!
do{
let jsonDataModels = try JSONDecoder().decode(JSONDataModel.self, from: data)
print(String(data: data, encoding: .utf8)!)
print("jsonDataModels: \(jsonDataModels)")
}catch {
print(error)
}
}
}
// This file was generated from JSON Schema using quicktype, do not modify it directly.
// To parse the JSON, add this file to your project and do:
//
// let jSONDataModel = try? newJSONDecoder().decode(JSONDataModel.self, from: jsonData)
import Foundation
// MARK: - JSONDataModel
struct JSONDataModel: Codable {
let jsonrpc, method: String
let params: Params
let id: String
}
// MARK: - Params
struct Params: Codable {
let filter: Filter
let limits: Limits
let properties: [String]
let sort: Sort
}
// MARK: - Filter
struct Filter: Codable {
let field, filterOperator, value: String
enum CodingKeys: String, CodingKey {
case field
case filterOperator = "operator"
case value
}
}
// MARK: - Limits
struct Limits: Codable {
let start, end: Int
}
// MARK: - Sort
struct Sort: Codable {
let order, method: String
let ignorearticle: Bool
}
Another example tries with API call.
import UIKit
import Foundation
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://jsonplaceholder.typicode.com/users")!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else { return }
do{
let jsonDataModels = try JSONDecoder().decode([JSONDataModel].self, from: data)
print(String(data: data, encoding: .utf8)!)
print("jsonDataModels: \(jsonDataModels)")
}catch{}
}
task.resume()
}
}
struct JSONDataModel: Codable {
let id: Int
let name, username, email: String
let address: Address
let phone, website: String
let company: Company
}
struct Address: Codable {
let street, suite, city, zipcode: String
let geo: Geo
}
struct Geo: Codable {
let lat, lng: String
}
struct Company: Codable {
let name, catchPhrase, bs: String
}
When I hit my configuration API with Postman I am given the following json response back. In this response the two apiVersion keys are numbers and not strings.
{
"data": {
"availability": {
"auth": true,
"ab": true,
"cd": true
},
"helloWorldConfiguration": {
"apiKey": "abcefg",
"rootUrl": "https://foo",
"apiVersion": 3
},
"fooBarConfiguration": {
"baseUrl": "https://foo",
"apiVersion": 1,
"privateApiPath": "",
"publicApiPath": "dev",
"tokenPath": ""
}
},
"errors": []
}
When I try to decode it it fails with a typeMismatch error. When I output the contents of the response, I see the following which looks fine to me.
data = {
availability = {
auth = 1;
ab = 1;
cd = 1;
};
helloWorldConfiguration = {
apiVersion = 1;
baseUrl = "https://foo";
privateApiPath = "";
publicApiPath = dev;
tokenPath = "";
};
fooBarConfiguration = {
apiKey = abcefg;
apiVersion = 3;
rootUrl = "https://foo";
};
};
errors = (
);
The error given to me indicates that data.helloWorldConfiguration.apiVersion is of type string instead of int. We can see from the original HTTP response I get from Postman that's not the case.
typeMismatch(Swift.Int, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), CodingKeys(stringValue: "helloWorldConfiguration", intValue: nil), CodingKeys(stringValue: "apiVersion", intValue: nil)], debugDescription: "Expected to decode Int but found a string/data instead.", underlyingError: nil))
21:17:40 ERROR Unable to decode the response data into a model representation.
My model represents those properties as integers so it would appear that it receives the response and considers those numbers to be strings, which they're not.
public struct ServerConfiguration: Decodable {
let availability: AvailabilityConfiguration
let helloWorldConfiguration: HelloWorldConfiguration
let fooBarConfiguration: FooBarConfiguration
init(availability: AvailabilityConfiguration, helloWorldConfiguration: HelloWorldConfiguration, fooBarConfiguration: FloatSinkConfiguration) {
self.availability = availability
self.helloWorldConfiguration = helloWorldConfiguration
self.fooBarConfiguration = fooBarConfiguration
}
}
public struct FooBarConfiguration: Decodable {
let baseUrl: String
let apiVersion: Int
let privateApiPath: String
let publicApiPath: String
let tokenPath: String
init(baseUrl: String, apiVersion: Int, privateApiPath: String, publicApiPath: String, tokenPath: String) {
self.baseUrl = baseUrl
self.apiVersion = apiVersion
self.privateApiPath = privateApiPath
self.publicApiPath = publicApiPath
self.tokenPath = tokenPath
}
}
public struct AvailabilityConfiguration: Decodable {
let auth: Bool
let ab: Bool
let cd: Bool
init(auth: Bool, ab: Bool, cd: Bool) {
self.auth = auth
self.ab = ab
self.cd = cd
}
}
public struct HelloWorldConfiguration: Codable {
let apiKey: String
let rootUrl: String
let apiVersion: Int
init(apiKey: String, rootUrl: String, apiVersion: Int) {
self.apiKey = apiKey
self.rootUrl = rootUrl
self.apiVersion = apiVersion
}
}
As you can see my apiVersion members are both of type integer along with the json response. What am I doing wrong here? I assume what's happening is Swift is considering the numbers in the json string, regardless of how they're actually represented in the json. Is that the case?
Edit to show utf8 string of Alamofire response data
21:44:06 INFO GET: https:foo/configuration
{
"data" : {
"availability" : {
"auth" : true,
"ab" : true,
"cb" : true
},
"helloWorldConfiguration" : {
"apiKey" : "abcd",
"rootUrl" : "https://foo",
"apiVersion" : "3"
},
"fooBarConfiguration" : {
"baseUrl" : "https://foo",
"apiVersion" : "1",
"privateApiPath" : "",
"publicApiPath" : "dev",
"tokenPath" : "auth/token"
}
},
"errors" : []
}
It would seem that despite the API correctly returning apiVersion as a number, Swift is turning it into a string. Am I decoding it incorrectly?
func getRoute<TResponseData: Decodable>(route:String, completion: #escaping (TResponseData) -> Void) throws {
let headers = try! self.getHeaders(contentType: ContentType.json)
let completeUrl: String = self.getUrl(route: route, requestUrl: nil)
logger.info("GET: \(completeUrl)")
Alamofire.request(
completeUrl,
method: .get,
parameters: nil,
encoding: JSONEncoding.default,
headers: headers)
.validate()
.responseJSON { (response) -> Void in
self.logger.info("GET Response: \(String(describing:response.response?.statusCode))")
switch response.result {
case .success(_):
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .custom(Date.toFooBarDate)
do {
let result = try decoder.decode(TResponseData.self, from: response.data!)
completion(result)
} catch DecodingError.dataCorrupted(let error) {
self.logger.error(error.underlyingError!)
return
} catch {
print(response.result.value!)
print(error)
self.logger.error("Unable to decode the response data into a model representation.")
return
}
}
}
I checked in my playground and it seems that everything is working fine.To find the real issue i think you are required to provide the real url from where you are getting json and can be checked with alamofire
import Foundation
let json = """
{
"data": {
"availability": {
"auth": true,
"ab": true,
"cd": true
},
"helloWorldConfiguration": {
"apiKey": "abcefg",
"rootUrl": "https://foo",
"apiVersion": 3
},
"fooBarConfiguration": {
"baseUrl": "https://foo",
"apiVersion": 1,
"privateApiPath": "",
"publicApiPath": "dev",
"tokenPath": ""
}
},
"errors": []
}
"""
let data = json.data(using: .utf8)
struct Response : Codable {
let data : Data?
let errors : [String]?
}
struct Availability : Codable {
let auth : Bool?
let ab : Bool?
let cd : Bool?
}
struct Data : Codable {
let availability : Availability?
let helloWorldConfiguration : HelloWorldConfiguration?
let fooBarConfiguration : FooBarConfiguration?
}
struct FooBarConfiguration : Codable {
let baseUrl : String?
let apiVersion : Int?
let privateApiPath : String?
let publicApiPath : String?
let tokenPath : String?
}
struct HelloWorldConfiguration : Codable {
let apiKey : String?
let rootUrl : String?
let apiVersion : Int?
}
let decoder = JSONDecoder()
let response = try decoder.decode(Response.self, from: data!)
print(response)
And here is the response
Response(data: Optional(__lldb_expr_11.Data(availability: Optional(__lldb_expr_11.Availability(auth: Optional(true), ab: Optional(true), cd: Optional(true))), helloWorldConfiguration: Optional(__lldb_expr_11.HelloWorldConfiguration(apiKey: Optional("abcefg"), rootUrl: Optional("https://foo"), apiVersion: Optional(3))), fooBarConfiguration: Optional(__lldb_expr_11.FooBarConfiguration(baseUrl: Optional("https://foo"), apiVersion: Optional(1), privateApiPath: Optional(""), publicApiPath: Optional("dev"), tokenPath: Optional(""))))), errors: Optional([]))