Habits Guide Project: nw_socket_handle_socket_event [C1.1.1:2] Socket SO_ERROR [61: Connection refused]

I keep getting the nw_socket_handle_socket_event [C1.1.1:2] Socket SO_ERROR [61: Connection refused] when I am trying to enter the HabitDetailView and UserDetailView. The server gives the information for the Habit/User Collection View (/habits and /users), but it does not give any of the images, UserStats or Habit Stats. I've posted below how the APIRequest and APIService code looks like. It just has me stumped that it gives some of the info, but blocks other parts.

API Request

import UIKit

protocol APIRequest { associatedtype Response

var path: String { get }
var queryItems: [URLQueryItem]? { get }
var request: URLRequest { get }
var postData: Data? { get }

}

extension APIRequest { var host: String { "localhost" } var port: Int { 8080 } }

extension APIRequest { var queryItems: [URLQueryItem]? { nil } var postData: Data? { nil } }

extension APIRequest { var request: URLRequest { var components = URLComponents()

    components.scheme = "http"
    components.host = host
    components.port = port
    components.path = path
    components.queryItems = queryItems
    
    var request = URLRequest(url: components.url!)
    
    if let data = postData {
        request.httpBody = data
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpMethod = "POST"
    }
    return request
}

}

API Service

import UIKit

struct HabitRequest: APIRequest { typealias Response = [String: Habit]

var habitName: String

var path: String { "/habits" }

}

struct UserRequest: APIRequest { typealias Response = [String: User]

var path: String { "/users"}

}

struct HabitStatisticsRequest: APIRequest { typealias Response = [HabitStatistics]

var habitNames: [String]?
var path: String { "/habitStats"}

var queryItems: [URLQueryItem]? {
    if let habitNames = habitNames {
        return [URLQueryItem(name: "names", value: habitNames.joined(separator: ","))]
    } else {
        return nil
    }
}

}

struct UserStatisticsRequest: APIRequest { typealias Response = [UserStatistics]

var userIDs: [String]?

var path: String { "/userStats"}

var queryItems: [URLQueryItem]? {
    if let userIDs = userIDs {
        return [URLQueryItem(name: "ids", value: userIDs.joined(separator: ","))]
    } else {
        return nil
    }
}

}

struct HabitLeadStatisticsRequest: APIRequest { typealias Response = UserStatistics

var userID: String

var path: String { "/userLeadingStats" + userID}

}

struct ImageRequest: APIRequest { typealias Response = UIImage

var imageID: String

var path: String { "/images/" + imageID }

}

enum APIRequestError: Error { case itemsNotFound case requestFailed(HTTPURLResponse) }

extension APIRequest where Response: Decodable { func send() async throws -> Response { let (data, response) = try await URLSession.shared.data(for: request)

    guard let httpResponse = response as? HTTPURLResponse else {
        throw APIRequestError.requestFailed(HTTPURLResponse())
    }
    
    guard httpResponse.statusCode == 200 else {
        throw APIRequestError.itemsNotFound
    }
    
    let decoder = JSONDecoder()
    let decoded = try decoder.decode(Response.self, from: data)
    
    return decoded
}

}

enum ImageRequestError: Error { case couldNotIntializeFromData case imageDataMissing }

extension APIRequest where Response == UIImage { func send() async throws -> UIImage { let (data, response) = try await URLSession.shared.data(for: request)

    guard let httpResponse = response as? HTTPURLResponse,
          httpResponse.statusCode == 200 else {
        throw ImageRequestError.imageDataMissing
    }
    
    guard let image = UIImage(data: data) else {
        throw ImageRequestError.couldNotIntializeFromData
    }
    
    return image
}

}

Replies

That message is coming out of Network framework, which is the underlying network transport used by URLSession. It should be surfaced to you via a URLSession error. In your code snippets, I’d expect try await URLSession.shared.data(for: request) to throw that error. Is that what you’re seeing?

ps It’ll be easier to help if you put your code in a code block. See Quinn’s Top Ten DevForums Tips for advice on how to do that, and lots of other hints and tips.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"