Parse JSON array returned via x-callback?

The notes app Bear has a way to retrieve all tags used in notes with an x-callback-url. What is returned is a json array. I know how to deal with this array in Shortcuts because of the dictionary functions (e.g., see this shortcut which returns all tags: https://www.icloud.com/shortcuts/df7d2440a0db40e0a7c6ebd1c924d440). However, I’d like to do this in Drafts with JavaScript so that I can use the returned data to populate a prompt (e.g., upon sending a note to Bear, prompt for tags by providing all the existing tags as a “picker” in a prompt. This way I don’t have to hard code the tags into the prompt).

However, not only do I not know how to get Drafts to read the json data, I don’t know how to then pipe it into the prompt as picker options. I’m not sure if I should be learning to use JSON.parse, maps, or some other JavaScript stuff that is beyond my current understanding. Any examples or code I could customize/copy would be very useful. Thanks!

1 Like

There’s a few different questions here…I’ll try address some of them…

Parsing JSON

If you have a string value which should have JSON content, like returned in a argument of a callback URL, you would turn that into a JavaScript object like:

let jsonStr = "{\"key\":\"value\"}";
let obj = JSON.parse(jsonStr);

JSON.parse docs

Getting Callback Parameters

If you have made a Callback URL step request to Bear, and it has returned result parameters, those parameters are available to scripts in the context.callbackResponse object. Details in the Callback URL step docs. It is important that the script step is after the Callback URL step and that the Callback URL step is set to wait for response.

(This can also be done in script with the CallbackURL object).

You’d have to check Bear’s URL docs for what the name of the parameter they are returning the JSON value is.

Prompt Values

If you want a picker, you would have to script the creation of the prompt. There are some examples out there in the directory and the in the Prompt object docs.

Hopefully that will at least get you headed in the right direction.

1 Like

Very helpful! Thanks @agiletortoise.

I’ve gotten what seems like most of the way there, but am stymied by this error:

Script Error: TypeError: Cannot convert primitive to NSArray

Line number: 30, Column 12 

Here’s the script I’m using:

// picker

// Prompt example
// Using Select 

var p = Prompt.create();
p.title = "Choose Tags";

let response = context.callbackResponses[0];

let result = response["tags"];

let result2 = JSON.parse(result);

let result3 = "";

for (let name in result2) {
	
	result3 += "\"" + result2[name].name + "\", ";
	
}

let tags = "[" + result3 + "]";

console.log(tags);

var selectedOptions = ["notes"];

// multiple selections
p.addSelect("s2", "Select multiple...", tags, selectedOptions, true);

p.addButton("OK");

if (p.show()) {
	var s = "Tags: " + p.fieldValues["s2"] + "\n";
	alert(s);
}

Here’s the full console output:

Callback success response received.
["favorite", "friday_review", "guide", "journal",]
Script Error: TypeError: Cannot convert primitive to NSArray
Line number: 30, Column 12

When I just paste in the tag array without calling it from the callback, the script works fine. However, from what I can tell from the console log, the “tag” variable seems to look exactly like what I’m pasting in, so I’m missing something.

Your “tags” variable is a string, not an array. You need an array of strings. Something like:

let result3 = [];
for (let name in result2) {
	result3.push(result2[name].name);	
}

Ok, thanks for your help @agiletortoise. I was able to achieve this:

var p = Prompt.create();
p.title = "choose tag";

let response = context.callbackResponses[0];

let result = response["tags"];

let result2 = JSON.parse(result);

let tags = [];

for (let item in result2) {
   tags.push(result2[item].name);	
}

// multiple selections
p.addSelect("s2", "Select multiple...", tags, [""], true);

p.addButton("OK");

if (p.show()) {
   var final="";
   for (let t of p.fieldValues["s2"]) {
   	final += "#" + t + " ";
   }
}

draft.content = draft.content + "\n" + final;
draft.update();

However, I’m getting an extra hash mark at the beginning of the line.

E.g., if I select the tags “favorite, friday_review, guide” from the prompt, I get the following appended to my draft:

# #favorite #friday_review #guide

Where is that first hash symbol coming from? Does the for loop create an empty first entry for some reason?

A quick scan and it looks like you are starting with a non-empty array.

p.addSelect("s2", "Select multiple...", tags, [""], true);

See if this fixes it.

p.addSelect("s2", "Select multiple...", tags, [], true);
1 Like

Beautiful! That did it. I thought it was necessary to have those quote in there to make the array empty. Thanks for the clarification.

What you had I think would be best described as an array containing one item; an empty string.

1 Like

The big thing I learned from making this script (which I’m still tweaking and will post soon) is that strings, arrays, and objects require unique ways of working. I hadn’t made this distinction properly before. Let that be a lesson to all the other novice Drafts javascripters! :wink:

2 Likes

Thanks to @agiletortoise and @sylumer for the help. I posted the finished script to the forum just now.