Skip to content

Commit 84a7b10

Browse files
Merge pull request #5 from Microsoft/sharad/postImages
Fix post image and post blob
2 parents b53a3d7 + 12a4ffe commit 84a7b10

7 files changed

Lines changed: 96 additions & 149 deletions

File tree

EmbeddedSocialClient/Classes/Swaggers/APIs/BlobsAPI.swift

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -49,52 +49,59 @@ open class BlobsAPI: APIBase {
4949
return requestBuilder.init(method: "GET", URLString: (url?.string ?? URLString), parameters: parameters, isBody: false, headers: headerParameters)
5050
}
5151

52+
5253
/**
5354
Upload a blob
54-
- parameter authorization: (header) Format is: \"Scheme CredentialsList\". Possible values are: - Anon AK=AppKey - SocialPlus TK=SessionToken - Facebook AK=AppKey|TK=AccessToken - Google AK=AppKey|TK=AccessToken - Twitter AK=AppKey|RT=RequestToken|TK=AccessToken - Microsoft AK=AppKey|TK=AccessToken - AADS2S AK=AppKey|[UH=UserHandle]|TK=AADToken
55-
- parameter blob: (body) MIME encoded contents of the blob
55+
- parameter authorization: (header) Format is: \"Scheme CredentialsList\". Possible values are: - Anon AK=AppKey - SocialPlus TK=SessionToken - Facebook AK=AppKey|TK=AccessToken - Google AK=AppKey|TK=AccessToken - Twitter AK=AppKey|RT=RequestToken|TK=AccessToken - Microsoft AK=AppKey|TK=AccessToken - AADS2S AK=AppKey|[UH=UserHandle]|TK=AADToken
56+
- parameter blob: (body) MIME encoded contents of the blob
5657
- parameter completion: completion handler to receive the data and the error objects
5758
*/
5859
open class func blobsPostBlob(authorization: String, blob: Data, completion: @escaping ((_ data: PostBlobResponse?, _ error: ErrorResponse?) -> Void)) {
59-
blobsPostBlobWithRequestBuilder(authorization: authorization, blob: blob).execute { (response, error) -> Void in
60-
completion(response?.body, error)
61-
}
62-
}
63-
64-
65-
/**
66-
Upload a blob
67-
- POST /v0.7/blobs
68-
- If your blob is an image, use image APIs. For all other blob types, use this API.
69-
70-
- examples: [{contentType=application/json, example={
71-
"blobHandle" : "aeiou"
72-
}}, {contentType=application/xml, example=<null>
73-
<blobHandle>aeiou</blobHandle>
74-
</null>}]
75-
- examples: [{contentType=application/json, example={
76-
"blobHandle" : "aeiou"
77-
}}, {contentType=application/xml, example=<null>
78-
<blobHandle>aeiou</blobHandle>
79-
</null>}]
80-
- parameter authorization: (header) Format is: \&quot;Scheme CredentialsList\&quot;. Possible values are: - Anon AK&#x3D;AppKey - SocialPlus TK&#x3D;SessionToken - Facebook AK&#x3D;AppKey|TK&#x3D;AccessToken - Google AK&#x3D;AppKey|TK&#x3D;AccessToken - Twitter AK&#x3D;AppKey|RT&#x3D;RequestToken|TK&#x3D;AccessToken - Microsoft AK&#x3D;AppKey|TK&#x3D;AccessToken - AADS2S AK&#x3D;AppKey|[UH&#x3D;UserHandle]|TK&#x3D;AADToken
81-
- parameter blob: (body) MIME encoded contents of the blob
82-
- returns: RequestBuilder<PostBlobResponse>
83-
*/
84-
open class func blobsPostBlobWithRequestBuilder(authorization: String, blob: Data) -> RequestBuilder<PostBlobResponse> {
60+
61+
// construct the URL where the POST will be issued
8562
let path = "/v0.7/blobs"
8663
let URLString = EmbeddedSocialClientAPI.basePath + path
87-
let parameters = blob.encodeToJSON() as? [String:AnyObject]
88-
89-
let url = NSURLComponents(string: URLString)
90-
let nillableHeaders: [String: Any?] = [
91-
"Authorization": authorization
92-
]
93-
let headerParameters = APIHelper.rejectNilHeaders(nillableHeaders)
94-
95-
let requestBuilder: RequestBuilder<PostBlobResponse>.Type = EmbeddedSocialClientAPI.requestBuilderFactory.getBuilder()
96-
97-
return requestBuilder.init(method: "POST", URLString: (url?.string ?? URLString), parameters: parameters, isBody: true, headers: headerParameters)
64+
let url = URL(string: URLString)!
65+
var urlRequest = URLRequest(url: url)
66+
urlRequest.httpMethod = "POST"
67+
68+
// construct the body
69+
urlRequest.httpBody = blob
70+
71+
// construct the headers
72+
urlRequest.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
73+
urlRequest.setValue(authorization, forHTTPHeaderField: "Authorization")
74+
75+
// issue the request
76+
let dataRequest = Alamofire.request(urlRequest)
77+
78+
// parse the response
79+
let validatedDataRequest = dataRequest.validate()
80+
validatedDataRequest.responseJSON(options: .allowFragments) { response in
81+
// failure
82+
if response.result.isFailure {
83+
completion(nil, ErrorResponse.HttpError(statusCode: response.response?.statusCode ?? 500, data: response.data, error: response.result.error!))
84+
return
85+
}
86+
87+
// handle HTTP 204 No Content
88+
if response.response?.statusCode == 204 && response.result.value is NSNull{
89+
completion(nil, nil)
90+
return
91+
}
92+
93+
// parse the result into PostBlobResponse
94+
if let json: Any = response.result.value {
95+
let decoded = Decoders.decode(clazz: PostBlobResponse.self, source: json as AnyObject, instance: nil)
96+
switch decoded {
97+
case let .success(object): completion(object, nil)
98+
case let .failure(error): completion(nil, ErrorResponse.DecodeError(response: response.data, decodeError: error))
99+
}
100+
return
101+
}
102+
103+
// unexpected
104+
completion(nil, ErrorResponse.HttpError(statusCode: 500, data: nil, error: NSError(domain: "localhost", code: 500, userInfo: ["reason": "unreacheable code"])))
105+
}
98106
}
99-
100107
}

