0

I am currently in the process of learning how to retrieve encoded JSON data from a mySQL database on an apache server and decode the JSON into an instance of my own custom struct;

struct Person: Codable, FetchableRecord, MutablePersistableRecord {
    var id: Int64
    var firstName: String
    var lastName: String
}

here is my method for the network request on xcode

func dataRequestDownload() {
        let baseURL = URL(string: "http://example.com/db_request.php?action=request")
        
        DispatchQueue.main.async {
            if let url = baseURL {
                let task = URLSession.shared.dataTask(with: url) { data, response, error in
                    if let data = data {
                        let decoder = JSONDecoder()
                        let person = try? decoder.decode(Person.self, from: data)
                        print(person)
                    }
                }
                task.resume()
            }
        }
    }
}

My issue is that person prints as nil which makes me think the data isnt being decoded properly.

This is my PHP script for the GET request.

<?php
    
    
$con=mysqli_connect("127.0.0.1","root","example_password","example_database");
 

if (mysqli_connect_errno())
{
  echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
 

$sql = "SELECT * FROM person";
 
if ($result = mysqli_query($con, $sql))
{
    // If so, then create a results array and a temporary one
    // to hold the data
    $resultArray = array();
    $tempArray = array();
 
    // Loop through each row in the result set
    while($row = $result->fetch_object())
    {
        // Add each row into our results array
        $tempArray = $row;
        array_push($resultArray, $tempArray);
    }
 
    // Finally, encode the array to JSON and output the results
    echo json_encode($resultArray);
}
 
// Close connections
mysqli_close($con)
?>

Finally I am not sure this info matters, but in the mySQL database the table is set up just like my struct where id is the PRIMARY key. If more information is needed let me know in the comments, but as far as I know this is all that seems connected to my issue.

Edit: Some other possibly important information is when calling print(data) and print(response) I get

48 bytes
{ Status Code: 200, Headers {
    Connection =     (
        "Keep-Alive"
    );
    "Content-Length" =     (
        48
    );
    "Content-Type" =     (
        "text/html; charset=UTF-8"
    );
    Date =     (
        "Thu, 17 Jun 2021 18:43:02 GMT"
    );
    "Keep-Alive" =     (
        "timeout=5, max=100"
    );
    Server =     (
        "Apache/2.4.46 (Win64) PHP/7.3.21"
    );
    "X-Powered-By" =     (
        "PHP/7.3.21"
    );
} })

the URL is exempt from this of course.

Per the request in the comments; having done this

let object = try? JSONSerialization.jsonObject(with: data)
print(object)

I get

Optional(<__NSSingleObjectArrayI 0x281510080>(
{
    firstName = John;
    id = 0;
    lastName = Doe;
}
)
)

Edit2: Upon running

do {
      let person = try decoder.decode([Person].self, from: data)
      print(person)
  } catch {
      print(error)
   }

the following error appears

typeMismatch(Swift.Int64, Swift.DecodingError.Context(codingPath [_JSONKey(stringValue: "Index 0", intValue: 0),
CodingKeys(stringValue: "id", intValue: nil)], debugDescription:
"Expected to decode Int64 but found a string/data instead.", underlyingError: nil))

Here is the actual JSON upon visiting the URL

[{"id":"0","firstName":"John","lastName":"Doe"}]
Holmes
  • 529
  • 1
  • 6
  • 15
  • 1
    Can you include a sample of the JSON that gets returned from your API request? – jnpdx Jun 17 '21 at 18:46
  • threw in a little more @jnpdx. Hope that helps. Keep in mind it could be something obvious from my lack of knowledge/experience. Hopefully not though haha. – Holmes Jun 17 '21 at 18:54
  • 1
    I'm writing an answer right now. In the meantime, can you post the actual JSON, so that I'm sure (ie what gets returned when you go to the URL -- not what happens when you try to decode with Swift) – jnpdx Jun 17 '21 at 18:55
  • 1
    That error (since the edit) is telling you that `id` is a string in the JSON. Either adjust your `Person` model to using `String` for the type of `id` instead of `Int64`, or adjust your database and or PHP code to use a number instead of a string for the id. – jnpdx Jun 17 '21 at 19:58
  • yea changing it to `String` was it. `id` is already an `Int` according to mySQL, but for some reason its recognized as string on xcode. Ive actually seen model data in examples involving SQL dbs where `id` is string; I guess I know why now haha. If you want you can edit this solution into original answer, so I can checkmark it. Thanks! – Holmes Jun 17 '21 at 20:57
  • 1
    Added it to the answer – jnpdx Jun 17 '21 at 20:59
  • 1
    You may want to read https://stackoverflow.com/questions/1390983/php-json-encode-encoding-numbers-as-strings for some hints about getting your PHP to encode the `id` as an `Int`. You can see that in the JSON, it is clearly a `String`, so it's not an issue on the Swift side of things. – jnpdx Jun 17 '21 at 21:10

1 Answers1

2

When decoding JSON, it's helpful to use do/try/catch so that you can actually see what the error is.

It looks like, in this case, you have an array (which is clear from your PHP code), but you're trying to decode a single object. Try this:

do {
  let person = try decoder.decode([Person].self, from: data)
  print(person)
} catch {
  print(error)
}

Then, since you'll have an array in person (which might be more accurately named people at this point), you'll want to access it with something like person.first


Update, based on added code in your edits:

That error is telling you that id is a String in the JSON. Either adjust your Person model to use String for the type of id instead of Int64, or adjust your database and or PHP code to use a number instead of a String for the id.

jnpdx
  • 45,847
  • 6
  • 64
  • 94
  • This helps a lot, I may have to rewrite the php at some point. as for the code above im about to post edit on the result and the actual JSON. – Holmes Jun 17 '21 at 19:50