Security News
Research
Supply Chain Attack on Rspack npm Packages Injects Cryptojacking Malware
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
featureserver
Advanced tools
An open source implementation of the GeoServices specification
This is meant to be used as a plugin to Express
const express = require('express')
const app = express() // set up a basic express server
const FeatureServer = require('featureserver')
const cache = require('cache')
// We only need one handler because FeatureServer.route is going to do all the work
const handler = (req, res) => {
cache.get(/* some geojson */, (err, data) => {
if (err) res.status(500).json({error: err.message})
else FeatureServer.route(req, res, data)
})
}
// Sets up all of the handled routes to support `GET` and `POST`
const routes = ['/FeatureServer', '/FeatureServer/layers', '/FeatureServer/:layer', '/FeatureServer/:layer/:method']
routes.forEach(route => {
app.route(route)
.get(handler)
.post(handler)
})
Pass in an incoming request object
, an outgoing response object
, a geojson
object, and options
and this function will route and return a geoservices compliant response
query
, info
, and generateRenderer
are supported methods at this time.FeatureServer.route(req, res, data, options)
e.g.
{
type: 'FeatureCollection' // Static
features: Array, // GeoJSON features
statistics: Object, // pass statistics to an outStatistics request to or else they will be calculated from geojson features passed in
metadata: {
name: String, // The name of the layer
description: String, // The description of the layer
extent: Array, // valid extent array e.g. [[180,90],[-180,-90]]
displayField: String, // The display field to be used by a client
geometryType: String // REQUIRED if no features are returned with this object Point || MultiPoint || LineString || MultiLineString || Polygon || MultiPolygon
idField: String, // unique identifier field,
maxRecordCount: Number, // the maximum number of features a provider can return at once
limitExceeded: Boolean, // whether or not the server has limited the features returned
timeInfo: Object // describes the time extent and capabilities of the layer,
transform: Object // describes a quantization transformation
fields: [
{ // Subkeys are optional
name: String,
type: String, // 'Date' || 'Double' || 'Integer' || 'String'
alias: String, // how should clients display this field name,
}
]
},
capabilities: {
quantization: Boolean // True if the provider supports quantization
},
filtersApplied: {
all: Boolean // true if all post processing should be skipped
geometry: Boolean, // true if a geometric filter has already been applied to the data
where: Boolean, // true if a sql-like where filter has already been applied to the data
offset: Boolean // true if the result offset has already been applied to the data,
limit: Boolean // true if the result count has already been limited,
projection: Boolean // true if the result data has already been projected
}
count: Number // pass count if the number of features in a query has been pre-calculated
}
or
{
layers: [
{
type: 'FeatureCollection'
...
},
{
type: 'FeatureCollection'
...
}
]
FeatureServer.query
and FeatureServer.generateRenderer
for more details.Pass in geojson
and options
(a valid geoservices query object), and the function will perform the query and return a valid geoservices query object. The in addition to input statistics: {}
, following is an example of all query options
that can be passed into the query route: '/FeatureServer/:layer/query'
e.g.
const options = {
where: `1=1`,
objectIds: '1,2,3',
geometry: {
xmin: -110, ymin: 30, xmax: -106, ymax: 50,
spatialReference: { wkid: 4326 },
},
geometryType: 'esriGeometryEnvelope',
spatialRel: 'esriSpatialRelContains',
outFields: '*',
returnGeometry: true,
outSR: 102100, // output spatial reference
returnIdsOnly: true,
returnCountOnly: true,
orderByFields: 'Full/Part_COUNT DESC',
groupByFieldsForStatistics: 'Full/Part',
outStatistics: {
statisticType: 'count',
onStatisticField: '<field>',
outStatisticFieldName: 'name'
},
returnDistinctValues: true,
resultOffset: 0,
resultRecordCount: 0,
f: 'pjson'
}
FeatureServer.query(geojson, options)
Generate version 10.21
Geoservices server info
const server = {
description: String // Describes the collection of layers below,
maxRecordCount: Number // the maximum number of features a provider can return at once,
hasStaticData: Boolean // whether or not the server contains any data that is not changing
layers: [{ // A collection of all the layers managed by the server
type: 'FeatureCollection',
metadata: {
name: String, // The name of the layer
description: String // The description of the layer
extent: Array // valid extent array e.g. [[180,90],[-180,-90]]
displayField: String // The display field to be used by a client
idField: String // unique identifier field,
geometryType: String // REQUIRED if no features are returned with this object Point || MultiPoint || LineString || MultiLineString || Polygon || MultiPolygon
maxRecordCount: Number // the maximum number of features a provider can return at once
limitExceeded: Boolean, // whether or not the server has limited the features returned
timeInfo: Object // describes the time extent and capabilities of the layer
}
features: [// If all the metadata provided above is provided features are optional.
{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [125.6, 10.1]
},
properties: {
name: 'Dinagat Islands'
}
}]
}
}]
}
FeatureServer.serverInfo(server)
Generate version 10.21
Geoservices information about a single layer
FeatureServer.layerInfo(geojson, options)
Generate version 10.21
Geoservices information about one or many layers
Can pass a single geojson object or an array of geojson objects
FeatureServer.layers(geojson, options)
Pass in geojson
and options
, and the function will return a valid generateRenderer object. Two classificationDef
classification types are supported, classBreaksDef and uniqueValueDef.
classBreaksDef is used to classify numeric data based on a number of breaks and a statistical method. Features can also be normalized before being classified. uniqueValueDef is used to classify data based on a unique field(s). If classification breaks are not supplied through in statistics
, they will be generated using classificationDef
options. The output is a generateRenderer object.
In addition to class breaks as input statistics: []
, the following is an example of all classBreaksDef options
that can be passed into the generateRenderer route: '/FeatureServer/:layer/generateRenderer'
e.g.
const options = {
*'classificationDef': {
*'type': 'classBreaksDef',
*'classificationField': '<field1>',
*'classificationMethod': 'esriClassifyEqualInterval' | 'esriClassifyNaturalBreaks' | 'esriClassifyQuantile' | 'esriClassifyStandardDeviation',
*'breakCount': 9,
'normalizationType': 'esriNormalizeByField' | 'esriNormalizeByLog' | 'esriNormalizeByPercentOfTotal',
'normalizationField': '<field2>' // mandatory if 'normalizationType' === 'esriNormalizeByField'
'baseSymbol': {
'type': 'esriSMS',
'style': 'esriSMSCircle',
'width': 2
},
'colorRamp': {
'type': 'algorithmic',
'fromColor': [115,76,0,255],
'toColor': [255,25,86,255],
'algorithm': 'esriHSVAlgorithm'
}
},
'where': '<field2> > 39'
}
FeatureServer.generateRender(geojson, options)
*required
Output:
{
type: 'classBreaks',
field: '<field1>',
classificationMethod: 'esriClassifyEqualInterval',
minValue: 0,
classBreakInfos: [
{
classMinValue: 0,
classMaxValue: 5,
label: '0-5',
description: '',
symbol: {
type: 'esriSMS',
style: 'esriSMSCircle',
width: 2,
color: [115, 76, 0]
}
},
{
classMinValue: 6,
classMaxValue: 11,
label: '6-11',
description: '',
symbol: {
type: 'esriSMS',
style: 'esriSMSCircle',
width: 2,
color: [156, 67, 0]
}
},
...
]
}
The following is an example of all uniqueValueDef options
that can be passed into the generateRenderer route: '/FeatureServer/:layer/generateRenderer'
e.g.
const options = {
*'classificationDef': {
*'type': 'uniqueValueDef',
*'uniqueValueFields': ['Genus', '<field2>', '<field3>'],
*'fieldDelimiter': ', '
'baseSymbol': {
'type': 'esriSMS',
'style': 'esriSMSCircle',
'width': 2
},
'colorRamp': {
'type': 'algorithmic',
'fromColor': [115,76,0,255],
'toColor': [255,25,86,255],
'algorithm': 'esriHSVAlgorithm'
}
},
'where': 'latitude > 39'
}
FeatureServer.generateRender(geojson, options)
*required
Output:
{
type: 'uniqueValue',
field1: 'Genus',
field2: '',
field3: '',
fieldDelimiter: ', ',
defaultSymbol: {},
defaultLabel: '',
uniqueValueInfos: [
{
value: 'MAGNOLIA',
count: 5908,
label: 'MAGNOLIA',
description: '',
symbol: {
type: 'esriSMS',
style: 'esriSMSCircle',
width: 2,
color: [115, 76, 0]
}
},
{
value: 'QUERCUS',
count: 12105,
label: 'QUERCUS',
description: '',
symbol: {
type: 'esriSMS',
style: 'esriSMSCircle',
width: 2,
color: [116, 76, 0]
}
},
...
]
[2.11.1] - 04-18-2018
empty
fields arrayreturnGeometry=false
and outSR=<EPSG>
, delete the outSR
param since no geometry will be present to reprojectFAQs
*An open source implementation of the GeoServices specification*
The npm package featureserver receives a total of 143 weekly downloads. As such, featureserver popularity was classified as not popular.
We found that featureserver demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 5 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.
Security News
Sonar’s acquisition of Tidelift highlights a growing industry shift toward sustainable open source funding, addressing maintainer burnout and critical software dependencies.