Skip to content

Commit

Permalink
Add "Client-Type" header for avatar upload request (#174)
Browse files Browse the repository at this point in the history
* Add header "Client-Type":"ios" to avatar upload

* Update version as 1.0.1
  • Loading branch information
pinarol committed Apr 4, 2024
1 parent 6812fd5 commit c6a115f
Show file tree
Hide file tree
Showing 5 changed files with 17 additions and 8 deletions.
2 changes: 1 addition & 1 deletion Sources/Gravatar/Network/Services/AvatarService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ public struct AvatarService {
/// - Returns: An asynchronously-delivered `URLResponse` instance, containing the response of the upload network task.
@discardableResult
public func upload(_ image: UIImage, email: Email, accessToken: String) async throws -> URLResponse {
try await imageUploader.uploadImage(image, email: email, accessToken: accessToken)
try await imageUploader.uploadImage(image, email: email, accessToken: accessToken, additionalHTTPHeaders: [(name: "Client-Type", value: "ios")])
}
}
14 changes: 9 additions & 5 deletions Sources/Gravatar/Network/Services/ImageUploadService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,18 @@ struct ImageUploadService: ImageUploader {
}

@discardableResult
func uploadImage(_ image: UIImage, email: Email, accessToken: String) async throws -> URLResponse {
func uploadImage(_ image: UIImage, email: Email, accessToken: String, additionalHTTPHeaders: [HTTPHeaderField]?) async throws -> URLResponse {
guard let data = image.pngData() else {
throw ImageUploadError.cannotConvertImageIntoData
}

return try await uploadImage(data: data, email: email, accessToken: accessToken)
return try await uploadImage(data: data, email: email, accessToken: accessToken, additionalHTTPHeaders: additionalHTTPHeaders)
}

private func uploadImage(data: Data, email: Email, accessToken: String) async throws -> URLResponse {
private func uploadImage(data: Data, email: Email, accessToken: String, additionalHTTPHeaders: [HTTPHeaderField]?) async throws -> URLResponse {
let boundary = "Boundary-\(UUID().uuidString)"
let request = URLRequest.imageUploadRequest(with: boundary).settingAuthorizationHeaderField(with: accessToken)
let request = URLRequest.imageUploadRequest(with: boundary, additionalHTTPHeaders: additionalHTTPHeaders)
.settingAuthorizationHeaderField(with: accessToken)
// For the Multipart form/data, we need to send the email address, not the id of the emai address
let body = imageUploadBody(with: data, account: email.rawValue, boundary: boundary) // TODO:
do {
Expand Down Expand Up @@ -75,11 +76,14 @@ extension Data {
}

extension URLRequest {
fileprivate static func imageUploadRequest(with boundary: String) -> URLRequest {
fileprivate static func imageUploadRequest(with boundary: String, additionalHTTPHeaders: [HTTPHeaderField]?) -> URLRequest {
let url = URL(string: "https://api.gravatar.com/v1/upload-image")!
var request = URLRequest(url: url)
request.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
additionalHTTPHeaders?.forEach { headerTuple in
request.addValue(headerTuple.value, forHTTPHeaderField: headerTuple.name)
}
return request
}
}
6 changes: 5 additions & 1 deletion Sources/Gravatar/Network/Services/ImageUploader.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import UIKit

typealias HTTPHeaderField = (name: String, value: String)

/// Represents a type which can be used by Gravatar to upload an image to Gravatar.
protocol ImageUploader {
/// Uploads an image to be used as the user's Gravatar profile image, and returns the `URLResponse` of the network tasks asynchronously. Throws
Expand All @@ -8,11 +10,13 @@ protocol ImageUploader {
/// - image: The image to be uploaded.
/// - email: The user email account.
/// - accessToken: The authentication token for the user.
/// - additionalHTTPHeaders: Additional headers to add.
/// - Returns: An asynchronously-delivered `URLResponse` instance, containing the response of the upload network task.
@discardableResult
func uploadImage(
_ image: UIImage,
email: Email,
accessToken: String
accessToken: String,
additionalHTTPHeaders: [HTTPHeaderField]?
) async throws -> URLResponse
}
1 change: 1 addition & 0 deletions Tests/GravatarTests/AvatarServiceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ final class AvatarServiceTests: XCTestCase {
XCTAssertTrue(sessionMock.request?.value(forHTTPHeaderField: "Authorization")?.hasPrefix("Bearer ") ?? false)
XCTAssertNotNil(sessionMock.request?.value(forHTTPHeaderField: "Content-Type"))
XCTAssertTrue(sessionMock.request?.value(forHTTPHeaderField: "Content-Type")?.hasPrefix("multipart/form-data; boundary=Boundary") ?? false)
XCTAssertTrue(sessionMock.request?.value(forHTTPHeaderField: "Client-Type") == "ios")
}

func testUploadImageError() async throws {
Expand Down
2 changes: 1 addition & 1 deletion version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Gravatar
VERSION = '1.0.0'.freeze
VERSION = '1.0.1'.freeze
end

0 comments on commit c6a115f

Please sign in to comment.