Skip to main content

Feature Querying with WFS

Scenario: You need to retrieve raw geographic features from a Qarta layer for analysis, export, or downstream processing. You want to filter by location (bounding box) or attributes (CQL filter), and retrieve the data as GeoJSON.

Workflow:

  1. Use DescribeLayer to find the WFS typeNames for a layer
  2. Call GetFeature with filters and output format
  3. Parse GeoJSON and process features in your application
  4. Paginate through large result sets if needed

Step 1: Get Layer Metadata

Use the WMS DescribeLayer operation to find the corresponding WFS layer name:

curl -X GET "https://graph.quarticle.ro/graph/layers/wms/DescribeLayer" \
-H "Authorization: YOUR_API_KEY" \
-G \
-d "service=WMS" \
-d "version=1.1.1" \
-d "request=DescribeLayer" \
-d "layers=GRAPHRASTER:cities"

From the response, extract the WFS typeNames (usually same as the layer name).


Step 2: Query Features by Bounding Box

Retrieve all features within a geographic area:

# Cities in New York area (bbox in EPSG:4326)
curl -X GET "https://graph.quarticle.ro/graph/layers/wfs/GetFeature" \
-H "Authorization: YOUR_API_KEY" \
-G \
-d "service=WFS" \
-d "version=2.0.0" \
-d "request=GetFeature" \
-d "typeNames=GRAPHRASTER:cities" \
-d "bbox=-74.1,40.6,-73.9,40.8,EPSG:4326" \
-d "outputFormat=application/json" \
| jq '.features[] | .properties'

Step 3: Query Features by Attributes (CQL Filter)

Filter features using attribute conditions:

# Cities with population > 1 million
cql_filter=population > 1000000

Step 4: Combine Spatial and Attribute Filters

Filter by both location and attributes:

curl -X GET "https://graph.quarticle.ro/graph/layers/wfs/GetFeature" \
-H "Authorization: YOUR_API_KEY" \
-G \
-d "service=WFS" \
-d "version=2.0.0" \
-d "request=GetFeature" \
-d "typeNames=GRAPHRASTER:cities" \
-d "bbox=-74.1,40.6,-73.9,40.8,EPSG:4326" \
-d "cql_filter=population > 100000" \
-d "propertyName=name,population,geometry" \
-d "outputFormat=application/json"

Step 5: Paginate Through Large Result Sets

For large datasets, paginate to avoid timeouts:

async function getAllFeatures(typeNames, cqlFilter = null) {
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: typeNames,
count: pageSize.toString(),
startIndex: (page * pageSize).toString(),
outputFormat: 'application/json'
});

if (cqlFilter) {
params.append('cql_filter', cqlFilter);
}

const response = await fetch(
`https://graph.quarticle.ro/graph/layers/wfs/GetFeature?${params}`,
{ headers: { 'Authorization': `${apiKey}` } }
);

const geojson = await response.json();
const count = geojson.features.length;
allFeatures.push(...geojson.features);

console.log(`Page ${page + 1}: Retrieved ${count} features (total: ${allFeatures.length})`);

// Stop if fewer features than page size
if (count < pageSize) break;
page++;
}

return allFeatures;
}

const allCities = await getAllFeatures('GRAPHRASTER:cities', "population > 50000");
console.log(`Total: ${allCities.length} cities`);

Step 6: Export to CSV or File

Save queried features to a file:

async function exportFeaturesToJSON(typeNames, filename) {
const features = await getAllFeatures(typeNames);

const geojson = {
type: 'FeatureCollection',
features: features
};

const json = JSON.stringify(geojson, null, 2);
const blob = new Blob([json], { type: 'application/json' });
const url = URL.createObjectURL(blob);

const link = document.createElement('a');
link.href = url;
link.download = filename;
link.click();
}

exportFeaturesToJSON('GRAPHRASTER:cities', 'cities.geojson');

Step 7: Spatial Queries (Advanced)

Use CQL spatial functions to query features:

# Cities within 10km of Times Square
cql_filter=DWITHIN(geometry, POINT(-73.9857 40.7580), 10000, meters)

Complete Workflow Example

const API_KEY = process.env.QARTA_API_KEY;

async function analyzeMetropolitanAreas() {
console.log('Querying metropolitan areas...');

// Step 1: Get all cities
const params = new URLSearchParams({
service: 'WFS',
version: '2.0.0',
request: 'GetFeature',
typeNames: 'GRAPHRASTER:cities',
cql_filter: "type = 'metropolitan' AND population > 1000000",
propertyName: 'name,population,area,country',
sortBy: 'population D',
outputFormat: 'application/json'
});

const response = await fetch(
`https://graph.quarticle.ro/graph/layers/wfs/GetFeature?${params}`,
{ headers: { 'Authorization': `${API_KEY}` } }
);

const geojson = await response.json();

// Step 2: Analyze
const analysis = {
totalCities: geojson.features.length,
totalPopulation: 0,
averagePopulation: 0,
cities: []
};

geojson.features.forEach(feature => {
const { name, population, area, country } = feature.properties;
analysis.totalPopulation += population;
analysis.cities.push({
name,
population,
area,
country,
density: (population / area).toFixed(0)
});
});

analysis.averagePopulation = Math.round(analysis.totalPopulation / analysis.totalCities);

// Step 3: Export
const json = JSON.stringify(analysis, null, 2);
const blob = new Blob([json], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'metropolitan_analysis.json';
link.click();

console.log('Analysis complete:', analysis);
return analysis;
}

analyzeMetropolitanAreas();

Use Cases

  • Real estate analysis: Query properties in specific areas and price ranges
  • Environmental data: Download pollution, climate, or vegetation data for analysis
  • Urban planning: Extract zoning, infrastructure, or demographic data
  • Research: Bulk-download geographic features for spatial analysis
  • Data pipeline: Integrate WFS queries into ETL processes

Next Steps