Marvel API Swift4 JSON Decoding











up vote
0
down vote

favorite












I'm making a basic IOS app, based on the "App development with Swift" book from Apple. My app uses the Marvel API. I'm trying to reach the name and the description of the heroes.

The connection with the API works completely and has been tested multiple times. The problem hasn't anything do to with this.



My problem is the fact that the JSON result is 3 times nested, I have no idea how to reach this in Swift 4.



Here is an example of the JSON result of 1 hero. All Heroes can be found in the "result"



The JSON structure can be found here



My code has a fatal error:




Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "results", intValue: nil)




let jsonDecoder = JSONDecoder()
let task = URLSession.shared.dataTask(with: url) { (data,
response, error) in
try! jsonDecoder.decode(CharactersContainer.self,
from: data!) //error here
if let data = data,
let char = try? jsonDecoder.decode(CharactersContainer.self, from: data) {
print(char.characters)
print("succes")

} else {
print("failed")
}
}


Now here are my models:



import Foundation

struct Character: Codable {
var name: String
var description: String
//var url: Image


enum CodingKeys: String, CodingKey {
case name
case description
//case url = "thumbnail"

}
init(from decoder: Decoder) throws {
let valueContainer = try decoder.container(keyedBy: CharactersContainer.CodingKeys.self).nestedContainer(keyedBy: Characters.CodingKeys.self, forKey: .characters).nestedContainer(keyedBy: Character.CodingKeys.self, forKey: .characters)
if let name = try valueContainer.decodeIfPresent(String.self, forKey: CodingKeys.name) {
self.name = name
} else {
self.name = ""
}
if let description = try valueContainer.decodeIfPresent(String.self, forKey: CodingKeys.description) {
self.description = description
} else {
self.description = ""
}

// self.url = try valueContainer.decode(URL.self, forKey: CodingKeys.url)

}
}



struct Characters : Decodable{
var characters : [Character]
enum CodingKeys: String, CodingKey {
case characters = "data"
}
}

struct CharactersContainer : Decodable {
var characters : Characters
//var total: Int
enum CodingKeys: String, CodingKey {
case characters = "results"
//case total
}
}


I have no idea what I did wrong, since I saw some examples who did the exact same thing.



Thanks for checking in!










share|improve this question
























  • Basically don't try! while developing JSON parsing with Codable. Add a do - catch block and print the error instance. It might contain more information than the fatal error. And mapping keys to the same property name (characters) in different structs can be confusing
    – vadian
    Nov 22 at 17:11












  • Valid criticism. I changed the names of the classes to MarvelData and Result
    – ConnorM
    Nov 22 at 17:43















up vote
0
down vote

favorite












I'm making a basic IOS app, based on the "App development with Swift" book from Apple. My app uses the Marvel API. I'm trying to reach the name and the description of the heroes.

The connection with the API works completely and has been tested multiple times. The problem hasn't anything do to with this.



My problem is the fact that the JSON result is 3 times nested, I have no idea how to reach this in Swift 4.



Here is an example of the JSON result of 1 hero. All Heroes can be found in the "result"



The JSON structure can be found here



My code has a fatal error:




Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "results", intValue: nil)




let jsonDecoder = JSONDecoder()
let task = URLSession.shared.dataTask(with: url) { (data,
response, error) in
try! jsonDecoder.decode(CharactersContainer.self,
from: data!) //error here
if let data = data,
let char = try? jsonDecoder.decode(CharactersContainer.self, from: data) {
print(char.characters)
print("succes")

} else {
print("failed")
}
}


Now here are my models:



import Foundation

struct Character: Codable {
var name: String
var description: String
//var url: Image


enum CodingKeys: String, CodingKey {
case name
case description
//case url = "thumbnail"

}
init(from decoder: Decoder) throws {
let valueContainer = try decoder.container(keyedBy: CharactersContainer.CodingKeys.self).nestedContainer(keyedBy: Characters.CodingKeys.self, forKey: .characters).nestedContainer(keyedBy: Character.CodingKeys.self, forKey: .characters)
if let name = try valueContainer.decodeIfPresent(String.self, forKey: CodingKeys.name) {
self.name = name
} else {
self.name = ""
}
if let description = try valueContainer.decodeIfPresent(String.self, forKey: CodingKeys.description) {
self.description = description
} else {
self.description = ""
}

// self.url = try valueContainer.decode(URL.self, forKey: CodingKeys.url)

}
}



struct Characters : Decodable{
var characters : [Character]
enum CodingKeys: String, CodingKey {
case characters = "data"
}
}

