ArcREST
Ruby Gem wrapper around the ArcGIS REST API
Requirements
Ruby >= 2.4
Current Limitations
API FeatureServer query capabilities only at present.
Installation
Add this line to your application's Gemfile:
$ gem 'arcrest'
And then execute:
$ bundle
Or install it yourself as:
$ gem install arcrest
Usage
The API defines a resource heirarchy which includes a Catalog of Services (MapServer or FeatureServer). Services have one or more Layers and Layers have Features, which may be queried in various ways, including by spatial coordinates.
require 'arcrest'
catalog = ArcREST::Catalog.new 'https://sampleserver6.arcgisonline.com/arcgis/rest/services'
puts catalog.services
#=> {"name"=>"911CallsHotspot", "type"=>"GPServer"}
#=> {"name"=>"911CallsHotspot", "type"=>"MapServer"}
#=> {"name"=>"Census", "type"=>"MapServer"}
...
puts catalog.folders
#=> AGP
#=> Elevation
#=> Energy
...
It is also possible to pass a Referer (or any other) header which will be added to all HTTP requests:
catalog = ArcREST::Catalog.new('https://gojdippmaps.azurewebsites.net/proxy.ashx?https://maps.gov.je/arcgis/rest/services', headers: {referer: 'https://www.gov.je//citizen/Planning/Pages/HistoricEnvironmentDetail.aspx'})
A Service (FeatureServer) is instantiated like this:
service = ArcREST::Service.new 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/EmergencyFacilities/FeatureServer'
puts service.layers
#=> {"id"=>0, "name"=>"Emergency Facilities", "parentLayerId"=>-1, "defaultVisibility"=>true, "subLayerIds"=>nil, "minScale"=>150000, "maxScale"=>0, "type"=>"Feature Layer", "geometryType"=>"esriGeometryPoint"}
layer = ArcREST::Layer.new "#{service.url}/0"
puts layer.name
#=> Emergency Facilities
puts layer.type
#=> Feature Layer
puts layer.max_record_count
#=> 1000 # maximum number of features that can be queried, see below
puts layer.count
#=> 16 # count of the layer's features
puts layer.object_ids.inspect
#=> [29489, 29503, 29490, 29491, 29492, 29493, 29494, 29495, 29496, 29497, 29498, 29499, 29500, 29501, 29502, 29504]
puts layer.fields
#=> {"name"=>"objectid", "type"=>"esriFieldTypeOID", "alias"=>"OBJECTID", "domain"=>nil, "editable"=>false, "nullable"=>false, "defaultValue"=>nil, "modelName"=>"System-maintained ObjectID"}
#=> {"name"=>"facilityid", "type"=>"esriFieldTypeString", "alias"=>"Emergency Facility ID", "domain"=>nil, "editable"=>true, "nullable"=>true, "length"=>20, "defaultValue"=>nil, "modelName"=>"FACILITYID"},
...
Catalog, Service and Layer have a json
method which returns information from the relevant server as a Hash. In addition to the example methods above this can be parsed in the usual way - e.g:
puts layer.json.keys.inspect
#=> ["currentVersion", "id", "name", "type", "parentLayer", "defaultVisibility", ...
Once you have a Layer object, you can perform queries on it. The documention shows the possibilities. Here is a very simple example:
The query
method returns the whole server response as a Hash:
puts layer.query(where: '1=0').inspect
#=> {"objectIdFieldName"=>"objectid", "globalIdFieldName"=>"globalid", "geometryType"=>"esriGeometryPoint", "spatialReference"=>{"wkid"=>4326, "latestWkid"=>4326}, "features"=>[]}
If you just want the features, use the features
method:
puts features.count
#=> 16
puts features[1]
#=> {"attributes"=>{"objectid"=>29503, "facilityid"=>"K2032", "facname"=>"Redlands Mall", "factype"=>3, ...
features = layer.features(where: "factype=3", returnGeometry: false)
puts features.size
#=> 7
puts features.first['attributes']
#=> {"objectid"=>29503, "facilityid"=>"K2032", "facname"=>"Redlands Mall", "factype"=>3, "organiz"=>"City of Redlands", ...
query
and features
take an options hash of API call params. Invalid key values raise an error. Valid params for the server can be listed like this:
puts layer.valid_opts.inspect
#=> ["dbVersion", "distance", "geometry", "geometryPrecision", ... , "where"]
or by consulting the docs. One default is set: outFields: '*'
- which requests data for all fields.
The :where
key is used with any valid SQL to query the layer fields. The default is '1=1' which returns all records (up to the layer.max_record_count
value, usually 1,000). An error is raised if the server gives a 400 error of this form:
{
"error": {
"code": 400,
"message": "Unable to complete operation.",
"details": [
"Unable to perform query operation.",
"Invalid query"
]
}
}
Specification & Tests
Full specification documentation is available by running the test suite thus:
$ bundle exec rake spec
Contributing
Bug reports and pull requests are welcome on GitHub at https://gitlab.com/matzfan/arcrest
License
The gem is available as open source under the terms of the MIT License.