Skip to content

Commit fe3ae25

Browse files
committed
Eliminate force unwraps in url creation
1 parent 60f32ef commit fe3ae25

File tree

8 files changed

+48
-15
lines changed

8 files changed

+48
-15
lines changed

FirebaseAI/Sources/AILog.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ enum AILog {
8787
case generateContentResponseEmptyCandidates = 4003
8888
case invalidWebsocketURL = 4004
8989
case duplicateLiveSessionSetupComplete = 4005
90+
case malformedURL = 4006
9091

9192
// SDK Debugging
9293
case loadRequestStreamResponseLine = 5000
@@ -138,6 +139,16 @@ enum AILog {
138139
log(level: .debug, code: code, message)
139140
}
140141

142+
static func makeInternalError(message: String, code: MessageCode) -> GenerateContentError {
143+
let error = GenerateContentError.internalError(underlying: NSError(
144+
domain: "",
145+
code: -1,
146+
userInfo: [NSLocalizedDescriptionKey: message]
147+
))
148+
AILog.error(code: code, message)
149+
return error
150+
}
151+
141152
/// Returns `true` if additional logging has been enabled via a launch argument.
142153
static func additionalLoggingEnabled() -> Bool {
143154
return ProcessInfo.processInfo.arguments.contains(enableArgumentKey)

FirebaseAI/Sources/GenerateContentRequest.swift

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,23 @@ extension GenerateContentRequest: Encodable {
6464
extension GenerateContentRequest: GenerativeAIRequest {
6565
typealias Response = GenerateContentResponse
6666

67-
var url: URL {
67+
func getURL() throws -> URL {
6868
let modelURL = "\(apiConfig.service.endpoint.rawValue)/\(apiConfig.version.rawValue)/\(model)"
69+
let urlString: String
6970
switch apiMethod {
7071
case .generateContent:
71-
return URL(string: "\(modelURL):\(apiMethod.rawValue)")!
72+
urlString = "\(modelURL):\(apiMethod.rawValue)"
7273
case .streamGenerateContent:
73-
return URL(string: "\(modelURL):\(apiMethod.rawValue)?alt=sse")!
74+
urlString = "\(modelURL):\(apiMethod.rawValue)?alt=sse"
7475
case .countTokens:
75-
fatalError("\(Self.self) should be a property of \(CountTokensRequest.self).")
76+
throw AILog.makeInternalError(
77+
message: "\(Self.self) should be a property of \(CountTokensRequest.self).",
78+
code: .malformedURL
79+
)
7680
}
81+
guard let url = URL(string: urlString) else {
82+
throw AILog.makeInternalError(message: "Malformed URL: \(urlString)", code: .malformedURL)
83+
}
84+
return url
7785
}
7886
}

FirebaseAI/Sources/GenerativeAIRequest.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import Foundation
1818
protocol GenerativeAIRequest: Sendable, Encodable {
1919
associatedtype Response: Sendable, Decodable
2020

21-
var url: URL { get }
21+
func getURL() throws -> URL
2222

2323
var options: RequestOptions { get }
2424
}

FirebaseAI/Sources/GenerativeAIService.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ struct GenerativeAIService {
167167
// MARK: - Private Helpers
168168

169169
private func urlRequest<T: GenerativeAIRequest>(request: T) async throws -> URLRequest {
170-
var urlRequest = URLRequest(url: request.url)
170+
var urlRequest = try URLRequest(url: request.getURL())
171171
urlRequest.httpMethod = "POST"
172172
urlRequest.setValue(firebaseInfo.apiKey, forHTTPHeaderField: "x-goog-api-key")
173173
urlRequest.setValue(

FirebaseAI/Sources/TemplateGenerateContentRequest.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ extension TemplateGenerateContentRequest: Encodable {
4343
extension TemplateGenerateContentRequest: GenerativeAIRequest {
4444
typealias Response = GenerateContentResponse
4545

46-
var url: URL {
46+
func getURL() throws -> URL {
4747
var urlString =
4848
"\(apiConfig.service.endpoint.rawValue)/\(apiConfig.version.rawValue)/projects/\(projectID)"
4949
if case let .vertexAI(_, location) = apiConfig.service {
@@ -53,6 +53,9 @@ extension TemplateGenerateContentRequest: GenerativeAIRequest {
5353
if stream {
5454
urlString += "?alt=sse"
5555
}
56-
return URL(string: urlString)!
56+
guard let url = URL(string: urlString) else {
57+
throw AILog.makeInternalError(message: "Malformed URL: \(urlString)", code: .malformedURL)
58+
}
59+
return url
5760
}
5861
}

FirebaseAI/Sources/TemplateGenerateImagesRequest.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,17 @@ import Foundation
1818
class TemplateGenerateImagesRequest: @unchecked Sendable, GenerativeAIRequest {
1919
typealias Response = ImagenGenerationResponse<ImagenInlineImage>
2020

21-
var url: URL {
21+
func getURL() throws -> URL {
2222
var urlString =
2323
"\(apiConfig.service.endpoint.rawValue)/\(apiConfig.version.rawValue)/projects/\(projectID)"
2424
if case let .vertexAI(_, location) = apiConfig.service {
2525
urlString += "/locations/\(location)"
2626
}
2727
urlString += "/templates/\(template):\(ImageAPIMethod.generateImages.rawValue)"
28-
return URL(string: urlString)!
28+
guard let url = URL(string: urlString) else {
29+
throw AILog.makeInternalError(message: "Malformed URL: \(urlString)", code: .malformedURL)
30+
}
31+
return url
2932
}
3033

3134
let options: RequestOptions

FirebaseAI/Sources/Types/Internal/Imagen/ImagenGenerationRequest.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,13 @@ struct ImagenGenerationRequest<ImageType: ImagenImageRepresentable>: Sendable {
3939
extension ImagenGenerationRequest: GenerativeAIRequest where ImageType: Decodable {
4040
typealias Response = ImagenGenerationResponse<ImageType>
4141

42-
var url: URL {
43-
return URL(string:
44-
"\(apiConfig.service.endpoint.rawValue)/\(apiConfig.version.rawValue)/\(model):predict")!
42+
func getURL() throws -> URL {
43+
let urlString =
44+
"\(apiConfig.service.endpoint.rawValue)/\(apiConfig.version.rawValue)/\(model):predict"
45+
guard let url = URL(string: urlString) else {
46+
throw AILog.makeInternalError(message: "Malformed URL: \(urlString)", code: .malformedURL)
47+
}
48+
return url
4549
}
4650
}
4751

FirebaseAI/Sources/Types/Internal/Requests/CountTokensRequest.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,14 @@ extension CountTokensRequest: GenerativeAIRequest {
2929

3030
var apiConfig: APIConfig { generateContentRequest.apiConfig }
3131

32-
var url: URL {
32+
func getURL() throws -> URL {
3333
let version = apiConfig.version.rawValue
3434
let endpoint = apiConfig.service.endpoint.rawValue
35-
return URL(string: "\(endpoint)/\(version)/\(modelResourceName):countTokens")!
35+
let urlString = "\(endpoint)/\(version)/\(modelResourceName):countTokens"
36+
guard let url = URL(string: urlString) else {
37+
throw AILog.makeInternalError(message: "Malformed URL: \(urlString)", code: .malformedURL)
38+
}
39+
return url
3640
}
3741
}
3842

0 commit comments

Comments
 (0)