struct CharactersContainer : Decodable {
var characters : Characters
//var total: Int
enum CodingKeys: String, CodingKey {
case characters = "results"
//case total
}
}


I have no idea what I did wrong, since I saw some examples who did the exact same thing.



Thanks for checking in!










share|improve this question
























  • Basically don't try! while developing JSON parsing with Codable. Add a do - catch block and print the error instance. It might contain more information than the fatal error. And mapping keys to the same property name (characters) in different structs can be confusing
    – vadian
    Nov 22 at 17:11












  • Valid criticism. I changed the names of the classes to MarvelData and Result
    – ConnorM
    Nov 22 at 17:43













up vote
0
down vote

favorite









up vote
0
down vote

favorite











I'm making a basic IOS app, based on the "App development with Swift" book from Apple. My app uses the Marvel API. I'm trying to reach the name and the description of the heroes.

The connection with the API works completely and has been tested multiple times. The problem hasn't anything do to with this.



My problem is the fact that the JSON result is 3 times nested, I have no idea how to reach this in Swift 4.



Here is an example of the JSON result of 1 hero. All Heroes can be found in the "result"



The JSON structure can be found here



My code has a fatal error:




Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "results", intValue: nil)




let jsonDecoder = JSONDecoder()
let task = URLSession.shared.dataTask(with: url) { (data,
response, error) in
try! jsonDecoder.decode(CharactersContainer.self,
from: data!) //error here
if let data = data,
let char = try? jsonDecoder.decode(CharactersContainer.self, from: data) {
print(char.characters)
print("succes")

} else {
print("failed")
}
}


Now here are my models:



import Foundation

struct Character: Codable {
var name: String
var description: String
//var url: Image


enum CodingKeys: String, CodingKey {
case name
case description
//case url = "thumbnail"

}
init(from decoder: Decoder) throws {
let valueContainer = try decoder.container(keyedBy: CharactersContainer.CodingKeys.self).nestedContainer(keyedBy: Characters.CodingKeys.self, forKey: .characters).nestedContainer(keyedBy: Character.CodingKeys.self, forKey: .characters)
if let name = try valueContainer.decodeIfPresent(String.self, forKey: CodingKeys.name) {
self.name = name
} else {
self.name = ""
}
if let description = try valueContainer.decodeIfPresent(String.self, forKey: CodingKeys.description) {
self.description = description
} else {
self.description = ""
}

// self.url = try valueContainer.decode(URL.self, forKey: CodingKeys.url)

}
}



struct Characters : Decodable{
var characters : [Character]
enum CodingKeys: String, CodingKey {
case characters = "data"
}
}

struct CharactersContainer : Decodable {
var characters : Characters
//var total: Int
enum CodingKeys: String, CodingKey {
case characters = "results"
//case total
}
}


I have no idea what I did wrong, since I saw some examples who did the exact same thing.



Thanks for checking in!










share|improve this question















I'm making a basic IOS app, based on the "App development with Swift" book from Apple. My app uses the Marvel API. I'm trying to reach the name and the description of the heroes.

The connection with the API works completely and has been tested multiple times. The problem hasn't anything do to with this.



My problem is the fact that the JSON result is 3 times nested, I have no idea how to reach this in Swift 4.



Here is an example of the JSON result of 1 hero. All Heroes can be found in the "result"



The JSON structure can be found here



My code has a fatal error:




Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "results", intValue: nil)




let jsonDecoder = JSONDecoder()
let task = URLSession.shared.dataTask(with: url) { (data,
response, error) in
try! jsonDecoder.decode(CharactersContainer.self,
from: data!) //error here
if let data = data,
let char = try? jsonDecoder.decode(CharactersContainer.self, from: data) {
print(char.characters)
print("succes")

} else {
print("failed")
}
}


Now here are my models:



import Foundation

struct Character: Codable {
var name: String
var description: String
//var url: Image


enum CodingKeys: String, CodingKey {
case name
case description
//case url = "thumbnail"

}
init(from decoder: Decoder) throws {
let valueContainer = try decoder.container(keyedBy: CharactersContainer.CodingKeys.self).nestedContainer(keyedBy: Characters.CodingKeys.self, forKey: .characters).nestedContainer(keyedBy: Character.CodingKeys.self, forKey: .characters)
if let name = try valueContainer.decodeIfPresent(String.self, forKey: CodingKeys.name) {
self.name = name
} else {
self.name = ""
}
if let description = try valueContainer.decodeIfPresent(String.self, forKey: CodingKeys.description) {
self.description = description
} else {
self.description = ""
}

// self.url = try valueContainer.decode(URL.self, forKey: CodingKeys.url)

}
}



