What3words API integration - Get the w3w address for a draft's creation location

If you’re not familiar with it, what3words, is one of those rather wonderful instances where technology solves a mundane problem - easily share the specific location of where you are / need people to go. So rather than a post/zip code which, can be hugely unreliable, each 3m x 3m square on the planet is given its own unique 3 word address. For example, the centre of Stonehenge is:

///workbook.remark.galloping
http://w3w.co/workbook.remark.galloping

So, as Drafts already records the location of a draft’s creation/modification, I was wondering if it would be possible to tie this into the what3words API? It would be very handy to be able to share locations of historical and current drafts in this user-friendly format.

3 Likes

This can easily be done with an action. I’m not sure what you want to do with the what3words response, but I’ve created an example action that lets you copy it or open in what3words.

Here’s a link to the action:
https://actions.getdrafts.com/a/1M2

It will prompt for your developer API key and store it in Drafts credentials thereafter. I hope this helps!

Nick

1 Like

This is fantastic. Many thanks for your time. I got it working with no issues.

In terms of use cases, this is what I was envisaging:

  1. Current: Send from Drafts a templated message which includes w3w URL. E.g.

"I am waiting here. Give me a call if any issues.

http://w3w.co/workbook.remark.galloping"

So you don’t write anything in Drafts itself - just run an action which includes templated text and calls w3w based on current location. You can then share via share sheet.

The only benefit here over the w3w app is that you can include a message opposed to just the link when you share with w3w app. Admittedly an iOS shortcut could cover this off.

  1. Historical/noting specific location details: This is where I see it being more beneficial going forward.

You may have taken a draft/notes pertinent to a specific location when at that location. E.g. “This stile had been blocked off on the x walk,” or “should have gone for the fish and chips as the portions were massive.” So when sharing this draft, it would be handy to have an action that rendered it something like:

"As discussed, here are the notes I made:

‘[[original_draft_content]]’

[[original_draft_creation time]]

w3w URL for original draft"

Hope this better articulates the use cases I envisaged.

I updated the action to see if it gets closer to what you were looking for. You could set up a “share & delete” action for either of these, so that the new drafts don’t hang around for long.

https://actions.getdrafts.com/a/1M2

I had never heard of what3words, so thanks for that.

Nick

Marvellous. Thanks for your help.

Sounds as if w3w are gathering a fair bit of momentum now. Mercedes are on board and TomTom are to adopt 3 word addressing too. It’s a very clever idea and I love the work they have done in Africa etc.

I’m getting a scripting error after adding my API Key… thoughts on corecting?

The error should give an indication of what the problem is. What error are you getting exactly?

What a blunder… here it is:

Script Error: TypeError: undefined is not an object (evaluating ‘data.words’)
Line number: 42, Column 19

Okay, data seems to be populated by the getWords() function. That writes any API return failures to the console (log). Do you have any details preceding the error you found in the log? when the action runs, it does not look like it will terminate processing when the API call fails. But it also does not look as though it logs a successful API call, only failures. We have to infer at this point what is going on by the presence or absence of the additional info.

My best guess would be the expected value is undefined because the API call did not return the data structure the subsequent processing requires. The most likely reason is that the API call failed, in which case the logged error code and reason should give an indication as to why. Hopefully, that will then help figure out how to resolve your issue.

I’ve just given the action a test, and it worked fine for me, and so there are only two factors at play - Drafts knowing your location, and the validity of the API key.

Assuming you entered the key correctly (mine is similar to ACTORON7), have you enabled location services access at the OS level for Drafts to grab your current location?

Hopefully, something above will get you on the right track.

@sylumer & @jaymf
The problem is that w3w deprecated the v2 API:

I changed the script as follows and it works again:

/* Send templates with w3w location */
(() => {
  'use strict';
  // main() :: Body of script and local functions 
  const main = () => {
    const getWords = () => {
      // Create API credential
      const credential = Credential.create("what3words API", "Key to access what3words REST API");
      credential.addTextField("Api_Key", "API Key");
      credential.authorize();
      const cLon = draft.createdLongitude,
        cLat = draft.createdLatitude,
        coordinates = `${cLat},${cLon}`,
        key = credential.getValue("Api_Key"),
        http = HTTP.create(),
        base_url = "https://api.what3words.com/v3/convert-to-3wa?",
        params = {
          "coordinates": coordinates,
          "key": key,
          "lang": "en",
          "format": "json",
          "display": "full"
        };
      let strs = [];
      for (let k of Object.keys(params)) {
        strs.push(`${k}=${encodeURIComponent(params[k])}`);
      }
      const url = base_url + strs.join('&'),
        response = http.request({
          "url": url,
          "method": "GET"
        });
     if (response.success) {
        const text = response.responseText;
        return JSON.parse(text);
      } else {
        console.log(response.statusCode);
        console.log(response.error);
      }
    }
    const data = getWords(),
      words = data.words,
      mapLink = data.map;
    if (words) {
      // Create prompt
      const p = Object.assign(Prompt.create(), {
          title: "Location",
          message: "Share Location",
          isCancellable: true
        }),
        // Build 2d array of buttons/actions
        buttons = [
          ['Copy to Clipboard', () => app.setClipboard(words)],
          ['Open in what3words', () => app.openURL(mapLink)],
          ['Create Template with Loc', () => createTemplateDraft(mapLink)],
          ['Create Draft Copy with Loc', () => createDraftCopyWithLoc(mapLink)]
        ],
        bMap = new Map(buttons);
      bMap.forEach((v, k) => p.addButton(k))
      const picked = p.show();
      if (picked) {
        bMap.get(p.buttonPressed)();
      } else {
        context.cancel();
      }
    }
  }
  // MAIN --------------------------------
  // createTemplateDraft :: w3w link -> Template msg
  const createTemplateDraft = locLink => {
    const msg = `I am waiting here. Give me a call if any issues.\n\n${locLink}`,
      d = Draft.create();
    d.content = msg;
    d.update();
    editor.load(d);
  };
  // createDraftCopyWithLoc :: w3w link -> Copy with loc link and msg
  const createDraftCopyWithLoc = locLink => {
    const createTime = draft.createdAt.toString("F"),
    origText = draft.content,
    newText = `As discussed, here are the notes I made:\n\n${origText}\n\n${createTime}\n\n${locLink}`,
    d = Draft.create();
    d.content = newText;
    d.update();
    editor.load(d);
  };
  return main();
})();

only changes in the base URL and the parameters where adapted. Did not test the full functionality of the action. Maybe @comfortablynick wants to update the public action :slight_smile:

It worked, and still does work fine for me.

I wonder if it is just that my API key is for the prior version of the API and that API still works, just not with more recently generated keys?

Interesting - but as you mentioned this might be the reason (I created my key today to test the action :slight_smile:

I am getting a new error with the new script:

Script Error: SyntaxError: Unexpected EOF
Line number: 3, Column undefined

I’ve confirmed location services are enabled for Drafts.

I generated a new API key on my W3W account and used it with a new version of the action using the script @FlohGro posted above. Once again it works fine for me.

Here is the action updated to use the script from above. The only modification I made is to the name of the credential so I could have both actions with both API keys alongside one another.

Try it and see if that works. Maybe you copied something wrong?

2 Likes

@sylumer the v2 with a newly generated API key worked.
Thank you and @FlohGro for your assistance!

1 Like