This recipe will focus on JSL’s ability to access information through a REST API. We’ll be using Apple’s publicly available iTunes API. We’ll build a small dialog box for user input using associative arrays to implement cascading combo boxes.
Difficulty – Hard
Video Length – 6:08
Names Default to Here(1);
New Window("iTunes Query");
New Window(
"iTunes Query",
Border Box(
Top(15),Bottom(15),Left(15),Right(15),
V List Box(
)
)
);
dialog = New Window(
"iTunes Query",
Border Box(
Top(15),Bottom(15),Left(15),Right(15),
V List Box(
Text Box(""),
H List Box(Text Box("Search for: "), Text Edit Box(""),
Line Up Box(N Col(2),
Text Box("Media Type " ),Combo Box({}),
Text Box("Entity Type " ),Combo Box({}),
Text Box("Attribute Type "),Combo Box({})
),
H Center Box( H List Box(Button Box("Run"),Button Box("Quit")))
)
)
);
Text Box("",<<Set Font Size(14),<<Set Font Style(Bold))
and set the wrap width of the Text Edit Box to 450
Text Edit Box("",<<Set Width(450),<<Set Font Size(14)))
cbMedia = Combo Box(mediaValues,Eval(changeMediaType))
cbEntities = Combo Box(aaEntities["all"]) cbAttributes = Combo Box(aaAttributes["all"])
aaEntities and aaAttributes are associative arrays and will be defined explicitly at the top of the script. As with the Media combo box, we’ll want to associate these two combo boxes with variables.
Button Box("Run",Eval(clickRun))
Button Box("Quit",dialog<<Close Window)
mediaValues = {"all","music","movie","podcast","tvShow","ebook","software"};
These values are a subset of values from the API information provided at the link given above.
entityLists = {
{"any","movie","album","allArtist","podcast","musicVideo","mix","audiobook","tvSeason","allTrack"},
{"any","audiobookAuthor","audiobook"},
{"any","ebook"},
{"any","movieArtist","movie"},
{"any","musicArtist", "musicTrack", "album", "musicVideo", "mix", "song"},
{"any","genreIndex","artistTerm","albumTerm","ratingIndex","songTerm"},
{"any","podcastAuthor","podcast"},
{"any","genreIndex","artistTerm","shortFilmTerm","ratingIndex","descriptionTerm"},
{"any","software","iPadSoftware","macSoftware"},
{"any","tvEpisode","tvSeason"}
};
attributeLists = {
{"any","actorTerm","languageTerm","allArtistTerm","tvEpisodeTerm","shortFilmTerm",
"directorTerm","releaseYearTerm","titleTerm","featureFilmTerm","ratingIndex",
"keywordsTerm","descriptionTerm","authorTerm","genreIndex","mixTerm",
"allTrackTerm","artistTerm","composerTerm","tvSeasonTerm","producerTerm",
"ratingTerm","songTerm","movieArtistTerm","showTerm","movieTerm","albumTerm"
},
{"any","titleTerm", "authorTerm", "genreIndex", "ratingIndex"},
{"any"},
{"any","actorTerm","genreIndex","artistTerm","shortFilmTerm","producerTerm","ratingTerm",
"directorTerm","releaseYearTerm","featureFilmTerm","movieArtistTerm","movieTerm",
"ratingIndex","descriptionTerm"
},
{"any","mixTerm","genreIndex","artistTerm","composerTerm","albumTerm","ratingIndex","songTerm"},
{"any","genreIndex","artistTerm","albumTerm","ratingIndex","songTerm"},
{"any","titleTerm","languageTerm","authorTerm","genreIndex","artistTerm","ratingIndex",
"keywordsTerm","descriptionTerm"
},
{"any","genreIndex","artistTerm","shortFilmTerm","ratingIndex","descriptionTerm"},
{"any","softwareDeveloper"},
{"any","genreIndex","tvEpisodeTerm","showTerm","tvSeasonTerm","ratingIndex","descriptionTerm"}
};
aaEntities = Associative Array(mediaValues,entityLists);
aaAttributes = Associative Array(mediaValues,attributeLists);
any is added as the first element of all lists to correspond to any item from the list.
changeMediaType = Expr(
cbEntities << Set Items(aaEntities[cbMedia << Get Selected]);
cbAttributes << Set Items(aaAttributes[cbMedia << Get Selected]);
);
The list used to populate either outline box for a given media type is associated with the key of the appropriate associative array. The keys are the values used in the Media combo box.
searchString = Regex(searchString,"%20","+",Global Replace);
searchString = Regex(searchString,"%2A","*",Global Replace);
The last thing left to do is pull together the user input and send the HTTP request to the API. Everything will be contained in the expression clickRun = Expr(...)
If(Is Missing(searchString),
tbWarning << Set Text("A search string must be given"),
"https://itunes.apple.com/search?" || "term=" || searchString ||
"&media=" || mediaValue ||
"&entity=" || entityValue ||
"&attribute=" || attributeValue
mediaValue, entityValue, and attributeValue can all be taken directly from the combo box text. If all is selected for mediaValue, we can ignore the line. Likewise, if any is selected for entityValue or attributeValue. searchString is required.
searchString = tebSearchTerm << Get Text;
searchString = Encode URI(searchString);
baseURL ||= "term="||searchString;
If(cbMedia << Get > 1,
baseURL ||= "&media=" || (cbMedia << Get Selected));
If(cbEntities << Get > 1,
baseURL ||= "&entity=" || (cbEntities << Get Selected));
If(cbAttributes << Get > 1,
baseURL ||= "&attribute=" || (cbAttributes << Get Selected));
outData = New HTTP Request(
URL(baseURL),
Method("GET")
) << Send;
JSON To Data Table(outData);
The iTunes API returns JSON formatted data which is converted to a JMP data table with the JSON to Data Table function.
A completed version of the recipe can be found below.
Hints for Success:
Don,
In the coming weeks I will be needing the use of REST API statements to access tables in a SQL server database, as such I found your post most interesting.
I followed along and created my JSL script but ran into a problem with the Associative Array see code below.
aaEntities = Associative Array(mediaValues, entityLists);
aaAttributes = Associative Array(mediaValues, attributeLists);I get the following error, see image below.
I'm not sure where to go next to resolve this error, can you point me in the right direction?
The entire code is below, this is untested as of yet, due to the above error.
Best regards
John
Names Default to Here(1);
mediaValues = {"all","music","movie","podcast","tvShow","ebook","software"};
entityLists = {
{"any","movie","album","allArtist","podcast","musicVideo","mix","audiobook","tvSeason","allTrack"},
{"any","audiobookAuthor","audiobook"},
{"any","ebook"},
{"any","movieArtist","movie"},
{"any","musicArtist", "musicTrack", "album", "musicVideo", "mix", "song"},
{"any","genreIndex","artistTerm","albumTerm","ratingIndex","songTerm"},
{"any","podcastAuthor","podcast"},
{"any","genreIndex","artistTerm","shortFilmTerm","ratingIndex","descriptionTerm"},
{"any","software","iPadSoftware","macSoftware"},
{"any","tvEpisode","tvSeason"}
};
attributeLists = {
{"any","actorTerm","languageTerm","allArtistTerm","tvEpisodeTerm","shortFilmTerm",
"directorTerm","releaseYearTerm","titleTerm","featureFilmTerm","ratingIndex",
"keywordsTerm","descriptionTerm","authorTerm","genreIndex","mixTerm",
"allTrackTerm","artistTerm","composerTerm","tvSeasonTerm","producerTerm",
"ratingTerm","songTerm","movieArtistTerm","showTerm","movieTerm","albumTerm"
},
{"any","titleTerm", "authorTerm", "genreIndex", "ratingIndex"},
{"any"},
{"any","actorTerm","genreIndex","artistTerm","shortFilmTerm","producerTerm","ratingTerm",
"directorTerm","releaseYearTerm","featureFilmTerm","movieArtistTerm","movieTerm",
"ratingIndex","descriptionTerm"
},
{"any","mixTerm","genreIndex","artistTerm","composerTerm","albumTerm","ratingIndex","songTerm"},
{"any","genreIndex","artistTerm","albumTerm","ratingIndex","songTerm"},
{"any","titleTerm","languageTerm","authorTerm","genreIndex","artistTerm","ratingIndex",
"keywordsTerm","descriptionTerm"
},
{"any","genreIndex","artistTerm","shortFilmTerm","ratingIndex","descriptionTerm"},
{"any","softwareDeveloper"},
{"any","genreIndex","tvEpisodeTerm","showTerm","tvSeasonTerm","ratingIndex","descriptionTerm"}
};
aaEntities = Associative Array(mediaValues, entityLists);
aaAttributes = Associative Array(mediaValues, attributeLists);
changeMediaType = Expr(
cbEntities << Set Items(aaEntities[cbMedia << Get Selected]);
cbAttributes << Set Items(aaAttributes[cbMedia << Get Selected]);
);
clickRun = Expr(
searchString = Trim(tebSearchTerm << Get Text()); // Remove any whitespace
If( Is Missing(searchString),
tbWarning << Set Text("A search string must be given"),
// ELSE
tbWarning << Set Text("");
baseURL = "https://itunes.apple.com/search?";
searchString = Encode URI(searchString);
searchString = Regex(searchString, "%20", "+", Global Replace); // Replace %20 encoding with + for
searchString = Regex(searchString, "%2A", "*", Global Replace); // Replace %2A encoding with *
baseURL ||= "term"||searchString;
If(cbMedia << Get > 1, baseURL ||= "&media=" || (cbMedia << Get Selected));
If(cbEntities << Get > 1, baseURL ||= "&entity=" || (cbEntities << Get Selected));
If(cbAttributes << Get > 1, baseURL ||= "&attribute=" || (cbAttributes << Get Selected));
outData = New HTTP Request(
URL(baseURL),
Method("GET")
) << Send;
JSON To Data Table(outData);
);
);
dialog = New Window(
"iTunes Query",
Border Box(
Top(15), Bottom(15), Left(15), Right(15),
V List Box(
tbWarning = Text Box("", << Set Font Size(14), << Set Font Style(Bold)),
Space Box(Size(0,5)),
H List Box(Text Box("Search for: "), << Set font Size(14)), tebSearchTerm = Text Edit Box("", << Set Width(450), << Set Font Size14))),
Spacer Box(Size(0,5)),
Line Up Box(N Col(2),
Text Box("Media Type ", << Set Font Size(14)), cbMedia = Combo Box(mediaValues, Eval(changeMediaType)),
Text Box("Entity Type ", << Set Font Size(14)), cbEntities = Combo Box(aaEntities["all"]),
Text Box("Attribute Type ", << Set Font Size(14), cbAttributes = Combo Box(aaAttributes["all"])
),
H Center Box( H List box(Button Box("Run", clickRun()), Button Box("Quit", dialog << Close Window)))
),
Button Box("Run", Eval(clickRun)),
Button Box("Quit", dialog << Close Window)
);