For a project that I am working on, I am trying to test my token refresh integration with Fetch. However, I am running into some limitations with the stubbing support of Fetch.
The Stub protocol is defined as follows:
/// A `Stub` represents a network response, which can be used to imitate an API endpoint
public protocol Stub {
/// HTTP status code
typealias StatusCode = Int
/// The result of the stubbed network call
/// It can be used to return a HTTP status code with a HTTP body and HTTP headers or an error
var result: Result<(StatusCode, Data, HTTPHeaders), Error> { get }
/// The id to identify a `Stub`. It is used to match the stub to the response
var id: UUID { get }
/// The `TimeInterval` after which the stub is returned to simulate a network delay
var delay: TimeInterval { get }
}
This is good, but does not support "dynamic" stubbing. To be more precise, I would like to adapt a stub, based on the request parameters. Here is what I would imagine a better (or more dynamic) stub to look like:
public struct StubResponse {
let statusCode: Int
let headers: HTTPHeaders
let body: Data
}
public protocol Stub {
var delay: TimeInterval { get }
func response(for request: URLRequest) -> StubResponse
}
Using this approach, more complex stubs could be constructed. For my personal use-case, I could define a stub that returns a 401 (triggering the token refresh logic) and for the second request a regular 200.
Another idea that I had when I played with the stubs is a better way to inject stubs. Right now, when defining stubs, I have to define them directly in the Resource. While this makes it great to read, it limits me in defining different stubs per test. Let's say, for one test I want to return a list with 4 entries, while for another test I want to return a list with zero entries.
Right now I am solving this by writing my own StubbingController where I register my stubs for routes. This, however, makes it annoying to define my Resouces, because I have to repeat myself a lot. A current Resource in my project looks like this:
public struct API {
@Injected(\.apiClient) private static var apiClient: APIClient
@Injected(\.stubbingController) private static var stubbingController: StubbingController
public static func login(username: String, password: String) -> Resource<Credentials> {
return Resource(
apiClient: apiClient,
method: .post,
path: "/auth/login",
body: .encodable([
"username": username,
"password": password
]),
stub: stubbingController.resolveStub(
for: .post,
path: "/auth/login"
)
)
}
}
As you can see, I can now dynamically resolve my stubs, however, I have to repeat this code for all my endpoints. If a mechanism like this was pre-built into Fetch, I would save myself a lot of work and the project would gain more flexibility.
I would love more opinions on these two ideas, especially since one of them is potentially API-breaking.
For a project that I am working on, I am trying to test my token refresh integration with Fetch. However, I am running into some limitations with the stubbing support of Fetch.
The
Stubprotocol is defined as follows:This is good, but does not support "dynamic" stubbing. To be more precise, I would like to adapt a stub, based on the request parameters. Here is what I would imagine a better (or more dynamic) stub to look like:
Using this approach, more complex stubs could be constructed. For my personal use-case, I could define a stub that returns a 401 (triggering the token refresh logic) and for the second request a regular 200.
Another idea that I had when I played with the stubs is a better way to inject stubs. Right now, when defining stubs, I have to define them directly in the
Resource. While this makes it great to read, it limits me in defining different stubs per test. Let's say, for one test I want to return a list with 4 entries, while for another test I want to return a list with zero entries.Right now I am solving this by writing my own
StubbingControllerwhere I register my stubs for routes. This, however, makes it annoying to define myResouces, because I have to repeat myself a lot. A currentResourcein my project looks like this:As you can see, I can now dynamically resolve my stubs, however, I have to repeat this code for all my endpoints. If a mechanism like this was pre-built into Fetch, I would save myself a lot of work and the project would gain more flexibility.
I would love more opinions on these two ideas, especially since one of them is potentially API-breaking.