struct Characters : Decodable{
var characters : [Character]
enum CodingKeys: String, CodingKey {
case characters = "data"
}
}

struct CharactersContainer : Decodable {
var characters : Characters
//var total: Int
enum CodingKeys: String, CodingKey {
case characters = "results"
//case total
}
}


I have no idea what I did wrong, since I saw some examples who did the exact same thing.



Thanks for checking in!







json swift api nested decode






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 22 at 16:57









Craig Siemens

9,11111839




9,11111839










asked Nov 22 at 16:55









ConnorM

1




1












  • Basically don't try! while developing JSON parsing with Codable. Add a do - catch block and print the error instance. It might contain more information than the fatal error. And mapping keys to the same property name (characters) in different structs can be confusing
    – vadian
    Nov 22 at 17:11












  • Valid criticism. I changed the names of the classes to MarvelData and Result
    – ConnorM
    Nov 22 at 17:43


















  • Basically don't try! while developing JSON parsing with Codable. Add a do - catch block and print the error instance. It might contain more information than the fatal error. And mapping keys to the same property name (characters) in different structs can be confusing
    – vadian
    Nov 22 at 17:11












  • Valid criticism. I changed the names of the classes to MarvelData and Result
    – ConnorM
    Nov 22 at 17:43
















Basically don't try! while developing JSON parsing with Codable. Add a do - catch block and print the error instance. It might contain more information than the fatal error. And mapping keys to the same property name (characters) in different structs can be confusing
– vadian
Nov 22 at 17:11






Basically don't try! while developing JSON parsing with Codable. Add a do - catch block and print the error instance. It might contain more information than the fatal error. And mapping keys to the same property name (characters) in different structs can be confusing
– vadian
Nov 22 at 17:11














Valid criticism. I changed the names of the classes to MarvelData and Result
– ConnorM
Nov 22 at 17:43




Valid criticism. I changed the names of the classes to MarvelData and Result
– ConnorM
Nov 22 at 17:43












1 Answer
1






active

oldest

votes

















up vote
0
down vote













In the JSON, data contains the results key. The way your keys are set up, it's expecting results to contain a data key.



CharactersContainer.CodingKeys.characters should probably be "data"



Characters.CodingKeys.characters should probably be "results"





Edit:



There's another issue in Character. It is trying to get a contain keyed by CharactersContainer.CodingKeys.self but it should probably be Character.CodingKeys.self






share|improve this answer























  • You're right, but if u change it. I still get an error saying: Thread 5: Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "data", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), CodingKeys(stringValue: "results", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "Cannot get KeyedDecodingContainer<CodingKeys> -- no value found for key CodingKeys(stringValue: "data", intValue: nil) ("data")", underlyingError: nil))
    – ConnorM
    Nov 22 at 17:09












  • Can you convert data to a string and print it out before you try decoding it? It's possible you're getting a different result from the server that doesn't have a data key
    – Craig Siemens
    Nov 22 at 17:20










  • The picture I added here is actually taken from a print.
    – ConnorM
    Nov 22 at 17:41










  • See my edit above
    – Craig Siemens
    Nov 22 at 17:43











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53435448%2fmarvel-api-swift4-json-decoding%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
0
down vote













In the JSON, data contains the results key. The way your keys are set up, it's expecting results to contain a data key.



CharactersContainer.CodingKeys.characters should probably be "data"



Characters.CodingKeys.characters should probably be "results"





Edit:



There's another issue in Character. It is trying to get a contain keyed by CharactersContainer.CodingKeys.self but it should probably be Character.CodingKeys.self






share|improve this answer























  • You're right, but if u change it. I still get an error saying: Thread 5: Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "data", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), CodingKeys(stringValue: "results", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "Cannot get KeyedDecodingContainer<CodingKeys> -- no value found for key CodingKeys(stringValue: "data", intValue: nil) ("data")", underlyingError: nil))
    – ConnorM
    Nov 22 at 17:09












  • Can you convert data to a string and print it out before you try decoding it? It's possible you're getting a different result from the server that doesn't have a data key
    – Craig Siemens
    Nov 22 at 17:20










  • The picture I added here is actually taken from a print.
    – ConnorM
    Nov 22 at 17:41










  • See my edit above
    – Craig Siemens
    Nov 22 at 17:43















up vote
0
down vote













In the JSON, data contains the results key. The way your keys are set up, it's expecting results to contain a data key.



CharactersContainer.CodingKeys.characters should probably be "data"



Characters.CodingKeys.characters should probably be "results"





Edit:



There's another issue in Character. It is trying to get a contain keyed by CharactersContainer.CodingKeys.self but it should probably be Character.CodingKeys.self