EmbeddedSocialClient/Classes/Swaggers/APIs/ImagesAPI.swift

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -63,50 +63,56 @@ open class ImagesAPI: APIBase {
6363
- parameter imageType: (path) Image type
6464
- parameter authorization: (header) Format is: \&quot;Scheme CredentialsList\&quot;. Possible values are: - Anon AK&#x3D;AppKey - SocialPlus TK&#x3D;SessionToken - Facebook AK&#x3D;AppKey|TK&#x3D;AccessToken - Google AK&#x3D;AppKey|TK&#x3D;AccessToken - Twitter AK&#x3D;AppKey|RT&#x3D;RequestToken|TK&#x3D;AccessToken - Microsoft AK&#x3D;AppKey|TK&#x3D;AccessToken - AADS2S AK&#x3D;AppKey|[UH&#x3D;UserHandle]|TK&#x3D;AADToken
6565
- parameter image: (body) MIME encoded contents of the image
66+
- parameter imageFileType: type of the file, such as "image/jpeg", "image/png", or "image/gif"
6667
- parameter completion: completion handler to receive the data and the error objects
6768
*/
68-
open class func imagesPostImage(imageType: ImageType_imagesPostImage, authorization: String, image: Data, completion: @escaping ((_ data: PostImageResponse?, _ error: ErrorResponse?) -> Void)) {
69-
imagesPostImageWithRequestBuilder(imageType: imageType, authorization: authorization, image: image).execute { (response, error) -> Void in
70-
completion(response?.body, error)
71-
}
72-
}
73-
74-
75-
/**
76-
Upload a new image
77-
- POST /v0.7/images/{imageType}
78-
- Images will be resized. To access a resized image, append the 1 character size identifier to the blobHandle that is returned. - d is 25 pixels wide - h is 50 pixels wide - l is 100 pixels wide - p is 250 pixels wide - t is 500 pixels wide - x is 1000 pixels wide - ImageType.UserPhoto supports d,h,l,p,t,x - ImageType.ContentBlob supports d,h,l,p,t,x - ImageType.AppIcon supports l All resized images will maintain their aspect ratio. Any orientation specified in the EXIF headers will be honored.
79-
80-
- examples: [{contentType=application/json, example={
81-
"blobHandle" : "aeiou"
82-
}}, {contentType=application/xml, example=<null>
83-
<blobHandle>aeiou</blobHandle>
84-
</null>}]
85-
- examples: [{contentType=application/json, example={
86-
"blobHandle" : "aeiou"
87-
}}, {contentType=application/xml, example=<null>
88-
<blobHandle>aeiou</blobHandle>
89-
</null>}]
90-
- parameter imageType: (path) Image type
91-
- parameter authorization: (header) Format is: \&quot;Scheme CredentialsList\&quot;. Possible values are: - Anon AK&#x3D;AppKey - SocialPlus TK&#x3D;SessionToken - Facebook AK&#x3D;AppKey|TK&#x3D;AccessToken - Google AK&#x3D;AppKey|TK&#x3D;AccessToken - Twitter AK&#x3D;AppKey|RT&#x3D;RequestToken|TK&#x3D;AccessToken - Microsoft AK&#x3D;AppKey|TK&#x3D;AccessToken - AADS2S AK&#x3D;AppKey|[UH&#x3D;UserHandle]|TK&#x3D;AADToken
92-
- parameter image: (body) MIME encoded contents of the image
93-
- returns: RequestBuilder<PostImageResponse>
94-
*/
95-
open class func imagesPostImageWithRequestBuilder(imageType: ImageType_imagesPostImage, authorization: String, image: Data) -> RequestBuilder<PostImageResponse> {
69+
open class func imagesPostImage(imageType: ImageType_imagesPostImage, authorization: String, image: Data, imageFileType: String, completion: @escaping ((_ data: PostImageResponse?, _ error: ErrorResponse?) -> Void)) {
70+
71+
// construct the URL where the POST will be issued
9672
var path = "/v0.7/images/{imageType}"
9773
path = path.replacingOccurrences(of: "{imageType}", with: "\(imageType.rawValue)", options: .literal, range: nil)
9874
let URLString = EmbeddedSocialClientAPI.basePath + path
99-
let parameters = image.encodeToJSON() as? [String:AnyObject]
100-
101-
let url = NSURLComponents(string: URLString)
102-
let nillableHeaders: [String: Any?] = [
103-
"Authorization": authorization
104-
]
105-
let headerParameters = APIHelper.rejectNilHeaders(nillableHeaders)
106-
107-
let requestBuilder: RequestBuilder<PostImageResponse>.Type = EmbeddedSocialClientAPI.requestBuilderFactory.getBuilder()
108-
109-
return requestBuilder.init(method: "POST", URLString: (url?.string ?? URLString), parameters: parameters, isBody: true, headers: headerParameters)
75+
let url = URL(string: URLString)!
76+
var urlRequest = URLRequest(url: url)
77+
urlRequest.httpMethod = "POST"
78+
79+
// construct the body
80+
urlRequest.httpBody = image
81+
82+
// construct the headers
83+
urlRequest.setValue(imageFileType, forHTTPHeaderField: "Content-Type")
84+
urlRequest.setValue(authorization, forHTTPHeaderField: "Authorization")
85+
86+
// issue the request
87+
let dataRequest = Alamofire.request(urlRequest)
88+
89+
// parse the response
90+
let validatedDataRequest = dataRequest.validate()
91+
validatedDataRequest.responseJSON(options: .allowFragments) { response in
92+
// failure
93+
if response.result.isFailure {
94+
completion(nil, ErrorResponse.HttpError(statusCode: response.response?.statusCode ?? 500, data: response.data, error: response.result.error!))
95+
return
96+
}
97+
98+
// handle HTTP 204 No Content
99+
if response.response?.statusCode == 204 && response.result.value is NSNull{
100+
completion(nil, nil)
101+
return
102+
}
103+
104+
// parse the result into PostImageResponse
105+
if let json: Any = response.result.value {
106+
let decoded = Decoders.decode(clazz: PostImageResponse.self, source: json as AnyObject, instance: nil)
107+
switch decoded {
108+
case let .success(object): completion(object, nil)
109+
case let .failure(error): completion(nil, ErrorResponse.DecodeError(response: response.data, decodeError: error))
110+
}
111+
return
112+
}
113+
114+
// unexpected
115+
completion(nil, ErrorResponse.HttpError(statusCode: 500, data: nil, error: NSError(domain: "localhost", code: 500, userInfo: ["reason": "unreacheable code"])))
116+
}
110117
}
111-
112118
}

EmbeddedSocialClient/EmbeddedSocialClient.xcodeproj/project.pbxproj

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
/* Begin PBXBuildFile section */
1010
10CB59A8CB005D588DA77543 /* Pods_EmbeddedSocialClientTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 759F48EE3269A3D8C0344D63 /* Pods_EmbeddedSocialClientTests.framework */; };
11-
6F3370E71F22DDBF00795CE1 /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6FED03B31F22C81D00850DCA /* Media.xcassets */; };
1211
6F5B44481F21511200FE6092 /* EmbeddedSocialClient.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F5B443E1F21511200FE6092 /* EmbeddedSocialClient.framework */; };
1312
6F5B444D1F21511200FE6092 /* EmbeddedSocialClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F5B444C1F21511200FE6092 /* EmbeddedSocialClientTests.swift */; };
1413
6FB3094D1F23F8BA000E8C6D /* GetTopicByNameResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FB3094C1F23F8BA000E8C6D /* GetTopicByNameResponse.swift */; };
@@ -172,7 +171,6 @@
172171
6FC066451F2151C4003746BB /* UserCompactView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserCompactView.swift; sourceTree = "<group>"; };
173172
6FC066461F2151C4003746BB /* UserProfileView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserProfileView.swift; sourceTree = "<group>"; };
174173
6FC066471F2151C4003746BB /* Models.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Models.swift; sourceTree = "<group>"; };
175-
6FED03B31F22C81D00850DCA /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Media.xcassets; sourceTree = "<group>"; };
176174
759F48EE3269A3D8C0344D63 /* Pods_EmbeddedSocialClientTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_EmbeddedSocialClientTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
177175
778EFBA489D0AA3A50F921E2 /* Pods-EmbeddedSocialClient.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-EmbeddedSocialClient.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-EmbeddedSocialClient/Pods-EmbeddedSocialClient.debug.xcconfig"; sourceTree = "<group>"; };
178176
C569334B6D7EFFD8CE780404 /* Pods_EmbeddedSocialClient.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_EmbeddedSocialClient.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -245,7 +243,6 @@
245243
children = (
246244
6F5B444C1F21511200FE6092 /* EmbeddedSocialClientTests.swift */,
247245
6F5B444E1F21511200FE6092 /* Info.plist */,
248-
6FED03B31F22C81D00850DCA /* Media.xcassets */,
249246
);
250247
path = EmbeddedSocialClientTests;
251248
sourceTree = "<group>";
@@ -466,7 +463,6 @@
466463
isa = PBXResourcesBuildPhase;
467464
buildActionMask = 2147483647;
468465
files = (
469-
6F3370E71F22DDBF00795CE1 /* Media.xcassets in Resources */,
470466
);
471467
runOnlyForDeploymentPostprocessing = 0;
472468
};

