Relay is a Swift framework that simplifies recording, replaying, intercepting, and modifying network requests to enhance testing and debugging of network interactions in iOS applications.
The primary use case for Relay is unit tests and SwiftUI previews that require server connections. By recording server responses once and replaying them in subsequent runs, you ensure fast, consistent, and reliable tests without constantly hitting the actual server. Relay also shines in SwiftUI previews, allowing you to load previews using previously recorded data. This accelerates the preview process, lets you manipulate a single recorded response for various states, and avoids repeatedly calling the server.
When you run your test or preview with isRecordingEnabled = true
, Relay intercepts HTTP requests and captures both the request and the corresponding response. These are stored as separate files in a structured directory (e.g., __RelayRecords__
) relative to the test or preview code file. On subsequent runs, when isRecordingEnabled = false
, Relay looks up these stored files and returns their recorded responses without making actual network calls. This means you can rely on consistent and stable test inputs and fast-loading previews.
Below is an example of how recorded files might be organized:
Tests
└─ __RelayRecords__
├─ customSession
│ └─ GET-typicode.com-posts_a25b94c312bb64a5
├─ defaultSession
│ └─ GET-typicode.com-posts_e3fdab5b4d16442f
├─ handleMultipleRequests
│ ├─ GET-typicode.com-posts_9986e99294a801c6
│ ├─ GET-typicode.com-users_1a8fe3094918fe243
│ └─ POST-typicode.com-posts_ea6ce919bf1be8a6
... and so on
Each directory represents a specific test scenario or function call, and each file inside corresponds to a particular network request/response pair that Relay recorded.
- Record and Replay: Capture network requests and responses once, and replay them for tests and previews to ensure consistent, reproducible results.
- Flexible Response Modification: Dynamically override JSON key-value pairs to simulate different states or conditions using the same recording.
- Request Interception: Intercept and optionally modify requests based on URL keywords for enhanced testing and preview scenarios without constant server calls.
-
Initial Setup and Recording:
- Run your unit test or SwiftUI preview with
isRecordingEnabled = true
. - Relay records all intercepted network requests and their responses.
- Run your unit test or SwiftUI preview with
-
Subsequent Uses with Recorded Data:
- Turn off recording (
isRecordingEnabled = false
). - Relay now uses the previously recorded responses from the file system, ensuring no live server calls.
- Turn off recording (
-
Manipulating Recorded Results:
- Use
jsonValueOverrides
to modify parts of the recorded response dynamically, simulating different states without needing new recordings.
- Use
First, import Relay at the top of your Swift file:
import Relay
let processor = Relay.recordAndReplay(
isRecordingEnabled: true, // Set to true for your first run to record
urlKeywords: ["api.example.com"],
jsonValueOverrides: ["token": "REDACTED"]
)
Parameters:
isRecordingEnabled
:true
: Capture and store responses during the initial run.false
: Subsequent runs use recorded data, ensuring no live server calls.
urlKeywords
: Filter requests by URL keywords.jsonValueOverrides
: A dictionary of keys and their override values to manipulate responses.
Recording Folder Structure:
recordingRootFolder
: Automatically detected based on the file invokingrecordAndReplay
, with all recordings stored under a__RelayRecords__
folder.recordingFolder
: Defaults to the function name from whichrecordAndReplay
was called, making it easy to identify which tests generated which recordings.
Important Note on Test Environments:
⚠️ Warning: When replaying network requests with Relay in unit tests, disable test parallelization. Relay supports only one replay session at a time. Configure your test suite to run serially by setting the test scheme'sExecution Order
to Sequential in Xcode.
To intercept network requests and modify responses without recording:
Relay.interceptAndModify(
urlKeywords: ["api.example.com"],
jsonValueOverrides: ["token": "REDACTED"]
)
If you're using a custom URLSession
with a custom URLSessionConfiguration
, you have two options to ensure that Relay can intercept the requests:
-
Initialize Relay Before Session Creation:
CallrecordAndReplay
orinterceptAndModify
before creating your customURLSession
. -
Manually Set
protocolClasses
:
If the session is already created, manually setprotocolClasses
to includeRelayURLProtocol
:static let urlSession: URLSession = { let config = URLSessionConfiguration.default config.httpAdditionalHeaders = ["x-key": "key", "x-platform": "ios"] config.protocolClasses = [RelayURLProtocol.self] return URLSession(configuration: config) }()
Relay supports installation via Swift Package Manager.
- In Xcode, select File > Add Packages.
- Enter the repository URL:
https://github.com/imodeveloperlab/Relay.git
- Choose the version you want to install.
- Add the package to your project.