Documentation
¶
Overview ¶
Package arcgis is a small, dependency-free client for querying ArcGIS Feature Services over their REST API.
It offers two interchangeable styles: a struct-based API (QueryParams passed to Client.Query) and a fluent builder (Client.Layer → LayerClient.Query). Pagination, counts, and object-ID-only queries are first-class.
client := arcgis.NewClient(baseURL)
features, err := client.Layer(7).Query().
Where("STAGE = 4").
Fields("NAME", "STAGE").
All(ctx)
Example (CountOnly) ¶
package main
import (
"context"
"fmt"
"log"
arcgis "github.com/richardwooding/go-arcgis"
)
// baseURL is an example FeatureServer root. Replace it with the service you
// are querying.
const baseURL = "https://example.gov/arcgis/rest/services/Theme/Service/FeatureServer"
func main() {
client := arcgis.NewClient(baseURL)
ctx := context.Background()
// Just get a count — no feature data transferred
count, err := client.Layer(1).
Query().
Where("SUBURB = 'Woodstock'").
Count(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Matching records: %d\n", count)
}
Output:
Example (FluentStyle) ¶
package main
import (
"context"
"fmt"
"log"
arcgis "github.com/richardwooding/go-arcgis"
)
// baseURL is an example FeatureServer root. Replace it with the service you
// are querying.
const baseURL = "https://example.gov/arcgis/rest/services/Theme/Service/FeatureServer"
func main() {
client := arcgis.NewClient(baseURL)
ctx := context.Background()
// Fluent style — readable, chainable
features, err := client.Layer(111).
Query().
Where("STAGE = 4").
Fields("BLOCK_NAME", "STAGE").
WithinEnvelope(18.4, -34.0, 18.6, -33.8).
PageSize(100).
All(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println(len(features))
}
Output:
Example (InspectParams) ¶
package main
import (
"fmt"
arcgis "github.com/richardwooding/go-arcgis"
)
// baseURL is an example FeatureServer root. Replace it with the service you
// are querying.
const baseURL = "https://example.gov/arcgis/rest/services/Theme/Service/FeatureServer"
func main() {
client := arcgis.NewClient(baseURL)
// QueryParams is just a struct — inspect, log, or marshal it
p := client.Layer(64).
Query().
Where("YEAR = 2021").
WithoutGeometry().
Params() // returns QueryParams without executing
fmt.Printf("Layer: %d, Where: %s\n", p.LayerID, p.Where)
}
Output: Layer: 64, Where: YEAR = 2021
Example (NamedQuery) ¶
package main
import (
"context"
"fmt"
"log"
arcgis "github.com/richardwooding/go-arcgis"
)
// baseURL is an example FeatureServer root. Replace it with the service you
// are querying.
const baseURL = "https://example.gov/arcgis/rest/services/Theme/Service/FeatureServer"
// loadSheddingForStage is the kind of named, pre-built query an application
// or companion package might expose.
func loadSheddingForStage(stage int) arcgis.QueryParams {
return arcgis.QueryParams{
LayerID: 111,
Where: fmt.Sprintf("STAGE = %d", stage),
Fields: []string{"BLOCK_NAME", "STAGE"},
}
}
func main() {
client := arcgis.NewClient(baseURL)
ctx := context.Background()
// Named query — pre-built params, optionally extended
features, err := client.Layer(111).
Query().
From(loadSheddingForStage(4)).
WithinEnvelope(18.4, -34.0, 18.6, -33.8). // further refined
All(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println(len(features))
}
Output:
Example (PaginatedAll) ¶
package main
import (
"context"
"fmt"
"log"
arcgis "github.com/richardwooding/go-arcgis"
)
// baseURL is an example FeatureServer root. Replace it with the service you
// are querying.
const baseURL = "https://example.gov/arcgis/rest/services/Theme/Service/FeatureServer"
func main() {
client := arcgis.NewClient(baseURL)
ctx := context.Background()
// QueryAll handles pagination transparently
all, err := client.QueryAll(ctx, arcgis.QueryParams{LayerID: 229})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Total records: %d\n", len(all))
}
Output:
Example (StructStyle) ¶
package main
import (
"context"
"fmt"
"log"
arcgis "github.com/richardwooding/go-arcgis"
)
// baseURL is an example FeatureServer root. Replace it with the service you
// are querying.
const baseURL = "https://example.gov/arcgis/rest/services/Theme/Service/FeatureServer"
func main() {
client := arcgis.NewClient(baseURL)
ctx := context.Background()
// Struct-style — explicit, composable, serializable
features, err := client.Query(ctx, arcgis.QueryParams{
LayerID: 111,
Where: "STAGE = 4",
Fields: []string{"BLOCK_NAME", "STAGE"},
PageSize: 100,
})
if err != nil {
log.Fatal(err)
}
fmt.Println(len(features.Features))
}
Output:
Index ¶
- type APIError
- type Client
- func (c *Client) Layer(id int) *LayerClient
- func (c *Client) LayerInfo(ctx context.Context, layerID int) (*LayerInfo, error)
- func (c *Client) Query(ctx context.Context, p QueryParams) (*FeatureSet, error)
- func (c *Client) QueryAll(ctx context.Context, p QueryParams) ([]Feature, error)
- func (c *Client) QueryCount(ctx context.Context, p QueryParams) (int, error)
- func (c *Client) QueryIDs(ctx context.Context, p QueryParams) ([]int64, error)
- func (c *Client) ServiceInfo(ctx context.Context) (*ServiceInfo, error)
- type ClientOption
- type Envelope
- type Feature
- type FeatureSet
- type Field
- type GeometryType
- type LayerClient
- type LayerInfo
- type LayerRef
- type OutputFormat
- type Point
- type Polygon
- type QueryBuilder
- func (q *QueryBuilder) All(ctx context.Context) ([]Feature, error)
- func (q *QueryBuilder) Count(ctx context.Context) (int, error)
- func (q *QueryBuilder) DistinctValues() *QueryBuilder
- func (q *QueryBuilder) Fields(fields ...string) *QueryBuilder
- func (q *QueryBuilder) First(ctx context.Context) (*FeatureSet, error)
- func (q *QueryBuilder) Format(f OutputFormat) *QueryBuilder
- func (q *QueryBuilder) From(base QueryParams) *QueryBuilder
- func (q *QueryBuilder) GroupBy(fields ...string) *QueryBuilder
- func (q *QueryBuilder) IDs(ctx context.Context) ([]int64, error)
- func (q *QueryBuilder) InSR(wkid int) *QueryBuilder
- func (q *QueryBuilder) IntersectsPoint(x, y float64) *QueryBuilder
- func (q *QueryBuilder) Offset(n int) *QueryBuilder
- func (q *QueryBuilder) OrderBy(fields ...string) *QueryBuilder
- func (q *QueryBuilder) PageSize(n int) *QueryBuilder
- func (q *QueryBuilder) Params() QueryParams
- func (q *QueryBuilder) SpatialRel(rel SpatialRel) *QueryBuilder
- func (q *QueryBuilder) Where(clause string) *QueryBuilder
- func (q *QueryBuilder) WithinEnvelope(minX, minY, maxX, maxY float64) *QueryBuilder
- func (q *QueryBuilder) WithinPolygon(rings [][][]float64) *QueryBuilder
- func (q *QueryBuilder) WithoutGeometry() *QueryBuilder
- type QueryParams
- type ServiceInfo
- type SpatialRel
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type APIError ¶
type APIError struct {
Code int `json:"code"`
Message string `json:"message"`
Details []string `json:"details,omitempty"`
}
APIError is an error returned by an ArcGIS service. ArcGIS commonly reports failures with an HTTP 200 status and an error envelope in the body, so this is surfaced even on otherwise-successful responses.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the main entry point for interacting with an ArcGIS Feature Service.
func NewClient ¶
func NewClient(baseURL string, opts ...ClientOption) *Client
NewClient creates a new ArcGIS Feature Service client. baseURL should be the root of the FeatureServer, e.g.:
https://example.gov/arcgis/rest/services/Theme/Service/FeatureServer
func (*Client) Layer ¶
func (c *Client) Layer(id int) *LayerClient
Layer returns a LayerClient scoped to a specific layer ID.
func (*Client) Query ¶
func (c *Client) Query(ctx context.Context, p QueryParams) (*FeatureSet, error)
Query executes a single-page query and returns the raw FeatureSet.
func (*Client) QueryCount ¶
QueryCount returns the count of features matching the query.
func (*Client) ServiceInfo ¶
func (c *Client) ServiceInfo(ctx context.Context) (*ServiceInfo, error)
ServiceInfo fetches metadata about the feature service.
type ClientOption ¶
type ClientOption func(*Client)
ClientOption configures a Client.
func WithHTTPClient ¶
func WithHTTPClient(hc *http.Client) ClientOption
WithHTTPClient sets a custom HTTP client.
func WithTimeout ¶
func WithTimeout(d time.Duration) ClientOption
WithTimeout sets a request timeout on the default HTTP client. It has no effect when combined with WithHTTPClient.
func WithToken ¶
func WithToken(token string) ClientOption
WithToken sets an ArcGIS authentication token, appended to every request.
type Envelope ¶
Envelope is a bounding-box spatial filter, expressed in the layer's coordinate system (typically WGS84 longitude/latitude).
type Feature ¶
type Feature struct {
Geometry json.RawMessage `json:"geometry"`
Attributes map[string]any `json:"attributes,omitempty"` // Esri JSON
Properties map[string]any `json:"properties,omitempty"` // GeoJSON
}
Feature represents a single ArcGIS feature with geometry and attributes.
The geometry is left as raw JSON because its shape depends on the requested format (Esri JSON vs GeoJSON) and the layer's geometry type. Attributes are populated for Esri JSON responses; Properties for GeoJSON.
type FeatureSet ¶
type FeatureSet struct {
Features []Feature `json:"features"`
ExceededTransferLimit bool `json:"exceededTransferLimit"`
ObjectIDFieldName string `json:"objectIdFieldName,omitempty"`
Fields []Field `json:"fields,omitempty"`
}
FeatureSet is a collection of features returned from a query.
type Field ¶
type Field struct {
Name string `json:"name"`
Type string `json:"type"`
Alias string `json:"alias"`
}
Field describes a single attribute field in a layer.
type GeometryType ¶
type GeometryType string
GeometryType for spatial filter inputs.
const ( GeometryTypeEnvelope GeometryType = "esriGeometryEnvelope" GeometryTypePoint GeometryType = "esriGeometryPoint" GeometryTypePolygon GeometryType = "esriGeometryPolygon" )
Supported geometry types for spatial filter inputs.
type LayerClient ¶
type LayerClient struct {
// contains filtered or unexported fields
}
LayerClient is scoped to a single layer and provides the fluent query entry point.
func (*LayerClient) Info ¶
func (l *LayerClient) Info(ctx context.Context) (*LayerInfo, error)
Info fetches metadata for this layer.
func (*LayerClient) Query ¶
func (l *LayerClient) Query() *QueryBuilder
Query returns a QueryBuilder pre-scoped to this layer.
type LayerInfo ¶
type LayerInfo struct {
ID int `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Description string `json:"description"`
MaxRecordCount int `json:"maxRecordCount"`
Fields []Field `json:"fields"`
GeometryType string `json:"geometryType"`
SupportsStatistics bool `json:"supportsStatistics"`
SupportsPagination bool `json:"supportsPagination"`
}
LayerInfo contains metadata about a feature layer.
type OutputFormat ¶
type OutputFormat string
OutputFormat controls the response format from ArcGIS.
const ( // FormatGeoJSON requests RFC 7946 GeoJSON. Each feature carries its // attributes under "properties". FormatGeoJSON OutputFormat = "geojson" // FormatJSON requests Esri JSON. Each feature carries its attributes // under "attributes". FormatJSON OutputFormat = "json" // FormatPBF requests the Protocol Buffer encoding. This package decodes // JSON responses only; use FormatPBF only with a custom decoder. FormatPBF OutputFormat = "pbf" )
type Polygon ¶ added in v0.2.0
type Polygon struct {
Rings [][][]float64
}
Polygon is a polygon spatial filter, expressed as one or more linear rings of [x, y] coordinates in the layer's coordinate system (typically WGS84 longitude/latitude). Per the Esri convention an exterior ring is clockwise and holes are counter-clockwise, but ArcGIS query filters tolerate either.
type QueryBuilder ¶
type QueryBuilder struct {
// contains filtered or unexported fields
}
QueryBuilder builds a QueryParams using a fluent chainable API.
func (*QueryBuilder) All ¶
func (q *QueryBuilder) All(ctx context.Context) ([]Feature, error)
All fetches all results, handling pagination automatically.
func (*QueryBuilder) Count ¶
func (q *QueryBuilder) Count(ctx context.Context) (int, error)
Count returns only the record count matching the query.
func (*QueryBuilder) DistinctValues ¶ added in v0.1.1
func (q *QueryBuilder) DistinctValues() *QueryBuilder
DistinctValues requests only distinct values for the selected Fields.
func (*QueryBuilder) Fields ¶
func (q *QueryBuilder) Fields(fields ...string) *QueryBuilder
Fields sets the output fields to return.
func (*QueryBuilder) First ¶
func (q *QueryBuilder) First(ctx context.Context) (*FeatureSet, error)
First fetches only the first page of results.
func (*QueryBuilder) Format ¶
func (q *QueryBuilder) Format(f OutputFormat) *QueryBuilder
Format sets the response format.
func (*QueryBuilder) From ¶
func (q *QueryBuilder) From(base QueryParams) *QueryBuilder
From merges a pre-built QueryParams into this builder (useful for named queries). The layer ID set by Layer() is preserved.
func (*QueryBuilder) GroupBy ¶
func (q *QueryBuilder) GroupBy(fields ...string) *QueryBuilder
GroupBy sets the GROUP BY fields (used with statistics queries).
func (*QueryBuilder) IDs ¶
func (q *QueryBuilder) IDs(ctx context.Context) ([]int64, error)
IDs returns only the object IDs matching the query.
func (*QueryBuilder) InSR ¶ added in v0.2.0
func (q *QueryBuilder) InSR(wkid int) *QueryBuilder
InSR sets the spatial reference (well-known ID) of the input filter geometry.
func (*QueryBuilder) IntersectsPoint ¶
func (q *QueryBuilder) IntersectsPoint(x, y float64) *QueryBuilder
IntersectsPoint sets a point spatial filter using the default "intersects" relationship.
func (*QueryBuilder) Offset ¶
func (q *QueryBuilder) Offset(n int) *QueryBuilder
Offset sets the starting record offset for pagination.
func (*QueryBuilder) OrderBy ¶
func (q *QueryBuilder) OrderBy(fields ...string) *QueryBuilder
OrderBy sets the ORDER BY fields.
func (*QueryBuilder) PageSize ¶
func (q *QueryBuilder) PageSize(n int) *QueryBuilder
PageSize sets the number of records per page.
func (*QueryBuilder) Params ¶
func (q *QueryBuilder) Params() QueryParams
Params returns the underlying QueryParams for inspection or reuse.
func (*QueryBuilder) SpatialRel ¶
func (q *QueryBuilder) SpatialRel(rel SpatialRel) *QueryBuilder
SpatialRel overrides the spatial relationship applied to the geometry filter.
func (*QueryBuilder) Where ¶
func (q *QueryBuilder) Where(clause string) *QueryBuilder
Where sets the SQL WHERE clause.
func (*QueryBuilder) WithinEnvelope ¶
func (q *QueryBuilder) WithinEnvelope(minX, minY, maxX, maxY float64) *QueryBuilder
WithinEnvelope sets a bounding-box spatial filter.
func (*QueryBuilder) WithinPolygon ¶ added in v0.2.0
func (q *QueryBuilder) WithinPolygon(rings [][][]float64) *QueryBuilder
WithinPolygon sets a polygon spatial filter from one or more [x, y] rings.
func (*QueryBuilder) WithoutGeometry ¶
func (q *QueryBuilder) WithoutGeometry() *QueryBuilder
WithoutGeometry omits geometry from the response (faster for attribute-only queries).
type QueryParams ¶
type QueryParams struct {
LayerID int
Where string
Fields []string
Envelope *Envelope
Geometry *Point
Polygon *Polygon
GeometryType GeometryType
SpatialRel SpatialRel
// InSR is the well-known ID of the spatial reference the input geometry
// (Envelope/Geometry/Polygon) is expressed in. When zero and a geometry
// filter is set, it defaults to 4326 (WGS84 longitude/latitude) — the SR
// of the coordinates callers normally supply. Without it, ArcGIS assumes
// the geometry is in the layer's native SR, so a WGS84 box silently
// matches nothing against a layer stored in Web Mercator.
InSR int
OrderByFields []string
GroupByFields []string
ResultOffset int
PageSize int
ReturnGeometry *bool // nil = server default (true)
ReturnIDsOnly bool
ReturnCountOnly bool
// ReturnDistinctValues requests only distinct values for the selected
// Fields. Typically combined with Fields (and often OrderByFields) to
// enumerate the values present in one or more columns.
ReturnDistinctValues bool
Format OutputFormat
}
QueryParams defines all parameters for an ArcGIS feature query. It can be used directly (struct-style) or built via QueryBuilder (fluent-style).
The zero value is usable: defaults are applied for an unset Where clause ("1=1"), Format (GeoJSON), and PageSize (1000).
type ServiceInfo ¶
type ServiceInfo struct {
ServiceDescription string `json:"serviceDescription"`
Layers []LayerRef `json:"layers"`
Tables []LayerRef `json:"tables"`
}
ServiceInfo contains metadata about a feature service.
type SpatialRel ¶
type SpatialRel string
SpatialRel defines the spatial relationship for geometry filters.
const ( SpatialRelIntersects SpatialRel = "esriSpatialRelIntersects" SpatialRelContains SpatialRel = "esriSpatialRelContains" SpatialRelWithin SpatialRel = "esriSpatialRelWithin" SpatialRelTouches SpatialRel = "esriSpatialRelTouches" SpatialRelOverlaps SpatialRel = "esriSpatialRelOverlaps" SpatialRelEnvelopeIntersects SpatialRel = "esriSpatialRelEnvelopeIntersects" )
Supported spatial relationships for geometry filters.