Currently in Hyperspace 3.0, the Request protocol is the sole requirement for use with a BackendService. While the use of a protocol allows for more freedom of implementation and arguably better testability, it also introduces a few issues as we look to expand its capabilities.
Hyperspace requires a custom type conforming to Request in order to utilize an error type other than AnyError, which should be considered a best practice in error handling. This custom type does little more than act as a wrapper around the default Request protocol extensions.
Transformations are not possible because Request is not a concrete type. For example, we can not currently implement map on our request type as we no way of expressing the appropriate return type:
This same issue presents itself when looking to create a ChainedRequest or ParallelRequest. Because of a combination of the associatedtype requirements of Request and the unknown concrete type, it becomes difficult to chain or combine these requests in a meaningful way.
If we were to migrate from using a Request protocol to a request struct, we would not lose the functionality attached to conformance to the Request protocol.
Any custom type conforming to Request can instead become a static property or function on the Request type - which is a win for discoverability. For example:
struct CreatePostRequest: Request {
// Define the model we want to get back
typealias ResponseType = Post
typealias ErrorType = AnyError
// Define Request property values
var method: HTTP.Method = .post
var url = URL(string: "http://jsonplaceholder.typicode.com/posts")!
var queryParameters: [URLQueryItem]?
var headers: [HTTP.HeaderKey: HTTP.HeaderValue]? = [.contentType: .applicationJSON]
var body: Data? {
let encoder = JSONEncoder()
return try? encoder.encode(newPost)
}
// Define any custom properties needed
private let newPost: NewPost
// Initializer
init(newPost: NewPost) {
self.newPost = newPost
}
}
Because of the bulk of the test-requiring work is done in NetworkService and BackendService there doesn't appear to be any downside to migrating from a protocol based Request to a struct based one as the extensibility of a struct simply holding variables still allows for easy testing.
Currently in Hyperspace 3.0, the
Request
protocol is the sole requirement for use with aBackendService
. While the use of a protocol allows for more freedom of implementation and arguably better testability, it also introduces a few issues as we look to expand its capabilities.Hyperspace requires a custom type conforming to
Request
in order to utilize an error type other thanAnyError
, which should be considered a best practice in error handling. This custom type does little more than act as a wrapper around the defaultRequest
protocol extensions.Transformations are not possible because
Request
is not a concrete type. For example, we can not currently implementmap
on our request type as we no way of expressing the appropriate return type:ChainedRequest
orParallelRequest
. Because of a combination of the associatedtype requirements ofRequest
and the unknown concrete type, it becomes difficult to chain or combine these requests in a meaningful way.If we were to migrate from using a
Request
protocol to a requeststruct
, we would not lose the functionality attached to conformance to theRequest
protocol.Request
can instead become a static property or function on theRequest
type - which is a win for discoverability. For example:NetworkService
andBackendService
there doesn't appear to be any downside to migrating from a protocol basedRequest
to a struct based one as the extensibility of a struct simply holding variables still allows for easy testing.There is a test implementation available here: https://github.com/BottleRocketStudios/iOS-Hyperspace/tree/requestStruct