Skip to content

Commit

Permalink
refactor: adds statusCode to serverError (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinhermawan authored Nov 2, 2024
1 parent b9cd7cd commit b119c78
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 32 deletions.
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version: 5.8
// swift-tools-version: 5.10
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,9 @@ do {
let models = try await modelRetriever.openAI(apiKey: "your-api-key")
} catch let error as AIModelRetrieverError {
switch error {
case .serverError(let message):
case .serverError(let statusCode, let message):
// Handle server-side errors (e.g., invalid API key, rate limits)
print("Server Error: \(message)")
print("Server Error [\(statusCode)]: \(message)")
case .networkError(let error):
// Handle network-related errors (e.g., no internet connection)
print("Network Error: \(error.localizedDescription)")
Expand Down
9 changes: 7 additions & 2 deletions Sources/AIModelRetriever/AIModelRetriever.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,17 @@ public struct AIModelRetriever: Sendable {
do {
let (data, response) = try await URLSession.shared.data(for: request)

guard let httpResponse = response as? HTTPURLResponse else {
throw AIModelRetrieverError.serverError(statusCode: 0, message: response.description)
}

// Check for API errors first, as they might come with 200 status
if let errorResponse = try? JSONDecoder().decode(E.self, from: data) {
throw AIModelRetrieverError.serverError(errorResponse.errorMessage)
throw AIModelRetrieverError.serverError(statusCode: httpResponse.statusCode, message: errorResponse.errorMessage)
}

guard let httpResponse = response as? HTTPURLResponse, 200...299 ~= httpResponse.statusCode else {
throw AIModelRetrieverError.serverError(response.description)
throw AIModelRetrieverError.serverError(statusCode: httpResponse.statusCode, message: response.description)
}

return try JSONDecoder().decode(T.self, from: data)
Expand Down
34 changes: 12 additions & 22 deletions Sources/AIModelRetriever/AIModelRetrieverError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,25 @@

import Foundation

/// An enum that represents errors that can occur during AI model retrieval.
/// An enum that represents errors that can occur during model retrieval.
public enum AIModelRetrieverError: Error, Sendable {
/// A case that represents a server-side error response.
/// An error that occurs during JSON decoding.
///
/// - Parameter message: The error message from the server.
case serverError(String)
/// - Parameter error: The underlying decoding error.
case decodingError(Error)

/// A case that represents a network-related error.
/// An error that occurs during network operations.
///
/// - Parameter error: The underlying network error.
case networkError(Error)

/// A case that represents a decoding error.
case decodingError(Error)
/// An error returned by the server.
///
/// - Parameters:
/// - statusCode: The HTTP status code returned by the server.
/// - message: The error message received from the server.
case serverError(statusCode: Int, message: String)

/// A case that represents a request has been canceled.
/// An error that occurs when the request is cancelled.
case cancelled

/// A localized message that describes the error.
public var errorDescription: String? {
switch self {
case .serverError(let error):
return error
case .networkError(let error):
return error.localizedDescription
case .decodingError(let error):
return error.localizedDescription
case .cancelled:
return "Request was cancelled"
}
}
}
4 changes: 2 additions & 2 deletions Sources/AIModelRetriever/Documentation.docc/Documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ do {
let models = try await modelRetriever.openAI(apiKey: "your-api-key")
} catch let error as AIModelRetrieverError {
switch error {
case .serverError(let message):
case .serverError(let statusCode, let message):
// Handle server-side errors (e.g., invalid API key, rate limits)
print("Server Error: \(message)")
print("Server Error [\(statusCode)]: \(message)")
case .networkError(let error):
// Handle network-related errors (e.g., no internet connection)
print("Network Error: \(error.localizedDescription)")
Expand Down
8 changes: 5 additions & 3 deletions Tests/AIModelRetrieverTests/AIModelRetrieverTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ final class AIModelRetrieverTests: XCTestCase {
override func setUp() {
super.setUp()

URLProtocol.registerClass(URLProtocolMock.self)
retriever = AIModelRetriever()
URLProtocol.registerClass(URLProtocolMock.self)
}

override func tearDown() {
Expand Down Expand Up @@ -155,7 +155,8 @@ extension AIModelRetrieverTests {
XCTFail("Expected serverError to be thrown")
} catch let error as AIModelRetrieverError {
switch error {
case .serverError(let message):
case .serverError(let statusCode, let message):
XCTAssertEqual(statusCode, 401)
XCTAssertEqual(message, "Invalid API key provided")
default:
XCTFail("Expected serverError but got \(error)")
Expand All @@ -182,7 +183,8 @@ extension AIModelRetrieverTests {
XCTFail("Expected serverError to be thrown")
} catch let error as AIModelRetrieverError {
switch error {
case .serverError(let message):
case .serverError(let statusCode, let message):
XCTAssertEqual(statusCode, 200)
XCTAssertEqual(message, "An error occurred")
default:
XCTFail("Expected serverError but got \(error)")
Expand Down

0 comments on commit b119c78

Please sign in to comment.