Add GIS FeatureClass to a map

This is a sample of a HTML page with a GIS FeatureClass rendered as a Vector Layer in Open Layers. Two backdrop layers from Google services are added to the map. Then, features are fetched from a GIS Service and added to the map.

<html>
  <head>
    <title>Feature Class in Open Layers</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta charset="UTF-8" />
    <script src="https://cdn.jsdelivr.net/npm/ol@v7.1.0/dist/ol.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.9.0/proj4-src.min.js"></script>
    <script src="https://viglino.github.io/ol-ext/dist/ol-ext.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v7.1.0/ol.css" />
    <link rel="stylesheet" href="https://viglino.github.io/ol-ext/dist/ol-ext.css" />
    <style type="text/css">
      html,
      body,
      #map {
        margin: 0;
        padding: 0;
        width: 100%;
        height: 100%;
      }
      #map .ol-layerswitcher .panel li label {
        max-width: 100%;
        height: 2.4em;
        user-select: all !important;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      const layerController = new ol.control.LayerSwitcher({ collapsed: false, extent: true });

      const map = new ol.Map({
        target: 'map',
        controls: ol.control.defaults
          .defaults({ attribution: false, zoom: false })
          .extend([layerController]),
        view: new ol.View({ center: [0, 0], zoom: 3 }),
        interactions: ol.interaction.defaults
          .defaults({ doubleClickZoom: false, })
          .extend([]),
        layers: [
          new ol.layer.Tile({
            title: 'Satellite',
            visible: true,
            baseLayer: false,
            displayInLayerSwitcher: true,
            preload: Infinity,
            source: new ol.source.XYZ({ url: 'http://mt{0-3}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}' }),
          }),
          new ol.layer.Tile({
            title: 'Terrain',
            visible: false,
            baseLayer: false,
            displayInLayerSwitcher: true,
            preload: Infinity,
            source: new ol.source.XYZ({ url: 'http://mt{0-3}.google.com/vt/lyrs=p&hl=en&x={x}&y={y}&z={z}' }),
          }),
        ],
      });

        const openApiKey = "<fill in open api key>";
        const gisProjectId = "<fill in project id>";
        const gisDatasetId =  "<fill in dataset id>";

        const style = new ol.style.Style({image: new ol.style.Circle({radius: 1, fill: null, stroke: new ol.style.Stroke({color: 'blue', width: 2})})});

        const styleFunction = (feature) => style;

        const handleStationSelected = (feature) => console.log(feature.getProperties());

        fetch(`https://api.mike-cloud.com/api/gis/dataset/${gisDatasetId}/query`,
            {
                method: 'POST',
                body: JSON.stringify({}),
                headers: {
                    'api-version': '2',
                    'dhi-open-api-key': openApiKey,
                    'Content-Type': 'application/json'
                },
            }
        )
        .then((response) => response.json())
        .then((response) => {
            const projection = map.getView().getProjection();
            const features = new ol.format.GeoJSON().readFeatures(response, {dataProjection: 'EPSG:4326', featureProjection: projection});
            const vectorSource = new ol.source.Vector({ features: features });

            const vectorLayer = new ol.layer.Vector({
                title: "Stations",
                source: vectorSource,
                style: styleFunction,
            });
            map.addLayer(vectorLayer);

            map.getView().fit(vectorLayer.getSource().getExtent(), {
                maxZoom: 10,
                duration: 500,
                size: [0.6 * map.getSize()[0], 0.6 * map.getSize()[1]],
            });

            map.on('click', function(evt) {
                const feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) { return feature; }, { hitTolerance: 10 });
                handleStationSelected(feature);
            });
        });
    </script>
  </body>
</html>