Introducing Live Patching
Tags: geocoding, launch, devjournal, api
Published: 2023-07-11 04:51:43

Live Patching empowers you to add or fix locations on the fly with [PlaceKit](https://placekit.io), and make them instantly available to your users.

## Motivation

Geocoding is providing geographical coordinates corresponding to a location, and reverse geocoding means finding a location based on geographical coordinates. One common use-case of geocoding you may have seen is an address autocomplete field:

![PlaceKit autocomplete](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1veaoj0wewkoag18o8b9.png)

Providing geocoding services means keeping up to date a catalog of worldwide locations with their coordinates, and providing the API to browse through that immense amount of data. The catalog is an overly tedious task, which always requires some degree of automation and approximation. Thus no one, not even Google Maps, can pretend to have it 100% accurate.

When we were working on Algolia Places (before [it got sunset](https://www.algolia.com/blog/product/sunsetting-our-places-feature/)), we noticed a critical pain point for our customers. Some use cases need a way to fix locations from a catalog, without delay. For example, an e-commerce website experiencing mis-shipments due to an invalid address will often reach out to its user to get the correct one, and need a way to fix it once and for all to prevent any more failed delivery for that person. And that would occur multiple times per week.

Even if we were somewhat reactive in fixing locations at Algolia Places, it had to go through a submission process via a form, manually reviewing internally whenever the product team has the time. It's very time-consuming and a bit hard to propagate fixes in a large automated pipeline processing. The same goes with our competitors like Google Places or Mapbox: at best, fixing a location is manual a process that could take days or weeks of back-and-forth validation.

At PlaceKit, we believe **businesses know better**, so we're introducing a differentiating feature: **Live Patching**, to let you add missing locations or fix existing ones **without delay**, providing the best experience possible for your users.

Instead of waiting for your favorite geocoding service employees to review and validate/reject your submission, PlaceKit enables you to build your own validation flow. You can either create fixes directly from the dashboard or API, or review and validate suggestions coming from your users. Once you approved the changes, the patches are instantly available to all your end users.

## How does it work

We merge your published patches in the autocomplete suggestions at search time, only for your applications:
- For missing locations, we append them to the search, and it goes through the same relevance algorithm as any other location from our catalog. 
- For fixes, we detect and substitute them from our original record, so there are no duplicates in the suggestions list.

Patches are tied to your PlaceKit account, so they're shared across all your applications, but not shared with other PlaceKit customers: only your users see your fixes.

## Using the admin panel

[Sign in to your PlaceKit account](https://app.placekit.io) and navigate to the new "Patch" tab. You should see an empty list and an "Add patch" button. Click on it to access the form. For example, adding a new street named "New Street" to Tahoe City:

![Live Patching: add missing location](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jubbektctqdzqmxmwgj0.png)

When adding a missing location, you can pre-fill the form with an existing location. For example, if you're adding a missing street, that could come in handy to fill in all the city information.

When fixing an existing location, it'll be required that you search for the existing location first. It'll fill the form for you, and then you only have to fix the wrong fields.

![Live Patching: patch records list](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aqal2468ot4fuf62dkow.png)

You can publish and unpublish it at any time. Published means your users will see it when they search for a location; unpublished means it's only showing on your Patch page on the admin panel.

Now you have it ready for your users in the autocomplete:

![Live Patching: instant availability](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6heno6n254sfdq58xapr.png)

## Using the API

We've updated our [API Reference](https://api.placekit.io) and the [JS Client](https://github.com/placekit/client-js/releases/tag/v1.2.0) with the new endpoints.

⚠️ You need to use a **private** API key from any of your apps.

Snippets below showcase both cURL and JavaScript implementations. Before running the JS examples, instantiate PlaceKit Client:

```js
// CommonJS syntax:
const placekit = require('@placekit/client-js');

// ES6 Modules syntax:
import placekit from '@placekit/client-js';

const pk = placekit('<your-api-key>');
```

Now let's make a tour of the feature:

### Adding a missing location

```js
const result = await pk.patch.create({
 type: 'street',
 name: 'New street',
 city: 'Tahoe City',
 county: 'Placer County',
 administrative: 'California',
 country: 'United States of America',
 countrycode: 'us',
 coordinates: '39.1689372,-120.1434787',
 zipcode: ['96154'],
 population: 2644
});
```

```sh
curl -l -X POST 'https://api.placekit.co/patch' \
 -H 'x-placekit-api-key: <your-api-key>' \
 -H 'Content-Type: application/json' \
 -d '{"record":{"type":"street","name":"New street","city":"Tahoe City","county":"Placer County","administrative":"California","country":"United States of America","countrycode":"us","coordinates":"39.1689372,-120.1434787","zipcode":["96154"],"population":2644}}'
```

### Fixing an existing location

```js
// Search for an existing record first
const { results } = await pk.search('Los Angeles', {
 types: ['city'],
 countries: ['us'],
});

// Fix the existing record
await pk.patch.create(
 { zipcode: ['96154'] },
 { status: 'approved' },
 results[0], // original record
);
```

```sh
curl -l -X PUT 'https://api.placekit.co/patch' \
 -H 'x-placekit-api-key: <your-api-key>' \
 -H 'Content-Type: application/json' \
 -d '{"update":{"zipcode":["96154"]},"origin":{/* original record */},"status":"approved"}'
```

### Listing patch records

```js
// Get all patches, paginated
const { results } = await pk.patch.list();

// Filter and paginate patches
const { results } = await pk.patch.list({
 query: 'new',
 countries: ['us'],
 types: ['street'],
 status: 'approved',
 maxResults: 10,
 offset: 0,
});
```

```sh
# Get all patches, paginated
curl -l -X POST 'https://api.placekit.co/patch/search' \
 -H 'x-placekit-api-key: <your-api-key>'

# Filter and paginate patches
curl -l -X POST 'https://api.placekit.co/patch/search' \
 -H 'x-placekit-api-key: <your-api-key>' \
 -H 'Content-Type: application/json' \
 -d '{"query":"new","countries":["us"],"status":"approved","maxResults":10,"offset":0}'
```

### Retrieving a patch record

```js
// Retrieve default language
const result = await pk.patch.get('<patch-id>');

// Retrieve translation
const result = await pk.patch.get('<patch-id>', 'fr');
```

```sh
# retrieve default language
curl -l -X GET 'https://api.placekit.co/patch/<patch-id>' \
 -H 'x-placekit-api-key: <your-api-key>'

# retrieve translation
curl -l -X GET 'https://api.placekit.co/patch/<patch-id>?language=fr' \
 -H 'x-placekit-api-key: <your-api-key>'
```

### Updating a patch record

```js
// Update and publish
const result = await pk.patch.update(
 '<patch-id>',
 { coordinates: '39.1689372,-120.1434787' },
 { status: 'approved' }
);

// Update translation
const result = await pk.patch.update(
 '<patch-id>',
 { name: 'Rue Nouvelle' }, 
 { language: 'fr' }
);

// Unpublish
const result = await pk.patch.update(
 '<patch-id>',
 undefined,
 { status: "pending" }
);
```

```sh
# Update and publish
curl -l -X PATCH 'https://api.placekit.co/patch/<patch-id>' \
 -H 'x-placekit-api-key: <your-api-key>' \
 -H 'Content-Type: application/json' \
 -d '{"update":{"coordinates":"39.1689372,-120.1434787"},"status":"approved"}'

# Update translation
curl -l -X PATCH 'https://api.placekit.co/patch/<patch-id>' \
 -H 'x-placekit-api-key: <your-api-key>' \
 -H 'Content-Type: application/json' \
 -d '{"update":{"name":"Rue Nouvelle"},"language":"fr"}'

# Unpublish
curl -l -X PATCH 'https://api.placekit.co/patch/<patch-id>' \
 -H 'x-placekit-api-key: <your-api-key>' \
 -H 'Content-Type: application/json' \
 -d '{"status":"pending"}'
```

### Delete a patch record

```js
// Delete translation
await pk.patch.deleteLang('<patch-id>', 'fr');

// Delete patch record
await pk.patch.delete('<patch-id>');
```

```sh
# Delete translation
curl -l -X DELETE 'https://api.placekit.co/patch/<patch-id>/language/fr'

# Delete patch
curl -l -X DELETE 'https://api.placekit.co/patch/<patch-id>'
```

---

It's mostly just a developer feature for now, but stay tuned, we'll add more to it soon. Nonetheless, we're excited to bring this unique feature to our service, and can't wait to see your implementations!