ArcGIS Integration Guide
How to get AXIOM Exchange asset polygons (or lines, or points) onto an ArcGIS map, in either direction the ArcGIS ecosystem expects data.
1. ArcGIS JS API — GeoJSONLayer (recommended)
The ArcGIS JS API's GeoJSONLayer
class consumes a GeoJSON FeatureCollection URL directly — no
transformation needed. Point it straight at any AXIOM Exchange geo
endpoint:
require(["esri/Map", "esri/views/MapView", "esri/layers/GeoJSONLayer"], (Map, MapView, GeoJSONLayer) => {
// Every asset of a given type, anywhere:
const solarFarms = new GeoJSONLayer({
url: "https://your-axiom-host/api/v1/assets?asset_type=solar_farm&format=geojson",
// Note: GeoJSONLayer expects a static FeatureCollection response.
// /assets returns a plain list — use /geo/bbox or /geo/query for a
// ready-made FeatureCollection instead (see below), or a small proxy
// route that wraps /assets in a FeatureCollection envelope.
});
// Everything currently in the map viewport — refresh on extent change:
function viewportLayer(view) {
const e = view.extent;
const url = `https://your-axiom-host/api/v1/geo/bbox` +
`?min_lon=${e.xmin}&min_lat=${e.ymin}&max_lon=${e.xmax}&max_lat=${e.ymax}`;
return new GeoJSONLayer({ url });
}
const map = new Map({ basemap: "topo-vector" });
const view = new MapView({ container: "viewDiv", map, center: [-97.74, 30.27], zoom: 9 });
let currentLayer = viewportLayer(view);
map.add(currentLayer);
view.watch("stationary", (isStationary) => {
if (!isStationary) return;
map.remove(currentLayer);
currentLayer = viewportLayer(view);
map.add(currentLayer);
});
});
Because /geo/bbox, /geo/query, and /geo/query/radius all return a
proper FeatureCollection (not a bare list), those three are the
endpoints to point a GeoJSONLayer at directly. /assets and
/assets/{id}/geometry return a plain list and a single Feature
respectively — fine for fetch()-and-render workflows, but wrap them in
a FeatureCollection (or call /geo/bbox with a huge extent) if you
need a single GeoJSONLayer URL.
Include auth in the layer's custom request handling, since
GeoJSONLayer doesn't attach headers itself — either put a short-lived
token in the URL via a signed-URL proxy, or use esriConfig.request.interceptors:
import esriConfig from "@arcgis/core/config";
esriConfig.request.interceptors.push({
urls: "https://your-axiom-host/api/v1",
headers: { "X-API-Key": "axiom-local-dev-key" },
});
2. Drawing a polygon in ArcGIS and sending it to AXIOM
The reverse direction: a user sketches an area of interest in the
ArcGIS JS API's Sketch widget, and you want every AXIOM asset inside
it.
require(["esri/widgets/Sketch", "esri/layers/GraphicsLayer"], (Sketch, GraphicsLayer) => {
const sketchLayer = new GraphicsLayer();
map.add(sketchLayer);
const sketch = new Sketch({ layer: sketchLayer, view, creationMode: "update" });
view.ui.add(sketch, "top-right");
sketch.on("create", async (event) => {
if (event.state !== "complete") return;
const geometry = event.graphic.geometry; // Esri Polygon geometry
const geojsonPolygon = arcgisPolygonToGeoJSON(geometry); // see helper below
const response = await fetch("https://your-axiom-host/api/v1/geo/query", {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": "axiom-local-dev-key" },
body: JSON.stringify({ geometry: geojsonPolygon }),
});
const featureCollection = await response.json();
// featureCollection.features now holds every intersecting AXIOM asset
});
});
// Esri geometry -> GeoJSON geometry (rings are already lon/lat like GeoJSON;
// this just reshapes the object). For anything beyond simple polygons,
// use @arcgis/core/geometry/support/webMercatorUtils + a proper GeoJSON
// conversion library (e.g. @terraformer/arcgis) instead of hand-rolling it.
function arcgisPolygonToGeoJSON(polygon) {
return { type: "Polygon", coordinates: polygon.rings };
}
3. Esri JSON / ArcGIS REST-style clients
Older ArcGIS Runtime SDKs (or code written against the ArcGIS REST API's
FeatureSet format) expect Esri JSON rather than GeoJSON. Every geo
endpoint in AXIOM Exchange supports ?format=esri for exactly this:
GET /api/v1/geo/bbox?min_lon=-98&min_lat=30&max_lon=-97.4&max_lat=30.6&format=esri
{
"geometryType": "esriGeometryPolygon",
"spatialReference": {"wkid": 4326},
"features": [
{
"geometry": {"rings": [[...]], "spatialReference": {"wkid": 4326}},
"attributes": {"id": "...", "name": "...", "asset_type": "solar_farm", "...": "..."}
}
]
}
This matches the shape returned by a real ArcGIS Feature Service query
(.../FeatureServer/0/query?f=json), so code already written against an
Esri feature service can largely be pointed at AXIOM with just a URL
change.
4. Publishing AXIOM data into ArcGIS Online / Enterprise
To get an asset layer into ArcGIS Online as a proper hosted feature layer (rather than calling AXIOM live from a web map):
GET /api/v1/geo/bbox?...&format=geojson(or/geo/querywith a large boundary) to pull the full dataset for an organization/asset type.- Upload the resulting
FeatureCollectionas a GeoJSON item in ArcGIS Online (Content → Add Item → From your computer), or use the ArcGIS REST API'saddItem+publishoperations to script it. - For data that needs to stay live, prefer the direct
GeoJSONLayerapproach in section 1 instead — publishing takes a snapshot.
5. Coordinate system notes
- Storage and every API response are SRID 4326 (WGS84) —
longitude first, then latitude, matching both GeoJSON's
[lon, lat]ordering and the ArcGIS JS API's defaultspatialReference: {wkid: 4326}. - If your ArcGIS deployment works in Web Mercator (
wkid: 102100/3857) internally, the JS API reprojects on the fly when it knows the source is 4326 — no server-side reprojection is needed for the common case. If you need geometry pre-projected to a different SRID for a specific client, add a?srid=parameter to the geometry endpoints and reproject with PostGIS'sST_Transformingeo_service.pybefore serializing (not implemented in the base scaffold — this is a natural first extension point).