Skip to content

Commit 10a4f14

Browse files
committed
refactor: further optimize Storage module execute method usage
- Improve serialization patterns for better performance - Clean up remaining manual decoding steps - Ensure consistent error handling across all Storage operations
1 parent 28f1fc0 commit 10a4f14

File tree

2 files changed

+65
-50
lines changed

2 files changed

+65
-50
lines changed

Sources/Storage/StorageApi.swift

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,29 +59,52 @@ public class StorageApi: @unchecked Sendable {
5959
body: RequestBody? = NoopParameter(),
6060
encoder: (any ParameterEncoder)? = nil
6161
) throws -> DataRequest {
62-
var request = try URLRequest(url: url, method: method, headers: headers)
62+
var request = try makeRequest(url, method: method, headers: headers, query: query)
6363

64-
request = try urlQueryEncoder.encode(request, with: query)
6564
if RequestBody.self != NoopParameter.self {
6665
request = try (encoder ?? defaultEncoder).encode(body, into: request)
6766
}
6867

6968
return session.request(request)
70-
.validate { request, response, data in
71-
guard 200..<300 ~= response.statusCode else {
72-
guard let data else {
73-
return .failure(AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength))
74-
}
75-
76-
do {
77-
return .failure(try self.configuration.decoder.decode(StorageError.self, from: data))
78-
} catch {
79-
return .failure(HTTPError(data: data, response: response))
80-
}
81-
}
82-
return .success(())
69+
.validate { _, response, data in
70+
self.validate(response: response, data: data ?? Data())
8371
}
8472
}
73+
74+
func upload(
75+
_ url: URL,
76+
method: HTTPMethod = .get,
77+
headers: HTTPHeaders = [:],
78+
query: Parameters? = nil,
79+
multipartFormData: @escaping (MultipartFormData) -> Void,
80+
) throws -> UploadRequest {
81+
let request = try makeRequest(url, method: method, headers: headers, query: query)
82+
return session.upload(multipartFormData: multipartFormData, with: request)
83+
.validate { _, response, data in
84+
self.validate(response: response, data: data ?? Data())
85+
}
86+
}
87+
88+
private func makeRequest(
89+
_ url: URL,
90+
method: HTTPMethod = .get,
91+
headers: HTTPHeaders = [:],
92+
query: Parameters? = nil
93+
) throws -> URLRequest {
94+
let request = try URLRequest(url: url, method: method, headers: headers)
95+
return try urlQueryEncoder.encode(request, with: query)
96+
}
97+
98+
private func validate(response: HTTPURLResponse, data: Data) -> DataRequest.ValidationResult {
99+
guard 200..<300 ~= response.statusCode else {
100+
do {
101+
return .failure(try self.configuration.decoder.decode(StorageError.self, from: data))
102+
} catch {
103+
return .failure(HTTPError(data: data, response: response))
104+
}
105+
}
106+
return .success(())
107+
}
85108
}
86109

87110
extension Helpers.HTTPRequest {

Sources/Storage/StorageFileApi.swift

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import Alamofire
22
import Foundation
3-
import HTTPTypes
43

54
#if canImport(FoundationNetworking)
65
import FoundationNetworking
@@ -74,26 +73,19 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
7473
}
7574