share|improve this answer























  • You're right, but if u change it. I still get an error saying: Thread 5: Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "data", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), CodingKeys(stringValue: "results", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "Cannot get KeyedDecodingContainer<CodingKeys> -- no value found for key CodingKeys(stringValue: "data", intValue: nil) ("data")", underlyingError: nil))
    – ConnorM
    Nov 22 at 17:09












  • Can you convert data to a string and print it out before you try decoding it? It's possible you're getting a different result from the server that doesn't have a data key
    – Craig Siemens
    Nov 22 at 17:20










  • The picture I added here is actually taken from a print.
    – ConnorM
    Nov 22 at 17:41










  • See my edit above
    – Craig Siemens
    Nov 22 at 17:43













up vote
0
down vote










up vote
0
down vote









In the JSON, data contains the results key. The way your keys are set up, it's expecting results to contain a data key.



CharactersContainer.CodingKeys.characters should probably be "data"



Characters.CodingKeys.characters should probably be "results"





Edit:



There's another issue in Character. It is trying to get a contain keyed by CharactersContainer.CodingKeys.self but it should probably be Character.CodingKeys.self






share|improve this answer














In the JSON, data contains the results key. The way your keys are set up, it's expecting results to contain a data key.



CharactersContainer.CodingKeys.characters should probably be "data"



Characters.CodingKeys.characters should probably be "results"





Edit:



There's another issue in Character. It is trying to get a contain keyed by CharactersContainer.CodingKeys.self but it should probably be Character.CodingKeys.self







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 22 at 17:43

























answered Nov 22 at 17:02









Craig Siemens

9,11111839




9,11111839












  • You're right, but if u change it. I still get an error saying: Thread 5: Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "data", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), CodingKeys(stringValue: "results", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "Cannot get KeyedDecodingContainer<CodingKeys> -- no value found for key CodingKeys(stringValue: "data", intValue: nil) ("data")", underlyingError: nil))
    – ConnorM
    Nov 22 at 17:09












  • Can you convert data to a string and print it out before you try decoding it? It's possible you're getting a different result from the server that doesn't have a data key
    – Craig Siemens
    Nov 22 at 17:20










  • The picture I added here is actually taken from a print.
    – ConnorM
    Nov 22 at 17:41










  • See my edit above
    – Craig Siemens
    Nov 22 at 17:43


















  • You're right, but if u change it. I still get an error saying: Thread 5: Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "data", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), CodingKeys(stringValue: "results", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "Cannot get KeyedDecodingContainer<CodingKeys> -- no value found for key CodingKeys(stringValue: "data", intValue: nil) ("data")", underlyingError: nil))
    – ConnorM
    Nov 22 at 17:09












  • Can you convert data to a string and print it out before you try decoding it? It's possible you're getting a different result from the server that doesn't have a data key
    – Craig Siemens
    Nov 22 at 17:20










  • The picture I added here is actually taken from a print.
    – ConnorM
    Nov 22 at 17:41










  • See my edit above
    – Craig Siemens
    Nov 22 at 17:43
















You're right, but if u change it. I still get an error saying: Thread 5: Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "data", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), CodingKeys(stringValue: "results", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "Cannot get KeyedDecodingContainer<CodingKeys> -- no value found for key CodingKeys(stringValue: "data", intValue: nil) ("data")", underlyingError: nil))
– ConnorM
Nov 22 at 17:09






You're right, but if u change it. I still get an error saying: Thread 5: Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "data", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), CodingKeys(stringValue: "results", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "Cannot get KeyedDecodingContainer<CodingKeys> -- no value found for key CodingKeys(stringValue: "data", intValue: nil) ("data")", underlyingError: nil))
– ConnorM
Nov 22 at 17:09














Can you convert data to a string and print it out before you try decoding it? It's possible you're getting a different result from the server that doesn't have a data key
– Craig Siemens
Nov 22 at 17:20




Can you convert data to a string and print it out before you try decoding it? It's possible you're getting a different result from the server that doesn't have a data key
– Craig Siemens
Nov 22 at 17:20












The picture I added here is actually taken from a print.
– ConnorM
Nov 22 at 17:41




The picture I added here is actually taken from a print.
– ConnorM
Nov 22 at 17:41












See my edit above
– Craig Siemens
Nov 22 at 17:43




See my edit above
– Craig Siemens
Nov 22 at 17:43


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53435448%2fmarvel-api-swift4-json-decoding%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

What visual should I use to simply compare current year value vs last year in Power BI desktop

How to ignore python UserWarning in pytest?

Alexandru Averescu