E2 on iOS
iOS apps call the E2 hosted REST endpoints with async/await and render the results as MapKit annotations, polylines, and stats.
Documentation navigation
Start with E2
SDK guides
CLI guides
MCP guides
Applications
Framework quickstarts
How E2 fits
E2 is a plain HTTPS API, so it needs no iOS framework. Search returns GeoJSON that converts to MKPointAnnotation objects, routes become MKPolyline, and compute results drive your UI. MapKit renders all of it.
Setup
E2Client.swift
struct E2Client {
// Configure the base URL for your deployment
var baseURL = URL(string: "https://api.e2.example")!
var session = URLSession.shared
func get(_ path: String, query: [String: String]) async throws -> Data {
var components = URLComponents(url: baseURL.appendingPathComponent(path),
resolvingAgainstBaseURL: false)!
components.queryItems = query.map { URLQueryItem(name: $0.key, value: $0.value) }
let (data, _) = try await session.data(from: components.url!)
return data
}
}Search
SearchViewModel.swift
struct FeatureCollection: Decodable {
let features: [GeoFeature]
}
struct GeoFeature: Decodable {
let geometry: Geometry
let properties: [String: String?]?
}
struct Geometry: Decodable {
let coordinates: [Double]
}
let data = try await client.get("search", query: [
"feature": "restaurant", "area": "Manhattan", "limit": "500",
])
let places = try JSONDecoder().decode(FeatureCollection.self, from: data)
let annotations = places.features.map { feature -> MKPointAnnotation in
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2D(
latitude: feature.geometry.coordinates[1],
longitude: feature.geometry.coordinates[0],
)
annotation.title = feature.properties?["name"] ?? nil ?? "Restaurant"
return annotation
}
mapView.addAnnotations(annotations)Routing
RoutingViewModel.swift
struct RouteRequest: Encodable {
let locations: [[String: Double]]
let mode: String
}
struct RouteResponse: Decodable {
let geometry: RouteGeometry
}
struct RouteGeometry: Decodable {
let coordinates: [[Double]]
}
var request = URLRequest(url: baseURL.appendingPathComponent("route"))
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONEncoder().encode(RouteRequest(
locations: [["lat": 40.74, "lon": -73.99], ["lat": 40.71, "lon": -74.01]],
mode: "walking",
))
let (data, _) = try await session.data(for: request)
let route = try JSONDecoder().decode(RouteResponse.self, from: data)
let coords = route.geometry.coordinates.map {
CLLocationCoordinate2D(latitude: $0[1], longitude: $0[0])
}
mapView.addOverlay(MKPolyline(coordinates: coords, count: coords.count))Compute
ComputeViewModel.swift
struct CountResponse: Decodable {
let count: Int
}
let data = try await client.get("compute/count", query: [
"feature": "restaurant", "region": "Manhattan",
"near": "park", "distance": "500",
])
let nearParks = try JSONDecoder().decode(CountResponse.self, from: data)
statusText = "\(nearParks.count) restaurants within 500 m of a park"Notes
The base URL is configurable — point it at the E2 hosted platform or your own deployment. Implement
rendererFor to style the route overlay, and store API keys in the keychain or an xcconfig file that stays out of source control.