How to retrieve JSON response data using URLSession with RapidAPI

I’m working on a Swift iOS app and trying to get weather information from an API service. I have the basic URLSession code set up and it’s connecting successfully, but I can only see the response headers in my console output.

Here’s my current implementation:

import Foundation

let apiHeaders = [
    "x-rapidapi-host": "weather-service.p.rapidapi.com",
    "x-rapidapi-key": "YOUR_API_KEY_HERE"
]

let urlRequest = NSMutableURLRequest(url: NSURL(string: "https://weather-service.p.rapidapi.com/forecast?location=90210")! as URL,
                                   cachePolicy: .useProtocolCachePolicy,
                                   timeoutInterval: 10.0)
urlRequest.httpMethod = "GET"
urlRequest.allHTTPHeaderFields = apiHeaders

let urlSession = URLSession.shared
let task = urlSession.dataTask(with: urlRequest as URLRequest, completionHandler: { (responseData, response, error) -> Void in
    if (error != nil) {
        print(error)
    } else {
        let httpResponse = response as? HTTPURLResponse
        print(httpResponse)
    }
})

task.resume()

The connection works fine and I can see the HTTP response headers, but I need to access the actual JSON data that comes back from the API. How do I parse and display the response body content? I’m fairly new to iOS development so any help would be appreciated.

You’re completely ignoring the responseData parameter - that’s where your JSON payload lives. I always check the HTTP status code first before parsing JSON since some APIs return errors in weird formats. Add something like guard httpResponse?.statusCode == 200 before you process anything. Also, JSONSerialization.jsonObject returns Any, so you’ll need to cast it - use [String: Any] for objects or [[String: Any]] for arrays depending on what your weather API spits out. I usually throw the JSON parsing into its own function to keep things clean, especially with nested weather data.

The Problem:

You’re fetching weather data from an API using URLSession in your Swift iOS app. The connection is successful, but you’re only seeing the response headers; the JSON body containing the actual weather data isn’t being processed. You want to parse this JSON data and display it in your app.

:thinking: Understanding the “Why” (The Root Cause):

The core issue is that your current code only accesses and prints the HTTP response object (response). The actual JSON data returned by the API is contained within the responseData parameter of the completionHandler. You need to parse this data using JSONSerialization to access the weather information. Simply printing the response object only shows the HTTP headers, not the body of the response. Furthermore, error handling is crucial to prevent crashes if the API returns an error or unexpected data.

:gear: Step-by-Step Guide:

Step 1: Retrieve and Parse the JSON Response:

The most important change is to correctly handle the responseData. This involves checking if responseData exists and then attempting to parse it into a usable data structure. You’ll use JSONSerialization.jsonObject to parse the data. The resulting Any object will need to be cast to a more specific type depending on the structure of your API’s JSON response (likely a dictionary).

Here’s the corrected completionHandler:

let task = urlSession.dataTask(with: urlRequest as URLRequest, completionHandler: { (responseData, response, error) in
    if let error = error {
        print("Error: \(error)")
        return
    }

    guard let data = responseData else {
        print("No data received")
        return
    }

    do {
        if let jsonResponse = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] { // Cast to [String: Any] – adjust as needed
            print(jsonResponse) // Inspect the JSON structure
            // Further processing: Extract relevant weather information from jsonResponse
            // ... your code to extract temperature, conditions, etc., from jsonResponse ...

            DispatchQueue.main.async { // Update UI on main thread
                // Update UI elements with extracted weather data.  For example:
                // self.temperatureLabel.text = "\(jsonResponse["temperature"] as? Double ?? 0)°C"
            }

        } else {
            print("Invalid JSON format")
        }
    } catch {
        print("JSON parsing failed: \(error)")
    }
})

Step 2: Handle HTTP Status Codes:

It’s crucial to check the HTTP status code (httpResponse?.statusCode) to ensure the request was successful before attempting to parse the JSON. A status code other than 200 (OK) indicates an error from the API.

Step 3: Error Handling and Data Type Safety:

Add comprehensive error handling. The do-catch block handles potential JSONSerialization errors. The guard let statements prevent crashes if responseData is nil. Crucially, the cast as? [String: Any] is essential—you will likely need to adjust this based on the structure of your API’s JSON response. Thorough error handling will make your app more robust.

Step 4 (Optional): Structuring Your Data:

For better code organization and maintainability, create a Swift struct to represent the weather data from the API. This will make accessing specific pieces of weather information (like temperature, condition, etc.) cleaner and less error-prone.

:mag: Common Pitfalls & What to Check Next:

  • Incorrect API Key: Double-check that your x-rapidapi-key is correct and hasn’t expired.
  • API Rate Limits: Some APIs have rate limits. If you’re making too many requests, your calls might be temporarily blocked.
  • Network Issues: Ensure you have a stable internet connection. Test with a different network if possible.
  • JSON Structure: Carefully inspect the JSON response using print(jsonResponse) to ensure you understand the structure and are correctly accessing the necessary elements. You might need to adjust the type cast in JSONSerialization.jsonObject (e.g., as? [[String: Any]] for an array of dictionaries).

:speech_balloon: Still running into issues? Share your (sanitized) API response (the jsonResponse output), the exact code you’re using, and any other relevant details. The community is here to help!

you’re missing the responseData handling! add if let data = responseData { let json = try? JSONSerialization.jsonObject(with: data, options: []) print(json) } inside your completion block. that’s where the json actually is, not in the response headers

You’re printing the HTTP response instead of the actual data. You need to handle responseData to get the JSON. Here’s the fix:

let task = urlSession.dataTask(with: urlRequest as URLRequest, completionHandler: { (responseData, response, error) in
    if let error = error {
        print("Error: \(error)")
        return
    }
    
    guard let data = responseData else {
        print("No data received")
        return
    }
    
    do {
        let jsonResponse = try JSONSerialization.jsonObject(with: data, options: [])
        print(jsonResponse)
    } catch {
        print("JSON parsing failed: \(error)")
    }
})

This works well for API calls - the guard statements prevent crashes when responses don’t come back as expected.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.