By default, custom data providers created using the CDF command line tool include only query capabilities. However, you can extend a custom data provider to implement the apply operation on the custom data feature service by defining custom routes and methods.
After creating a custom data provider with the CDF command line tool, follow the steps below to configure it for edit capability.
Configuring Provider Routes and Controllers
-
Create a new file called routes.js in the providers/your_provider_name/src directory. Add the following code to the file:
Use dark colors for code blocks Copy module.exports = [ { path: `/<provider_name>/rest/services/:host/:id/FeatureServer/:layer/applyEdits`, methods: ['POST'], handler: 'editData' }, { path: `/<provider_name>/rest/services/:host/:id/FeatureServer/applyEdits`, methods: ['POST'], handler: 'editData' } ]In this file, we've created two new routes - one for layer-level editing requests and one for service-level editing requests. These routes follow the same pattern as the read-only
queryroutes but have theapplyoperation instead. If your custom data provider makes use ofEdits hostandidpath parameters, make sure these are present in the newly registered routes.applyis an HTTPEdits POSTmethod. The value of thehandlerproperty refers the name of the function that your custom data code will execute when this route recieves a request. In this case the function name isedit, but this can be any name you choose.Data -
Create a new file called controllers.js in the providers/your_provider_name/src directory. Add
the following code to the file:Use dark colors for code blocks Copy function Controller (model) { this.model = model } Controller.prototype.editData = async function (req, res) { const reply = await this.model.editData(req); res.status(200).json(reply); } module.exports = ControllerIn the file, we've registerd our
handlerfunctionedit. The request is passed intoData edit. AfterData editexecutes its editing logic, the reply is returned.Data -
Open the file index.js in the providers/your_provider_name/src directory. Add the two lines (
routesandController) shown in the code below to theproviderobject.Use dark colors for code blocks Copy const packageInfo = require('../package.json') const csconfigInfo = require('../cdconfig.json') const provider = { type: csconfigInfo.type, name: csconfigInfo.name, version: packageInfo.version, hosts: csconfigInfo.properties.hosts, disableIdParam: csconfigInfo.properties.disableIdParam, Model: require('./model'), routes: require('./routes'), Controller: require('./controllers') } module.exports = providerAt this point, the provider is configured to handle editing requests via the
applyroute. The next step is write the custom code for performing edits on the remote data source in theEdits editfunction.Data -
Open the model.js file in the providers/your_provider_name/src directory. In the
Modelclass, create a neweditfunction. At this point, the code becomes specific to your implementation. Below is a sample of a basicData editfunction that calls on various helper functions.Data Use dark colors for code blocks Copy async editData(req) { // assign database and collection name from path parameters const databaseName = req.params.host; const collectionName = req.params.id; // add logic to normalize layer-level or service-level requests const extractedEdits = normalizeRequestedEdits(req.body); const database = this.#client.db(databaseName); const collection = database.collection(collectionName); let applyEditsResponse = {} // initialize the response object // call the necessary functions to handle the edits applyEditsResponse = await performEdits(collection, extractedEdits.edits); // check if the response should be an object(layer-level) or an array(service-level) if (extractedEdits.editLevel === 'service') { applyEditsResponse.id = extractedEdits.layer; return [applyEditsResponse]; } return applyEditsResponse; }
Understanding the apply Edits API Specification
The edit method must be written to handle requests and return responses that conform to the apply REST API specification. To ensure compatibility with ArcGIS clients, the edit method should be designed to handle both layer-level and service-level apply requests.
A high-level overview of the specification is provided below. For complete details on the structure of requests and responses, refer to the REST API specification. Additionally, see this Walkthrough topic for an example of how to implement these details in a custom data provider.
Layer-level Request
The request object for a layer-level apply operation includes three optional parameters: adds, updates, deletes, with at least one of these present. Each parameter is an array:
addsandupdates: Arrays of objects where each objects containsgeometryand/orattributes.deletes: Either a comma-separated string of object IDs or an array of object IDs.
Examples:
adds:
[
{
"geometry": {
"x": -12246623.482500909,
"y": 6274905.896395514,
"spatialReference": {
"wkid": 102100,
"latestWkid": 3857
}
},
"attributes": {
"fireId": "C3PO",
"fireName": "Golden Fire",
"fireType": "Wild",
"acres": "4682"
}
}
]updates:
[
{
"geometry": {
"x": -12345678.123456789,
"y": 6543210.987654321,
"spatialReference": {
"wkid": 102100,
"latestWkid": 3857
}
},
"attributes": {
"OBJECTID": 99,
"fireId": "R2D2",
"fireName": "Silver Blaze",
"fireType": "Controlled",
"acres": "2500"
}
}
]deletes:
[4692]Layer-level Response
The response object for a layer-level apply operation includes three arrays: add, update, and delete. Each array contains objects that minimally include the object and a success status (true or false). The arrays may be empty if no edits were requested.
Example:
{
"addResults": [
{
"objectId": 621431404,
"success": true
}
],
"updateResults": [
{
"objectId": 99,
"success": true
}
],
"deleteResults": [
{
"objectId": 4692,
"success": false,
"error": {
"code": 1018,
"description": "Failed to delete."
}
}
]
}Service-level Request
The request object for a service-level apply operation includes a required edits parameter, which is an array of layer objects. Each layer object contains the following arrays:
addsandupdates: Arrays of objects where each object includesgeometryand/orattributes.deletes: Either an array of object IDs or a comma-separated string of objectIDs.
If no edit is requested for a particular type (adds, updates, or deletes), its value will be null.
Example:
edits:
[
{
"id": 0,
"adds": [
{
"geometry": {
"x": -12246623.482500909,
"y": 6274905.896395514,
"spatialReference": {
"wkid": 102100,
"latestWkid": 3857
}
},
"attributes": {
"fireId": "C3PO",
"fireName": "Golden Fire",
"fireType": "Wild",
"acres": "4682"
}
}
],
"updates": [
{
"geometry": {
"spatialReference": {
"wkid": 102100
},
"x": -12700718.995399643,
"y": 6622215.403721428
},
"attributes": {
"OBJECTID": 3
}
}
],
"deletes": null,
}
]Service-level Response
The response for a service-level apply operation is an array of layer objects. Each layer object includes the following arrays:
add,Results update, andResults delete: Each array contains objects that minimally include theResults objectand aID successstatus (trueorfalse).
If no edits were requested, these arrays may be empty.
Example:
[
{
"id": 0,
"addResults": [
{
"success": true,
"objectId": 621431404
}
],
"updateResults": [
{
"success": true,
"objectId": 3
}
],
"deleteResults": []
}
]Important Points
Custom data providers with edit capability require additional considerations for maintaining data integrity and accessibilty. At a minimum, this involves understanding the spatial reference and data structure of the remote data source. The metadata provided with the returned GeoJSON in the provider will also impact which attributes are editable and influence how ArcGIS clients configure editing widgets.
Spatial Reference
Your provider code should track the spatial reference of the remote data source. Once data are sent to the client, reprojections may occur based on the client’s default behavior or user preferences. Edits may be requested in a spatial reference that differs from the data source. It is highly recommended that your code compares the spatial references and, when they differ, transforms the data back to the original spatial reference. For transformation, use @esri/proj-codes and proj4. This process is demonstrated in this Walkthrough.
ObjectId
To be editable, features in the remote data source must include an attribute that meets the requirements for an esri. This attribute must be an integer no larger than 64 bits. For detials, refer to the CDF API Reference documentation on the id metadata property.
Templates
Templates are essential for customizing editing widgets in ArcGIS clients. By using custom templates, you can specify which attributes are visible for editing, set default values, and apply other customizations. Refer to the CDF API Reference documentation on the templates metadata property.
fields Metadata
To make an attribute editable, set the editable property in the fields metadata. This allows fine-grained control over which feature attributes are available for editing. See the CDF API Reference documentation on the fields metadata property.
Error Codes
Refer to the ArcGIS REST documentation for Feature Service Error Codes. Generally, the error codes that your provider should return are 1017 for an insert error, 1018 for a delete error, and 1019 for an update error.