Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swift3: non dictionary body type #6531

Merged
merged 6 commits into from
Sep 28, 2017
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ open class APIBase {
open class RequestBuilder<T> {
var credential: URLCredential?
var headers: [String:String]
let parameters: [String:Any]?
let parameters: Any?
let isBody: Bool
let method: String
let URLString: String

/// Optional block to obtain a reference to the request's progress instance when available.
public var onProgressReady: ((Progress) -> ())?

required public init(method: String, URLString: String, parameters: [String:Any]?, isBody: Bool, headers: [String:String] = [:]) {
required public init(method: String, URLString: String, parameters: Any?, isBody: Bool, headers: [String:String] = [:]) {
self.method = method
self.URLString = URLString
self.parameters = parameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ private struct SynchronizedDictionary<K: Hashable, V> {
private var managerStore = SynchronizedDictionary<String, Alamofire.SessionManager>()

open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
required public init(method: String, URLString: String, parameters: [String : Any]?, isBody: Bool, headers: [String : String] = [:]) {
required public init(method: String, URLString: String, parameters: Any?, isBody: Bool, headers: [String : String] = [:]) {
super.init(method: method, URLString: URLString, parameters: parameters, isBody: isBody, headers: headers)
}

Expand Down Expand Up @@ -76,8 +76,15 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
May be overridden by a subclass if you want to control the request
configuration (e.g. to override the cache policy).
*/
open func makeRequest(manager: SessionManager, method: HTTPMethod, encoding: ParameterEncoding, headers: [String:String]) -> DataRequest {
return manager.request(URLString, method: method, parameters: parameters, encoding: encoding, headers: headers)
open func makeRequest(manager: SessionManager, method: HTTPMethod, encoding: ParameterEncoding, headers: [String:String]) throws -> DataRequest {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added throws here... which might break peoples implementation if they are extending AlamofireRequestBuilder. They would need to add some type of try in there code if they are calling super.makeRequest. I can back this out, but originally the manager.request was handling these errors for us.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be cleaner to keep the original implementation w/o throws and just return an error if the try's below fail just like in manger.request:
return request(originalRequest, failedWith: error)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thats what I wanted to do originally but that method is private. I could try figuring out whats going on in that function and try to mimic it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could this logic be pushed into SessionManager.swift? so AlamofireImplementations just calls a helper method in that class which then has access to that function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SessionManager is part of Alamo if I remember correctly. I don't think that will work.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah you're correct. maybe just return some type of error instead (not necessary copying Alamo's logic exactly but something similar)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So change the method signature? Right now it expects DataRequest to be returned. I was trying to avoid changing the method signature but if thats ok I can do that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jgavris any thoughts as to how to avoid changing the method signature here so we all don't have to try/catch around these blocks?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my only thought would be to make a new request in the catch block w/ some bogus url to force an error... but seems messy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I though about this for a while and I think I finally have a clean solution. I'll update the pull request in a little bit.

let originalRequest = try URLRequest(url: URLString, method: method, headers: headers)
if let encoding = encoding as? JSONEncoding {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to do this here since ParameterEncoding protocol only nows how to take Parameters?. JSONEncoding has a special encode function that will take Any?.

let encodedRequest = try encoding.encode(originalRequest, withJSONObject: parameters)
return manager.request(encodedRequest)
} else {
let encodedRequest = try encoding.encode(originalRequest, with: parameters as? Parameters)
return manager.request(encodedRequest)
}
}

override open func execute(_ completion: @escaping (_ response: Response<T>?, _ error: ErrorResponse?) -> Void) {
Expand All @@ -89,12 +96,14 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
let encoding:ParameterEncoding = isBody ? JSONEncoding() : URLEncoding()

let xMethod = Alamofire.HTTPMethod(rawValue: method)
let fileKeys = parameters == nil ? [] : parameters!.filter { $1 is NSURL }

let param = parameters as? Parameters
let fileKeys = param == nil ? [] : param!.filter { $1 is NSURL }
.map { $0.0 }

if fileKeys.count > 0 {
manager.upload(multipartFormData: { mpForm in
for (k, v) in self.parameters! {
for (k, v) in param! {
switch v {
case let fileURL as URL:
if let mimeType = self.contentTypeForFormPart(fileURL: fileURL) {
Expand Down Expand Up @@ -127,11 +136,15 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
}
})
} else {
let request = makeRequest(manager: manager, method: xMethod!, encoding: encoding, headers: headers)
if let onProgressReady = self.onProgressReady {
onProgressReady(request.progress)
do {
let request = try makeRequest(manager: manager, method: xMethod!, encoding: encoding, headers: headers)
if let onProgressReady = self.onProgressReady {
onProgressReady(request.progress)
}
processRequest(request: request, managerId, completion)
} catch {
completion(nil, ErrorResponse.HttpError(statusCode: 500, data: nil, error: error))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is 500 the right status code here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

y that looks right

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about returning a response code if this didn't come from the server. It could be confusing / misleading.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree and I'm not really sure HttpError actually make since here. Changing how the error system would be a bigger change?

Also I choose 500 since that was the closest to what processRequest would have done. I think this is the response you would have gotten in the old code.
ErrorResponse.HttpError(statusCode: response.response?.statusCode ?? 500, data: response.data, error: response.result.error!)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jgavris hmm we do send the 500 at the end of processRequest in AlamofireImplementations as well - maybe we should avoid doing that - is there a better type of ErrorResponse to return?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that...yes we should improve it. Maybe we can add a case ClientError to ErrorResposne enum?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For other API client (e.g. PHP), we set the status code to 0 in the API exception object/class if the issue happens in the client side (e.g. network issue). Maybe we can follow the same convention in the Swift client.

}
processRequest(request: request, managerId, completion)
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ open class {{classname}}: APIBase {
path = path.replacingOccurrences(of: "{{=<% %>=}}{<%baseName%>}<%={{ }}=%>", with: "\({{paramName}}{{#isEnum}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}.rawValue{{/isContainer}}{{/isEnum}})", options: .literal, range: nil){{/pathParams}}
let URLString = {{projectName}}API.basePath + path
{{#bodyParam}}
let parameters = {{paramName}}{{^required}}?{{/required}}.encodeToJSON() as? [String:AnyObject]
let parameters = {{paramName}}{{^required}}?{{/required}}.encodeToJSON()
{{/bodyParam}}
{{^bodyParam}}
{{#hasFormParams}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ open class APIBase {
open class RequestBuilder<T> {
var credential: URLCredential?
var headers: [String:String]
let parameters: [String:Any]?
let parameters: Any?
let isBody: Bool
let method: String
let URLString: String

/// Optional block to obtain a reference to the request's progress instance when available.
public var onProgressReady: ((Progress) -> ())?

required public init(method: String, URLString: String, parameters: [String:Any]?, isBody: Bool, headers: [String:String] = [:]) {
required public init(method: String, URLString: String, parameters: Any?, isBody: Bool, headers: [String:String] = [:]) {
self.method = method
self.URLString = URLString
self.parameters = parameters
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// AnotherFakeAPI.swift
//
// Generated by swagger-codegen
// https://github.com/swagger-api/swagger-codegen
//

import Foundation
import Alamofire


open class AnotherFakeAPI: APIBase {
/**
To test special tags
- parameter body: (body) client model
- parameter completion: completion handler to receive the data and the error objects
*/
open class func testSpecialTags(body: Client, completion: @escaping ((_ data: Client?, _ error: ErrorResponse?) -> Void)) {
testSpecialTagsWithRequestBuilder(body: body).execute { (response, error) -> Void in
completion(response?.body, error)
}
}


/**
To test special tags
- PATCH /another-fake/dummy
- To test special tags

- examples: [{contentType=application/json, example={
"client" : "client"
}}]
- parameter body: (body) client model
- returns: RequestBuilder<Client>
*/
open class func testSpecialTagsWithRequestBuilder(body: Client) -> RequestBuilder<Client> {
let path = "/another-fake/dummy"
let URLString = PetstoreClientAPI.basePath + path
let parameters = body.encodeToJSON()

let url = NSURLComponents(string: URLString)

let requestBuilder: RequestBuilder<Client>.Type = PetstoreClientAPI.requestBuilderFactory.getBuilder()

return requestBuilder.init(method: "PATCH", URLString: (url?.string ?? URLString), parameters: parameters, isBody: true)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ open class FakeAPI: APIBase {
open class func fakeOuterBooleanSerializeWithRequestBuilder(body: OuterBoolean? = nil) -> RequestBuilder<OuterBoolean> {
let path = "/fake/outer/boolean"
let URLString = PetstoreClientAPI.basePath + path
let parameters = body?.encodeToJSON() as? [String:AnyObject]
let parameters = body?.encodeToJSON()

let url = NSURLComponents(string: URLString)

Expand Down Expand Up @@ -67,7 +67,7 @@ open class FakeAPI: APIBase {
open class func fakeOuterCompositeSerializeWithRequestBuilder(body: OuterComposite? = nil) -> RequestBuilder<OuterComposite> {
let path = "/fake/outer/composite"
let URLString = PetstoreClientAPI.basePath + path
let parameters = body?.encodeToJSON() as? [String:AnyObject]
let parameters = body?.encodeToJSON()

let url = NSURLComponents(string: URLString)

Expand Down Expand Up @@ -98,7 +98,7 @@ open class FakeAPI: APIBase {
open class func fakeOuterNumberSerializeWithRequestBuilder(body: OuterNumber? = nil) -> RequestBuilder<OuterNumber> {
let path = "/fake/outer/number"
let URLString = PetstoreClientAPI.basePath + path
let parameters = body?.encodeToJSON() as? [String:AnyObject]
let parameters = body?.encodeToJSON()

let url = NSURLComponents(string: URLString)

Expand Down Expand Up @@ -129,7 +129,7 @@ open class FakeAPI: APIBase {
open class func fakeOuterStringSerializeWithRequestBuilder(body: OuterString? = nil) -> RequestBuilder<OuterString> {
let path = "/fake/outer/string"
let URLString = PetstoreClientAPI.basePath + path
let parameters = body?.encodeToJSON() as? [String:AnyObject]
let parameters = body?.encodeToJSON()

let url = NSURLComponents(string: URLString)

Expand Down Expand Up @@ -164,7 +164,7 @@ open class FakeAPI: APIBase {
open class func testClientModelWithRequestBuilder(body: Client) -> RequestBuilder<Client> {
let path = "/fake"
let URLString = PetstoreClientAPI.basePath + path
let parameters = body.encodeToJSON() as? [String:AnyObject]
let parameters = body.encodeToJSON()

let url = NSURLComponents(string: URLString)

Expand Down Expand Up @@ -307,15 +307,15 @@ open class FakeAPI: APIBase {
*/
public enum EnumQueryInteger_testEnumParameters: Int32 {
case _1 = 1
case numberminus2 = -2
case number2 = -2
}

/**
* enum for parameter enumQueryDouble
*/
public enum EnumQueryDouble_testEnumParameters: Double {
case _11 = 1.1
case numberminus12 = -1.2
case number12 = -1.2
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// FakeClassnameTags123API.swift
//
// Generated by swagger-codegen
// https://github.com/swagger-api/swagger-codegen
//

import Foundation
import Alamofire


open class FakeClassnameTags123API: APIBase {
/**
To test class name in snake case
- parameter body: (body) client model
- parameter completion: completion handler to receive the data and the error objects
*/
open class func testClassname(body: Client, completion: @escaping ((_ data: Client?, _ error: ErrorResponse?) -> Void)) {
testClassnameWithRequestBuilder(body: body).execute { (response, error) -> Void in
completion(response?.body, error)
}
}


/**
To test class name in snake case
- PATCH /fake_classname_test
- API Key:
- type: apiKey api_key_query (QUERY)
- name: api_key_query
- examples: [{contentType=application/json, example={
"client" : "client"
}}]
- parameter body: (body) client model
- returns: RequestBuilder<Client>
*/
open class func testClassnameWithRequestBuilder(body: Client) -> RequestBuilder<Client> {
let path = "/fake_classname_test"
let URLString = PetstoreClientAPI.basePath + path
let parameters = body.encodeToJSON()

let url = NSURLComponents(string: URLString)

let requestBuilder: RequestBuilder<Client>.Type = PetstoreClientAPI.requestBuilderFactory.getBuilder()

return requestBuilder.init(method: "PATCH", URLString: (url?.string ?? URLString), parameters: parameters, isBody: true)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ open class PetAPI: APIBase {
open class func addPetWithRequestBuilder(body: Pet) -> RequestBuilder<Void> {
let path = "/pet"
let URLString = PetstoreClientAPI.basePath + path
let parameters = body.encodeToJSON() as? [String:AnyObject]
let parameters = body.encodeToJSON()

let url = NSURLComponents(string: URLString)

Expand Down Expand Up @@ -448,7 +448,7 @@ open class PetAPI: APIBase {
open class func updatePetWithRequestBuilder(body: Pet) -> RequestBuilder<Void> {
let path = "/pet"
let URLString = PetstoreClientAPI.basePath + path
let parameters = body.encodeToJSON() as? [String:AnyObject]
let parameters = body.encodeToJSON()

let url = NSURLComponents(string: URLString)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ open class StoreAPI: APIBase {
open class func placeOrderWithRequestBuilder(body: Order) -> RequestBuilder<Order> {
let path = "/store/order"
let URLString = PetstoreClientAPI.basePath + path
let parameters = body.encodeToJSON() as? [String:AnyObject]
let parameters = body.encodeToJSON()

let url = NSURLComponents(string: URLString)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ open class UserAPI: APIBase {
open class func createUserWithRequestBuilder(body: User) -> RequestBuilder<Void> {
let path = "/user"
let URLString = PetstoreClientAPI.basePath + path
let parameters = body.encodeToJSON() as? [String:AnyObject]
let parameters = body.encodeToJSON()

let url = NSURLComponents(string: URLString)

Expand Down Expand Up @@ -65,7 +65,7 @@ open class UserAPI: APIBase {
open class func createUsersWithArrayInputWithRequestBuilder(body: [User]) -> RequestBuilder<Void> {
let path = "/user/createWithArray"
let URLString = PetstoreClientAPI.basePath + path
let parameters = body.encodeToJSON() as? [String:AnyObject]
let parameters = body.encodeToJSON()

let url = NSURLComponents(string: URLString)

Expand Down Expand Up @@ -97,7 +97,7 @@ open class UserAPI: APIBase {
open class func createUsersWithListInputWithRequestBuilder(body: [User]) -> RequestBuilder<Void> {
let path = "/user/createWithList"
let URLString = PetstoreClientAPI.basePath + path
let parameters = body.encodeToJSON() as? [String:AnyObject]
let parameters = body.encodeToJSON()

let url = NSURLComponents(string: URLString)

Expand Down Expand Up @@ -308,7 +308,7 @@ open class UserAPI: APIBase {
var path = "/user/{username}"
path = path.replacingOccurrences(of: "{username}", with: "\(username)", options: .literal, range: nil)
let URLString = PetstoreClientAPI.basePath + path
let parameters = body.encodeToJSON() as? [String:AnyObject]
let parameters = body.encodeToJSON()

let url = NSURLComponents(string: URLString)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ private struct SynchronizedDictionary<K: Hashable, V> {
private var managerStore = SynchronizedDictionary<String, Alamofire.SessionManager>()

open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
required public init(method: String, URLString: String, parameters: [String : Any]?, isBody: Bool, headers: [String : String] = [:]) {
required public init(method: String, URLString: String, parameters: Any?, isBody: Bool, headers: [String : String] = [:]) {
super.init(method: method, URLString: URLString, parameters: parameters, isBody: isBody, headers: headers)
}

Expand Down Expand Up @@ -76,8 +76,15 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
May be overridden by a subclass if you want to control the request
configuration (e.g. to override the cache policy).
*/
open func makeRequest(manager: SessionManager, method: HTTPMethod, encoding: ParameterEncoding, headers: [String:String]) -> DataRequest {
return manager.request(URLString, method: method, parameters: parameters, encoding: encoding, headers: headers)
open func makeRequest(manager: SessionManager, method: HTTPMethod, encoding: ParameterEncoding, headers: [String:String]) throws -> DataRequest {
let originalRequest = try URLRequest(url: URLString, method: method, headers: headers)
if let encoding = encoding as? JSONEncoding {
let encodedRequest = try encoding.encode(originalRequest, withJSONObject: parameters)
return manager.request(encodedRequest)
} else {
let encodedRequest = try encoding.encode(originalRequest, with: parameters as? Parameters)
return manager.request(encodedRequest)
}
}

override open func execute(_ completion: @escaping (_ response: Response<T>?, _ error: ErrorResponse?) -> Void) {
Expand All @@ -89,12 +96,14 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
let encoding:ParameterEncoding = isBody ? JSONEncoding() : URLEncoding()

let xMethod = Alamofire.HTTPMethod(rawValue: method)
let fileKeys = parameters == nil ? [] : parameters!.filter { $1 is NSURL }

let param = parameters as? Parameters
let fileKeys = param == nil ? [] : param!.filter { $1 is NSURL }
.map { $0.0 }

if fileKeys.count > 0 {
manager.upload(multipartFormData: { mpForm in
for (k, v) in self.parameters! {
for (k, v) in param! {
switch v {
case let fileURL as URL:
if let mimeType = self.contentTypeForFormPart(fileURL: fileURL) {
Expand Down Expand Up @@ -127,11 +136,15 @@ open class AlamofireRequestBuilder<T>: RequestBuilder<T> {
}
})
} else {
let request = makeRequest(manager: manager, method: xMethod!, encoding: encoding, headers: headers)
if let onProgressReady = self.onProgressReady {
onProgressReady(request.progress)
do {
let request = try makeRequest(manager: manager, method: xMethod!, encoding: encoding, headers: headers)
if let onProgressReady = self.onProgressReady {
onProgressReady(request.progress)
}
processRequest(request: request, managerId, completion)
} catch {
completion(nil, ErrorResponse.HttpError(statusCode: 500, data: nil, error: error))
}
processRequest(request: request, managerId, completion)
}

}
Expand Down
Loading