Closed mttjhn closed 5 years ago
Hello @mttjhn and thanks for reaching out. So, this isn't really documented, but I can help explain what to do.
First, req.params.layer
is undefined on http://localhost:8080/provider/rest/services/FeatureServer/layers
because that route is registered without the layer
route param (i.e., /FeatureServer/layers
vs /FeatureServer/:layerId
. However you can still do what you want with the right code in your provider. I would do a check via a regex in your getData
if (/\/FeatureServer\/layers$/i.test(url)) {
// Build GeoJSON to support layers output here
}
For details on how to build the GeoJSON you need take a look at where the geojson for this route is processed and rendered. See https://github.com/koopjs/FeatureServer/blob/master/src/info.js#L57-L79
If you get stuck, please reach out, I'll do my best to respond ASAP. I'm interested in your work, as it will help us document this.
Ok, it's good to know that there's a way to do this. I was expecting that there might be a separate architectural layer where I could define my metadata in a single spot and then access it from getData()
. For now, I'll play with the code example you provided and will be back with more questions (or an example of how I get it working)...
@rgwozdz: I got something working. Here's the general approach I followed:
const layerMetadata = [
{
id: 0,
name: 'First Layer',
description: 'Points from my first layer',
displayField: 'loc_name',
geometryType: 'Point',
idField: 'pointid'
},
{
id: 1,
name: 'Second Layer',
description: 'Points from my second layer',
displayField: 'loc_name',
geometryType: 'Point',
idField: 'pointid'
}
];
I'm using the regex you provided to check the URL to see if I'm using the layers
route, and then I'm calling agetMetadataGeoJson()
method simply loops through all the items in my const array and creates a new FeatureCollection with a single feature in each:
function getMetadataGeoJson() {
var metadata = { layers: []};
for (var i = 0; i < layerMetadata.length; i++) {
var newFeature = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [0, 0]
}
}
],
metadata: layerMetadata[i]
}
metadata.layers.push(newFeature);
}
return metadata;
}
Putting it all together, I updated getData
to also look up metadata from my array by layerId, as shown below:
Model.prototype.getData = function (req, callback) {
if (/\/FeatureServer\/layers$/i.test(req.originalUrl)) {
// Build GeoJSON, sorta
var layers = getMetadataGeoJson();
callback(null, layers);
}
else {
var layerId = req.params.layer;
// Call database to get data
getDataFromDb(layerId)
.then((res) => {
// translate the response into geojson
const geojson = translate(res)
// Get metadata for the layer
geojson.metadata = getLayerMetadata(layerId);
// hand off the data to Koop
callback(null, geojson)
})
.catch((err) => {
callback(err)
})
}
The only downside to this right now is that I'm getting the following error whenever I hit the layers
route:
WARNING: Source data for /provider/rest/services/FeatureServer/layers is invalid GeoJSON:
1) "type" member required
If I provide a type (I was trying "FeatureCollection") it tries to parse it as actual GeoJSON... am I missing something here?
Sorry for dropping the ball on this. Nice work.
The getData callback always expects geojson; you are seeing a warning caused by the GeoJSON validator. It's just a warning, and should be turned off on requests to this endpoint (I'll make it an issue). But you can safely ignore it - the code that processes the data can accept a FeatureCollection OR a regular JSON array.
I'm planning to use Koop to expose data from a non-GIS system using multiple sublayers on a FeatureService. Based on the documentation, it seems that I can use the
req.params.layer
value to do this in thegetData()
method. When testing various URLs with the query method on specific layer ids, it seems to work fine. For example, I might use this URL: http://localhost:8080/provider/rest/services/FeatureServer/0/query and the data returned is different from http://localhost:8080/provider/rest/services/FeatureServer/1/query.However, when using the http://localhost:8080/provider/rest/services/FeatureServer/layers route, the output doesn't correspond to the actual layers that I return from
getData()
. Only a single layer is returned, and it is actually returning the wrong metadata, becausereq.params.layer
is undefined when calling the../FeatureServer/layers
route. Is there some undocumented way to define the layer metadata? It seems that calling../FeatureServer/layers
actually executes getData. How is that part of the output provider intended to work?My goal here is to provide all the layer metadata so that ArcGIS tools (or other code consuming the Feature Service) can see all of the layers that I intend to support in my Koop service.