Geocode with OpenCage and MapLibre
Tags: javascript, geocoder, opencage, api
Published: 2023-03-22 09:39:17

> [OpenCage](https://opencagedata.com/) is an API Provider offering two services a geocoding service and a geosearch service 
> [MapLibre](https://maplibre.org/) is an Open-source mapping libraries for web and mobile app developers.

In this article we will learn how to geocode with OpenCage and the maplibre-gl-geocoder plugin.

First, one need an OpenCage API Key, it is free for testing, signup for your own key [here](https://opencagedata.com/users/sign_up).

This example will be based on a simple HTML page.

### Header
The header will then contain a viewport:

```html
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
```

Some CSS and JS for MapLibre and the geocoder plugin
```html
<!-- STYLES -->
<link href="https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.css" rel="stylesheet" />
<link href="https://unpkg.com/@maplibre/maplibre-gl-geocoder@1.2.0/dist/maplibre-gl-geocoder.css" rel="stylesheet" />
```

```html
<!-- scripts -->
<script src="https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.js"></script>
<script src="https://unpkg.com/@maplibre/maplibre-gl-geocoder@1.2.0/dist/maplibre-gl-geocoder.min.js"></script>
```

```html
<!-- CSS -->
body {
  margin: 0;
  padding: 0;
}
#map {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
}
```

### Body
Now let's look at the body of this HTML page

```html
<div id="map"></div>
```

Pretty sleek, isn't it?

### Script

#### Map
Indeed the magic happens in JS. The first part is the map using MapLibre GL JS. Here, I used a simple openstreetmap basemap using a raster source. The SDK offers various sources [link](https://maplibre.org/maplibre-gl-js-docs/style-spec/sources).

```js
var map = new maplibregl.Map({
  container: "map",
  // Use a minimalist raster style
  style: {
    version: 8,
    name: "Blank",
    center: [0, 0],
    zoom: 0,
    sources: {
      "raster-tiles": {
        type: "raster",
        tiles: ["https://tile.openstreetmap.org/{z}/{x}/{y}.png"],
        tileSize: 256,
        minzoom: 0,
        maxzoom: 19
      }
    },
    layers: [
      {
        id: "background",
        type: "background",
        paint: {
          "background-color": "#e0dfdf"
        }
      },
      {
        id: "simple-tiles",
        type: "raster",
        source: "raster-tiles"
      }
    ],
    id: "blank"
  },
  center: [0, 51],
  zoom: 4,
  antialias: true
});
```

#### Geocode

We define the geocoder API. From the documentation _Any geocoder api that supports the functions reverseGeocode and forwardGeocode and returns a response which includes a FeatureCollection of results_ 

We use the OpenCage API and its GeoJSON format, but as you can see, because this is JS, one can use the classical JSON response from the API and transform into GeoJSON.

```js
// Replace it with your API Key. 
// The test key returns only 
// "Friedrich-Ebert-Straße 7, 48153 Münster, Germany" 
// whatever the input is
var YOUR_API_KEY="6d0e711d72d74daeb2b0bfd2a5cdfdba";

var geocoder_api = {
  forwardGeocode: async (config) => {
    const features = [];
    try {
      let request =
        "https://api.opencagedata.com/geocode/v1/geojson?q=" +
        config.query +
 "&key="+YOUR_API_KEY+"&no_annotations=1";
      const response = await fetch(request);
      const geojson = await response.json();
      for (let feature of geojson.features) {
        let point = {
          type: "Feature",
          geometry: {
            type: "Point",
            coordinates: feature.geometry.coordinates
          },
          place_name: feature.properties.formatted,
          properties: feature.properties,
          text: feature.properties.formatted,
          place_type: ["place"]
        };
        features.push(point);
      }
    } catch (e) {
      console.error(`Failed to forwardGeocode with error: ${e}`);
    }

    return {
      features: features
    };
  }
};
```

now add the Geocoder API to the plugin and attached it to the map

```js
map.addControl(
  new MaplibreGeocoder(geocoder_api, {
    maplibregl: maplibregl
  })
);
```

and we are all set.

### Demo

A live example using the test API key (returning only Münster) is available on [codepen](https://codepen.io/tsamaya/pen/KKxGwLj)

### The end

Thanks for reading 🙏 


### Resources
- The code fragments are available on this [gist](https://gist.github.com/tsamaya/dd6fdf3ed4ee9e4497216a52af58c44e)
- Photo by <a href="https://unsplash.com/@delfidelarua7?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">delfi de la Rua</a> on <a href="https://unsplash.com/photos/vfzfavUZmfc?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>