-
Notifications
You must be signed in to change notification settings - Fork 84
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
swift: add response interfaces #261
Closed
Closed
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import Foundation | ||
|
||
/// Error representing cases when no response was received from the server. | ||
/// I.e., the client went offline or became disconnected. | ||
@objcMembers | ||
public final class NetworkError: NSObject, Swift.Error { | ||
/// Message describing this error. | ||
public let message: String? | ||
|
||
/// Designated initializer. | ||
public init(message: String?) { | ||
self.message = message | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import Foundation | ||
|
||
/// Represents an Envoy HTTP response. Use `ResponseBuilder` to construct new instances. | ||
@objcMembers | ||
public final class Response: NSObject { | ||
/// Status code returned with the response. | ||
public let statusCode: Int | ||
/// Headers returned with the response. | ||
/// Multiple values for a given name are valid, and will be sent as comma-separated values. | ||
public let headers: [String: [String]] | ||
/// Trailers returned with the response. | ||
/// Multiple values for a given name are valid, and will be sent as comma-separated values. | ||
public let trailers: [String: [String]] | ||
/// Serialized data returned as the body of the response. | ||
public let body: Data? | ||
|
||
/// Converts the response back to a builder so that it can be modified (i.e., by a filter). | ||
/// | ||
/// - returns: A new builder including all the properties of this response. | ||
public func newBuilder() -> ResponseBuilder { | ||
return ResponseBuilder(response: self) | ||
} | ||
|
||
/// Internal initializer called from the builder to create a new response. | ||
init(statusCode: Int, | ||
headers: [String: [String]] = [:], | ||
trailers: [String: [String]] = [:], | ||
body: Data?) | ||
{ | ||
self.statusCode = statusCode | ||
self.headers = headers | ||
self.trailers = trailers | ||
self.body = body | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import Foundation | ||
|
||
/// Builder used for constructing instances of `Response` types. | ||
@objcMembers | ||
public final class ResponseBuilder: NSObject { | ||
/// Status code returned with the response. | ||
public private(set) var statusCode: Int = 200 | ||
/// Headers returned with the response. | ||
/// Multiple values for a given name are valid, and will be sent as comma-separated values. | ||
public private(set) var headers: [String: [String]] = [:] | ||
/// Trailers returned with the response. | ||
/// Multiple values for a given name are valid, and will be sent as comma-separated values. | ||
public private(set) var trailers: [String: [String]] = [:] | ||
/// Serialized data returned as the body of the response. | ||
public private(set) var body: Data? | ||
|
||
// MARK: - Initializers | ||
|
||
/// Internal initializer used for converting a response back to a builder. | ||
convenience init(response: Response) { | ||
self.init() | ||
self.statusCode = response.statusCode | ||
self.headers = response.headers | ||
self.trailers = response.trailers | ||
self.body = response.body | ||
} | ||
|
||
// MARK: - Builder functions | ||
|
||
@discardableResult | ||
public func addStatusCode(_ statusCode: Int) -> ResponseBuilder { | ||
self.statusCode = statusCode | ||
return self | ||
} | ||
|
||
@discardableResult | ||
public func addHeader(name: String, value: String) -> ResponseBuilder { | ||
self.headers[name, default: []].append(value) | ||
return self | ||
} | ||
|
||
@discardableResult | ||
public func removeHeaders(name: String) -> ResponseBuilder { | ||
self.headers.removeValue(forKey: name) | ||
return self | ||
} | ||
|
||
@discardableResult | ||
public func removeHeader(name: String, value: String) -> ResponseBuilder { | ||
self.headers[name]?.removeAll(where: { $0 == value }) | ||
if self.headers[name]?.isEmpty == true { | ||
self.headers.removeValue(forKey: name) | ||
} | ||
|
||
return self | ||
} | ||
|
||
@discardableResult | ||
public func addTrailer(name: String, value: String) -> ResponseBuilder { | ||
self.trailers[name, default: []].append(value) | ||
return self | ||
} | ||
|
||
@discardableResult | ||
public func removeTrailer(name: String) -> ResponseBuilder { | ||
self.trailers.removeValue(forKey: name) | ||
return self | ||
} | ||
|
||
@discardableResult | ||
public func removeTrailers(named name: String, value: String) -> ResponseBuilder { | ||
self.trailers[name]?.removeAll(where: { $0 == value }) | ||
if self.trailers[name]?.isEmpty == true { | ||
self.trailers.removeValue(forKey: name) | ||
} | ||
|
||
return self | ||
} | ||
|
||
@discardableResult | ||
public func addBody(_ body: Data?) -> ResponseBuilder { | ||
self.body = body | ||
return self | ||
} | ||
|
||
public func build() -> Response { | ||
return Response(statusCode: self.statusCode, | ||
headers: self.headers, | ||
trailers: self.trailers, | ||
body: self.body) | ||
} | ||
} | ||
|
||
// MARK: - Objective-C helpers | ||
|
||
extension Response { | ||
/// Convenience builder function to allow for cleaner Objective-C syntax. | ||
/// | ||
/// For example: | ||
/// | ||
/// Response *res = [Response withBuild:^(ResponseBuilder *builder) { | ||
/// [builder addBody:bodyData]; | ||
/// [builder addHeaderWithName:@"x-some-header" value:@"foo"]; | ||
/// [builder addTrailerWithName:@"x-some-trailer" value:@"foo"]; | ||
/// }]; | ||
@objc | ||
public static func with(build: (ResponseBuilder) -> Void) -> Response { | ||
let builder = ResponseBuilder() | ||
build(builder) | ||
return builder.build() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import Foundation | ||
|
||
/// A result returned from Envoy. | ||
@objcMembers | ||
public final class Result: NSObject { | ||
/// The response returned from the server. | ||
public let response: Response? | ||
/// An error that was encountered on the network (i.e., going offline). | ||
public let error: NetworkError? | ||
|
||
/// Designated initializer. | ||
public init(response: Response?, | ||
error: NetworkError?) | ||
{ | ||
self.response = response | ||
self.error = error | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, more of a platform question:
It is a swift convention to return an error and let the caller handle the error that way, correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you referring to doing this instead of
throw
ing?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The benefit of returning an error is that it can be typed. Swift doesn’t allow you to specify which errors can be thrown by a function, so consumers would have to catch all errors and cast. Also throwing wouldn’t work for async