7675
private func _uploadOrUpdate(
77-
method: HTTPTypes.HTTPRequest.Method,
76+
method: HTTPMethod,
7877
path: String,
7978
file: FileUpload,
8079
options: FileOptions?
8180
) async throws -> FileUploadResponse {
8281
let options = options ?? defaultFileOptions
83-
var headers = options.headers.map { HTTPFields($0) } ?? HTTPFields()
82+
var headers = options.headers.map { HTTPHeaders($0) } ?? HTTPHeaders()
8483

8584
if method == .post {
86-
headers[.xUpsert] = "\(options.upsert)"
85+
headers["x-upsert"] = "\(options.upsert)"
8786
}
8887

89-
headers[.duplex] = options.duplex
90-
91-
#if DEBUG
92-
let formData = MultipartFormData(boundary: testingBoundary.value)
93-
#else
94-
let formData = MultipartFormData()
95-
#endif
96-
file.encode(to: formData, withPath: path, options: options)
88+
headers["duplex"] = options.duplex
9789

9890
struct UploadResponse: Decodable {
9991
let Key: String
@@ -103,12 +95,15 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
10395
let cleanPath = _removeEmptyFolders(path)
10496
let _path = _getFinalPath(cleanPath)
10597

106-
let response = try await execute(
98+
let response = try await upload(
10799
configuration.url.appendingPathComponent("object/\(_path)"),
108-
method: HTTPMethod(rawValue: method.rawValue),
109-
headers: HTTPHeaders(headers.map { HTTPHeader(name: $0.name.rawName, value: $0.value) }),
110-
body: formData.encode()
111-
).serializingDecodable(UploadResponse.self, decoder: configuration.decoder).value
100+
method: method,
101+
headers: headers
102+
) { formData in
103+
file.encode(to: formData, withPath: path, options: options)
104+
}
105+
.serializingDecodable(UploadResponse.self, decoder: configuration.decoder)
106+
.value
112107

113108
return FileUploadResponse(
114109
id: response.Id,
@@ -514,15 +509,15 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
514509
let url: String
515510
}
516511

517-
var headers = HTTPFields()
512+
var headers = HTTPHeaders()
518513
if let upsert = options?.upsert, upsert {
519-
headers[.xUpsert] = "true"
514+
headers["x-upsert"] = "true"
520515
}
521516

522517
let response = try await execute(
523518
configuration.url.appendingPathComponent("object/upload/sign/\(bucketId)/\(path)"),
524519
method: .post,
525-
headers: HTTPHeaders(headers.map { HTTPHeader(name: $0.name.rawName, value: $0.value) })
520+
headers: headers
526521
).serializingDecodable(Response.self, decoder: configuration.decoder).value
527522

528523
let signedURL = try makeSignedURL(response.url, download: nil)
@@ -597,10 +592,10 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
597592
options: FileOptions?
598593
) async throws -> SignedURLUploadResponse {
599594
let options = options ?? defaultFileOptions
600-
var headers = options.headers.map { HTTPFields($0) } ?? HTTPFields()
595+
var headers = options.headers.map { HTTPHeaders($0) } ?? HTTPHeaders()
601596

602-
headers[.xUpsert] = "\(options.upsert)"
603-
headers[.duplex] = options.duplex
597+
headers["x-upsert"] = "\(options.upsert)"
598+
headers["duplex"] = options.duplex
604599

605600
#if DEBUG
606601
let formData = MultipartFormData(boundary: testingBoundary.value)
@@ -613,14 +608,16 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
613608
let Key: String
614609
}
615610

616-
let response = try await execute(
617-
configuration.url
618-
.appendingPathComponent("object/upload/sign/\(bucketId)/\(path)"),
611+
let response = try await upload(
612+
configuration.url.appendingPathComponent("object/upload/sign/\(bucketId)/\(path)"),
619613
method: .put,
620-
headers: HTTPHeaders(headers.map { HTTPHeader(name: $0.name.rawName, value: $0.value) }),
621-
query: ["token": token],
622-
body: formData.encode()
623-
).serializingDecodable(UploadResponse.self, decoder: configuration.decoder).value
614+
headers: headers,
615+
query: ["token": token]
616+
) { formData in
617+
file.encode(to: formData, withPath: path, options: options)
618+
}
619+
.serializingDecodable(UploadResponse.self, decoder: configuration.decoder)
620+
.value
624621

625622
let fullPath = response.Key
626623

@@ -641,8 +638,3 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
641638
return cleanedPath
642639
}
643640
}
644-
645-
extension HTTPField.Name {
646-
static let duplex = Self("duplex")!
647-
static let xUpsert = Self("x-upsert")!
648-
}

0 commit comments

Comments
 (0)