EmbeddedSocialClient/EmbeddedSocialClientTests/EmbeddedSocialClientTests.swift

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ class EmbeddedSocialClientTests: XCTestCase {
2020
// which authorization to use for API calls that require authentication
2121
let authorization = "XXX"
2222

23-
// which images to use
23+
// which image to use
2424
let myImageURL = URL(string: "https://i2.wp.com/sharadagarwaldotnet.files.wordpress.com/2016/02/sharad_suit_square2.jpg")
25+
let myImageFileType = "image/jpeg"
2526

2627
// Put setup code here. This method is called before the invocation of each test method in the class.
2728
override func setUp() {
@@ -104,42 +105,6 @@ class EmbeddedSocialClientTests: XCTestCase {
104105
}
105106
}
106107

107-
// Test the PostImage API call using a resource file
108-
func testPostImageFromFile() {
109-
let expectation = self.expectation(description: "testPostImageFromFile")
110-
111-
// setup the client interface
112-
EmbeddedSocialClientAPI.basePath = serverURL
113-
114-
// load an image into memory
115-
let myImageFile = #imageLiteral(resourceName: "sharad")
116-
let imageData = UIImageJPEGRepresentation(myImageFile, 1.0)
117-
118-
// issue the API call
119-
ImagesAPI.imagesPostImage(imageType: ImagesAPI.ImageType_imagesPostImage.contentBlob, authorization: authorization, image: imageData!) { (postImageResponse: PostImageResponse?, error: Error?) in
120-
if let error = error {
121-
XCTFail("error posting new image : \(error.localizedDescription)")
122-
return
123-
}
124-
125-
guard let postImageResponse = postImageResponse else {
126-
XCTFail("did not get post image response")
127-
return
128-
}
129-
130-
XCTAssert(postImageResponse.blobHandle != nil)
131-
XCTAssert(!postImageResponse.blobHandle!.isEmpty)
132-
print("new blob handle is \(postImageResponse.blobHandle!)")
133-
expectation.fulfill()
134-
}
135-
136-
self.waitForExpectations(timeout: self.testTimeout) { error in
137-
if let error = error {
138-
XCTFail("waitForExpectations errored: \(error)")
139-
}
140-
}
141-
}
142-
143108
// Test the PostImage API call using a URL
144109
func testPostImageFromURL() {
145110
let expectation = self.expectation(description: "testPostImageFromURL")
@@ -158,7 +123,7 @@ class EmbeddedSocialClientTests: XCTestCase {
158123
}
159124

160125
// issue the API call
161-
ImagesAPI.imagesPostImage(imageType: ImagesAPI.ImageType_imagesPostImage.contentBlob, authorization: authorization, image: imageData!) { (postImageResponse: PostImageResponse?, error: Error?) in
126+
ImagesAPI.imagesPostImage(imageType: ImagesAPI.ImageType_imagesPostImage.contentBlob, authorization: authorization, image: imageData!, imageFileType: myImageFileType) { (postImageResponse: PostImageResponse?, error: Error?) in
162127
if let error = error {
163128
XCTFail("error posting new image : \(error.localizedDescription)")
164129
return

EmbeddedSocialClient/EmbeddedSocialClientTests/Media.xcassets/Contents.json

Lines changed: 0 additions & 6 deletions
This file was deleted.

EmbeddedSocialClient/EmbeddedSocialClientTests/Media.xcassets/sharad.imageset/Contents.json

Lines changed: 0 additions & 21 deletions
This file was deleted.
Binary file not shown.

0 commit comments

Comments
 (0)