This example uses OpenLayers v10.9.0. The latest is v.
Edit

#### Editable ArcGIS REST Feature Service

vector 86 esri 3 ArcGIS 5 REST 3 Feature 12 Service 2 loading 8 server 5 edit 13 updateFeature 1 addFeature 1

#####

Draw or modify

Example of using an ArcGIS REST Feature Service in an editing application.

This example loads features from ArcGIS REST Feature Service and allows to add new features or update existing features.

##### main.js

    import Map from 'ol/Map.js';
    import View from 'ol/View.js';
    import EsriJSON from 'ol/format/EsriJSON.js';
    import Draw from 'ol/interaction/Draw.js';
    import Modify from 'ol/interaction/Modify.js';
    import Select from 'ol/interaction/Select.js';
    import {defaults as defaultInteractions} from 'ol/interaction/defaults.js';
    import TileLayer from 'ol/layer/Tile.js';
    import VectorLayer from 'ol/layer/Vector.js';
    import {tile as tileStrategy} from 'ol/loadingstrategy.js';
    import {fromLonLat} from 'ol/proj.js';
    import ImageTile from 'ol/source/ImageTile.js';
    import VectorSource from 'ol/source/Vector.js';
    import {createXYZ} from 'ol/tilegrid.js';

    const serviceUrl =
      'https://sampleserver6.arcgisonline.com/arcgis/rest/services/Wildfire/FeatureServer/';
    const layer = '2';

    const esrijsonFormat = new EsriJSON();

    const vectorSource = new VectorSource({
      loader: async (extent, resolution, projection) => {
        const url =
          serviceUrl +
          layer +
          '/query/?f=json&' +
          'returnGeometry=true&spatialRel=esriSpatialRelIntersects&geometry=' +
          encodeURIComponent(
            '{"xmin":' +
              extent[0] +
              ',"ymin":' +
              extent[1] +
              ',"xmax":' +
              extent[2] +
              ',"ymax":' +
              extent[3] +
              ',"spatialReference":{"wkid":102100}}',
          ) +
          '&geometryType=esriGeometryEnvelope&inSR=102100&outFields=*' +
          '&outSR=102100';
        const response = await fetch(url);
        const json = await response.json();
        if (json.error) {
          alert(json.error.message + '\n' + json.error.details.join('\n'));
          throw new Error(json.error.message);
        } else {
          // dataProjection will be read from document
          const features = esrijsonFormat.readFeatures(json, {
            featureProjection: projection,
          });
          return features;
        }
      },
      strategy: tileStrategy(
        createXYZ({
          tileSize: 512,
        }),
      ),
    });

    const vector = new VectorLayer({
      source: vectorSource,
    });

    const raster = new TileLayer({
      source: new ImageTile({
        attributions:
          'Tiles © <a href="https://services.arcgisonline.com/ArcGIS/' +
          'rest/services/World_Topo_Map/MapServer">ArcGIS</a>',
        url:
          'https://server.arcgisonline.com/ArcGIS/rest/services/' +
          'World_Topo_Map/MapServer/tile/{z}/{y}/{x}',
      }),
    });

    const draw = new Draw({
      source: vectorSource,
      type: 'Polygon',
    });

    const select = new Select();
    select.setActive(false);
    const selected = select.getFeatures();

    const modify = new Modify({
      features: selected,
    });
    modify.setActive(false);

    const map = new Map({
      interactions: defaultInteractions().extend([draw, select, modify]),
      layers: [raster, vector],
      target: document.getElementById('map'),
      view: new View({
        center: fromLonLat([-110.875, 37.345]),
        zoom: 5,
      }),
    });

    const typeSelect = document.getElementById('type');

    /**
     * Let user change the interaction type.
     */
    typeSelect.onchange = function () {
      draw.setActive(typeSelect.value === 'DRAW');
      select.setActive(typeSelect.value === 'MODIFY');
      modify.setActive(typeSelect.value === 'MODIFY');
    };

    const dirty = {};

    selected.on('add', function (evt) {
      const feature = evt.element;
      feature.on('change', function (evt) {
        dirty[evt.target.get('objectid')] = true;
      });
    });

    selected.on('remove', function (evt) {
      const feature = evt.element;
      const fid = feature.get('objectid');
      if (dirty[fid] === true) {
        const payload =
          '[' +
          esrijsonFormat.writeFeature(feature, {
            featureProjection: map.getView().getProjection(),
          }) +
          ']';
        const url = serviceUrl + layer + '/updateFeatures';
        fetch(url, {
          method: 'POST',
          body: new URLSearchParams({f: 'json', features: payload}),
          headers: {'Content-Type': 'application/x-www-form-urlencoded'},
        })
          .then((response) => response.json())
          .then((data) => {
            const result = typeof data === 'string' ? JSON.parse(data) : data;
            if (result.updateResults && result.updateResults.length > 0) {
              if (result.updateResults[0].success !== true) {
                const error = result.updateResults[0].error;
                alert(error.description + ' (' + error.code + ')');
              } else {
                delete dirty[fid];
              }
            }
          });
      }
    });

    draw.on('drawend', function (evt) {
      const feature = evt.feature;
      const payload =
        '[' +
        esrijsonFormat.writeFeature(feature, {
          featureProjection: map.getView().getProjection(),
        }) +
        ']';
      const url = serviceUrl + layer + '/addFeatures';
      fetch(url, {
        method: 'POST',
        body: new URLSearchParams({f: 'json', features: payload}),
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
      })
        .then((response) => response.json())
        .then((data) => {
          const result = typeof data === 'string' ? JSON.parse(data) : data;
          if (result.addResults && result.addResults.length > 0) {
            if (result.addResults[0].success === true) {
              feature.set('objectid', result.addResults[0]['objectId']);
            } else {
              const error = result.addResults[0].error;
              alert(error.description + ' (' + error.code + ')');
            }
          }
        });
    });

##### index.html

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <title>Editable ArcGIS REST Feature Service</title>
        <link rel="stylesheet" href="node_modules/ol/ol.css">
        <style>
          .map {
            width: 100%;
            height: 400px;
          }
        </style>
      </head>
      <body>
        <div id="map" class="map"></div>
        <form>
          <label for="type">Draw or modify &nbsp;</label>
          <select id="type">
            <option value="DRAW">Draw</option>
            <option value="MODIFY">Modify</option>
          </select>
        </form>

        <script type="module" src="main.js"></script>
      </body>
    </html>

##### package.json

    {
      "name": "vector-esri-edit",
      "dependencies": {
        "ol": "10.9.0"
      },
      "devDependencies": {
        "vite": "^3.2.3"
      },
      "scripts": {
        "start": "vite",
        "build": "vite build"
      }
    }