Configuring Endpoints
Simple Example
val endpoint = EndpointConfiguration.Builder("Hello World")
.setDefaultHandler {
MockzillaHttpResponse(
statusCode = HttpStatusCode.OK,
headers = mapOf("test-header" to "test-value"),
body = "{}"
)
}
.setPatternMatcher { uri.endsWith("greeting") }
.build()
let endpoint = EndpointConfigurationBuilder(id: "Hello world")
.setDefaultHandler { _ in
MockzillaHttpResponse(
statusCode: HttpStatusCode.OK,
headers: ["test-header": "test-value"],
body: "{}"
)
}.setSwiftPatternMatcher {
$0.uri.hasSuffix("greeting")
}.build()
final endpoint = EndpointConfig(
name: "Greeting",
endpointMatcher: (request) => request.uri.endsWith("greeting"),
defaultHandler: (request) => const MockzillaHttpResponse(
headers: {"key": "value"},
body: "Hello world",
),
errorHandler: (request) => const MockzillaHttpResponse(statusCode: 500),
);
We can then call this endpoint as follows:
SHELL % curl -v http://localhost:8080/local-mock/greeting
* Trying 127.0.0.1:8080...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET /local-mock/greeting HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.87.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Connection: close
< Content-Length: 12
< Content-Type: text/plain; charset=UTF-8
<
Hello world
* Closing connection 0
(This assumes your app is running on a simulator and accessible on localhost; replace localhost with your device IP if running on device.)
Compile-time Safety
This relies on a simple concept: Use the same set of model classes for deserialisation and for your mocks!
Example:
.setDefaultHandler {
MockzillaHttpResponse(
body = Json.encodeToString(MyDtoResponseClass("my value"))
)
}
It is recommended to use a JSON serialisation library such as freezed or json_serializable that can generate toJson()/fromJson() methods for you.
MockzillaHttpResponse(
body: jsonEncode(
FetchDeparturesResponse(
departures: [
Departure(
arrival: DateTime.now().add(const Duration(minutes: 2)),
destination: "East Didsbury",
tramType: TramType.single,
)
],
),
),
);
(1) - Pattern matchers
The pattern matching block is how Mockzilla maps an incoming network request to a given endpoint.
Given the request data, return true if the given endpoint should map to this endpoint.
Request data is accessible as follows:
EndpointConfiguration.Builder("Hello world")
.setPatternMatcher {
// this: MockzillaHttpRequest
}
EndpointConfigurationBuilder(id: "Hello world")
.setSwiftPatternMatcher {
// $0: MockzillaHttpRequest
}
EndpointConfig(
name: "Hello world",
endpointMatcher: (request) =>
request.method == HttpMethod.get && request.uri.endsWith("/departures"),
/* Handlers */
)
Where MockzillaHttpRequest is defined as follows.
data class MockzillaHttpRequest(
val uri: String,
val headers: Map<String, String>,
val body: String = "",
val method: HttpMethod,
)
(2) - Artificial Latency
The following can be configured globally across all endpoints here.
Network requests generally don't complete instantly. Mockzilla can mimic the latency of a network and can be configured either across all endpoints on the top-level config, or on individual endpoints as follows:
EndpointConfiguration.Builder("Hello world")
.setDelayMillis(100)
EndpointConfigurationBuilder(id: "Hello world")
.setDelayMillis(delay: 100)
EndpointConfig(
name: "Fetch departures",
endpointMatcher: (request) => request.uri.endsWith("/departures"),
defaultHandler: (request) => MockzillaHttpResponse(
body: jsonEncode(const FetchDeparturesResponse(departures: []))),
errorHandler: (request) => const MockzillaHttpResponse(statusCode: 418),
delay: const Duration(milliseconds: 500),
)
By default there is no artificial delay.
(3) - Artificial Errors
Mockzilla supports artificially causing network requests to fail.
EndpointConfiguration.Builder("Hello world")
// Optional error handler, called when endpoint is set to fail
// Defaults to an empty 400 response.
.setErrorHandler {
MockzillaHttpResponse(statusCode = HttpStatusCode.NotFound)
}
.setShouldFail(true)
EndpointConfigurationBuilder(id: "Hello world")
// Optional error handler, called when endpoint is set to fail
// Defaults to an empty 400 response.
.setSwiftErrorHandler { _ in
MockzillaHttpResponse(status: HttpStatusCode.NotFound)
}
.setShouldFail(shouldFail: true)
EndpointConfig(
name: "Fetch departures",
endpointMatcher: (request) => request.uri.endsWith("/departures"),
defaultHandler: (request) => MockzillaHttpResponse(
body: jsonEncode(const FetchDeparturesResponse(departures: []))),
// Optional error handler, called when endpoint is set to fail
// Defaults to an empty 400 response.
errorHandler: (request) => const MockzillaHttpResponse(statusCode: 400),
shouldFail: true,
)
The default is for requests to succeed.
Note
Controlling artificial latency in code is time consuming and inflexible. We recommend using the Mockzilla Desktop app or Embedded Mobile Ui to do this on the fly.
Mock Request Lifecycle
When calling the Mockzilla server from your app's code the following happens:
sequenceDiagram
participant A as Client App
participant S as Mockzilla Server
A->>S: Network request
S->>S: Lookup Endpoint based on pattern matchers (1)
S->>S: Delay as long as appropriate (2)
S->>S: Decide whether to simulate a failure (3)
alt Call should succeed
S->>S: Check for property overrides from desktop app / embedded UI (4)
alt All properties overridden
S->>A: Return response using overridden values only (defaultHandler skipped)
else Partial override
S->>S: Call `defaultHandler`
S->>A: Return response, overridden properties take priority over defaultHandler's
else No overrides
S->>A: Return response by calling block defined by `setDefaultHandler`
end
else Call should fail
S->>A: Return response by calling block defined by `setErrorHandler`
end