Crate serde_esri

source ·
Expand description


Esri JSON parsing library.

This crate provides representations of Esri JSON objects with serde::Deserialize and serde::Serialize trait implementations.

serde_esri has additional features:

  • geo implements From for the Esri JSON objects.
  • geoarrow provides compatibility with arrow and geoarrow by implementing geoarrow geometry traits as well as providing a utility function featureset_to_geoarrow() which converts a FeatureSet to an arrow GeoTable.
  • places-client provides an API client for the Places Service REST API.

§Example usage:

This example reads a few features from a feature service and returns a FeatureSet struct. It illustrates the use of the geo and geoarrow features.

geo = "0.28.0"
geoarrow = "0.2.0"
reqwest = { version = "0.12.3", features = ["blocking"] }
serde_esri = { version = "0.2.0", features = ["geo", "geoarrow"] }
serde_json = "1.0.115"
use geo::{GeodesicArea, Polygon};
use serde_esri::arrow_compat::featureset_to_geoarrow;
use serde_esri::features::FeatureSet;
use std::io::Read;

fn main() {
    let flayer_url = "*&returnGeometry=true&resultRecordCount=5&f=json";
    let mut res = reqwest::blocking::get(flayer_url).unwrap();
    let mut body = String::new();

    // Read the request into a String
    res.read_to_string(&mut body).unwrap();

    // Parse into a 2D FeatureSet
    let fset: FeatureSet<2> = serde_json::from_str(&body).unwrap();

    // Utilize the `geo` feature by converting to Polygon
    // and calculate geodesic area
    // iterate through the features
    let area = fset
        .map(|feat| {
            // convert to a geo_types::Polygon
            let poly = Polygon::from(feat.geometry.unwrap().as_polygon().unwrap());
            // calculate geodesic area

    // print areas
    println!("{:?}", area);

    // convert to a geoarrow GeoTable
    println!("{:?}", featureset_to_geoarrow(fset).unwrap());

§Supported Esri JSON objects:


Esri Geometries Objects are encoded by the following structs:

  • EsriPoint
  • EsriMultiPoint<N>
  • EsriPolyline<N>
  • EsriPolygon<N>
  • EsriEnvelope

They are encapsulated by the EsriGeometry enum:

enum EsriGeometry<const N: usize> {

The parameter N is used to specify the dimension of the geometries. Use <2> for 2 dimensional data, <3> for Z values and <4> when M and Z are present.


An Esri JSON FeatureSet is what is most commonly returned from a Feature Service. It is comprised of a number of optional fields and most importantly, a vector of Features.

Features are a struct with a geometry and an attributes field. The geometry must be one of the possible geometry types and attributes can be an key-value pair.

struct Feature<const N: usize> {
    geometry: Option<EsriGeometry<N>>,
    attributes: Option<Map<String, Value>>,

FeatureSets are defined as

pub struct FeatureSet<const N: usize> {
    // ... other optional fields 
    features: Vec<Feature<N>>,
    geometryType: Option<String>,
    spatialReference: SpatialReference,

§Spatial References

Esri Spatial Reference Objects are represented by the SpatialReference struct. Note that while all fields are optional, one should always be provided.

struct SpatialReference {
    wkid: Option<u32>,
    latest_wkid: Option<u32>,
    vcs_wkid: Option<u32>,
    latest_vcs_wkid: Option<u32>,
    wkt: Option<String>,

§Places Service API Client

Activate the PlaceAPI client in your Cargo.toml

serde_esri = { version = "0.3.0", features = ["places-client"] }
fn main() {

    let client = PlacesClient::new(

    // Use the query within extent query builder to create query parameters
    let params = WithinExtentQueryParamsBuilder::default()

    // Call the within_extent method with the query parameters
    let res = client.within_extent(params).unwrap();

    // use the automatic pagination for the iterator method
        .for_each(|r| println!("{:?}", r.unwrap().name));