WFS — Web Feature Service
The WFS (Web Feature Service) allows you to retrieve raw geographic features from GeoServer layers. Use WFS to download features as GeoJSON, filter by spatial or attribute criteria, and integrate feature data into your applications.
All requests go to: https://graph.quarticle.ro/graph/layers/wfs/
Authentication: Add the Authorization: YOUR_API_KEY header to all requests.
GetFeature
Retrieve geographic features from a WFS layer.
Required Parameters
| Parameter | Description | Example |
|---|---|---|
service | WFS | WFS |
version | WFS version | 2.0.0 |
request | GetFeature | GetFeature |
typeNames | Layer name(s) | GRAPHRASTER:light_pollution |
Optional Parameters
Filtering
| Parameter | Description | Example |
|---|---|---|
featureID | Return only features with specific ID | namespace:layername.id |
bbox | Spatial filter: minx,miny,maxx,maxy,SRS | 2554219.59,5763351.78,2554220.89,5763352.09,EPSG:3857 |
cql_filter | GeoServer CQL filter expression | population > 1000000 |
filter | OGC Filter XML | (see examples below) |
Output Control
| Parameter | Description | Example |
|---|---|---|
outputFormat | Response format | application/json (GeoJSON) |
srsName | Output coordinate system | EPSG:4326 |
propertyName | Comma-separated properties to return | name,population,area |
Pagination
| Parameter | Description | Example |
|---|---|---|
count (WFS 2.0.0) | Max features to return | 100 |
maxFeatures (WFS 1.1.0) | Max features to return | 100 |
startIndex | Pagination offset | 200 |
Sorting
| Parameter | Description | Example |
|---|---|---|
sortBy | Sort results by field | population D (descending) or population A (ascending) |
Examples
Basic Feature Query
- cURL
- JavaScript
- Python
curl -X GET "https://graph.quarticle.ro/graph/layers/wfs/GetFeature" \
-H "Authorization: YOUR_API_KEY" \
--data-urlencode "service=WFS" \
--data-urlencode "version=2.0.0" \
--data-urlencode "request=GetFeature" \
--data-urlencode "typeNames=GRAPHRASTER:light_pollution" \
--data-urlencode "outputFormat=application/json"
const apiKey = process.env.QARTA_API_KEY;
const params = new URLSearchParams({
service: 'WFS',
version: '2.0.0',
request: 'GetFeature',
typeNames: 'GRAPHRASTER:light_pollution',
outputFormat: 'application/json'
});
fetch(`https://graph.quarticle.ro/graph/layers/wfs/GetFeature?${params}`, {
headers: { 'Authorization': `${apiKey}` }
})
.then(r => r.json())
.then(geojson => {
console.log(`Retrieved ${geojson.features.length} features`);
geojson.features.forEach(f => {
console.log(f.properties);
});
});
import requests
import json
api_key = os.getenv('QARTA_API_KEY')
response = requests.get(
'https://graph.quarticle.ro/graph/layers/wfs/GetFeature',
params={
'service': 'WFS',
'version': '2.0.0',
'request': 'GetFeature',
'typeNames': 'GRAPHRASTER:light_pollution',
'outputFormat': 'application/json'
},
headers={'Authorization': f'{api_key}'}
)
geojson = response.json()
print(f'Retrieved {len(geojson["features"])} features')
Spatial Filter (BBox)
Query features within a bounding box:
- cURL
curl -X GET "https://graph.quarticle.ro/graph/layers/wfs/GetFeature" \
-H "Authorization: YOUR_API_KEY" \
--data-urlencode "service=WFS" \
--data-urlencode "version=2.0.0" \
--data-urlencode "request=GetFeature" \
--data-urlencode "typeNames=GRAPHRASTER:cities" \
--data-urlencode "bbox=-74.1,40.6,-73.9,40.8,EPSG:4326" \
--data-urlencode "outputFormat=application/json"
CQL Filter (Attribute Query)
Filter features by attributes using CQL (Common Query Language):
- Simple Filter
- Combined Conditions
- Spatial CQL
- cURL Example
# Get cities with population > 1 million
cql_filter=population > 1000000
# Urban areas with population > 500k
cql_filter=type = 'urban' AND population > 500000
# Features within a specific point (buffer)
cql_filter=DWITHIN(geom, POINT(-74.0060 40.7128), 1000, meters)
# Features containing a point
cql_filter=CONTAINS(geom, POINT(-74.0060 40.7128))
# Features intersecting a polygon
cql_filter=INTERSECTS(geom, POLYGON((-74.1 40.6, -73.9 40.6, -73.9 40.8, -74.1 40.8, -74.1 40.6)))
curl -X GET "https://graph.quarticle.ro/graph/layers/wfs/GetFeature" \
-H "Authorization: YOUR_API_KEY" \
--data-urlencode "service=WFS" \
--data-urlencode "version=2.0.0" \
--data-urlencode "request=GetFeature" \
--data-urlencode "typeNames=GRAPHRASTER:cities" \
--data-urlencode "cql_filter=population > 1000000 AND country = 'USA'" \
--data-urlencode "outputFormat=application/json"
Property Selection & Pagination
Retrieve specific properties and paginate through large result sets:
- cURL
- JavaScript
curl -X GET "https://graph.quarticle.ro/graph/layers/wfs/GetFeature" \
-H "Authorization: YOUR_API_KEY" \
--data-urlencode "service=WFS" \
--data-urlencode "version=2.0.0" \
--data-urlencode "request=GetFeature" \
--data-urlencode "typeNames=GRAPHRASTER:cities" \
--data-urlencode "propertyName=name,population,country" \
--data-urlencode "count=100" \
--data-urlencode "startIndex=0" \
--data-urlencode "sortBy=population D" \
--data-urlencode "outputFormat=application/json"
async function getAllFeatures(typeName) {
const apiKey = process.env.QARTA_API_KEY;
const pageSize = 100;
let allFeatures = [];
let page = 0;
while (true) {
const params = new URLSearchParams({
service: 'WFS',
version: '2.0.0',
request: 'GetFeature',
typeNames: typeName,
count: pageSize.toString(),
startIndex: (page * pageSize).toString(),
outputFormat: 'application/json'
});
const response = await fetch(
`https://graph.quarticle.ro/graph/layers/wfs/GetFeature?${params}`,
{ headers: { 'Authorization': `${apiKey}` } }
);
const geojson = await response.json();
allFeatures.push(...geojson.features);
// Stop if fewer features than page size
if (geojson.features.length < pageSize) break;
page++;
}
return allFeatures;
}
Output Formats
WFS can return features in multiple formats:
| Format | MIME Type | Use Case |
|---|---|---|
| GeoJSON | application/json | Recommended for web apps |
| GML 3 | text/xml or application/gml+xml | OGC standard, GIS desktop apps |
| CSV | text/csv | Data analysis, Excel export |
Example:
outputFormat=application/json # GeoJSON
outputFormat=application/gml+xml # GML
outputFormat=text/csv # CSV
Response Structure (GeoJSON)
A typical WFS response in GeoJSON format:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"id": "cities.1",
"geometry": {
"type": "Point",
"coordinates": [-74.0060, 40.7128]
},
"properties": {
"name": "New York",
"population": 8335897,
"country": "USA"
}
},
{
"type": "Feature",
"id": "cities.2",
"geometry": {
"type": "Point",
"coordinates": [-87.6298, 41.8857]
},
"properties": {
"name": "Chicago",
"population": 2693976,
"country": "USA"
}
}
]
}
Error Handling
If a GetFeature request fails, the error is returned as XML by default:
<?xml version="1.0" encoding="UTF-8"?>
<ExceptionReport version="2.0.0">
<Exception exceptionCode="InvalidParameterValue">
<ExceptionText>
Unknown typename: invalid_layer
</ExceptionText>
</Exception>
</ExceptionReport>
Or as JSON if you add &outputFormat=application/json:
{
"code": "InvalidParameterValue",
"message": "Unknown typename: invalid_layer"
}
Common errors:
- InvalidParameterValue: Wrong
typeNames,srsName, oroutputFormat - NoApplicableCode: CQL filter syntax error or invalid property name
- Unauthorized: API key is missing or invalid
- ServiceException: General GeoServer error (check parameters)
Tips & Best Practices
- Use JSON for web apps:
outputFormat=application/jsonis easiest to parse in JavaScript - Filter early: Use
bboxorcql_filterto reduce payload instead of downloading all features - Select properties: Only request the fields you need with
propertyName=field1,field2 - Paginate large sets: Use
countandstartIndexto avoid timeouts - Coordinate system: Data in EPSG:4326 (lat/lon) is standard; use
srsNameto transform if needed - Cache results: For frequently-accessed datasets, consider caching feature data locally
Next Steps
- GeoServer Overview
- WMS Guide — Render map tiles
- Feature Querying Use Case — Real-world feature query examples