We flesh out the Spotify api with pure functional constructs to retrieve two sets of related artists.
Let's go ahead and make little Spotify API here. We have both of these, and it's totally OK to go ahead and make what looks like a Spotify class, somewhere else, that's really just a module. We just have a little Spotify module here. We'll go ahead and make that, spotify js. There we go.
Let's save it, and go ahead and grab these from here, pull them out, and paste them here. Looks like we're going to need Task after all, so we have Task. What other dependencies might we need? We need our little Request, here, because we're going to be doing API accounts.
We have our Request and a Task. That's it, for now. Let's go ahead and implement this. I always forget how Request works. Let's go ahead and look that up here. Request npm here. Grab this. It's already there. I look this up all the time. I never remember these APIs.
We grab this here. Just paste it right in. Now, I could use, again, a little wrapper library, but maybe not in this case, because it's a little weird. Let's go ahead and just call this HttpGet, we'll take a URL, and just wrap this ourselves, manually, here. Just go ahead and write URL as our first argument. Takes a little error function. Forget about all that.
Now, if we have an error, we just reject it. Oh? We don't have a reject. Let's wrap it in a little Task here. Reject result, and we can reject the error or resolve the body here. Perfect.
That's all it took. Now, we have a pure HTTP library, to make GET calls here. We'll go ahead and start.
Let's go ahead and say find(artist). What we're going to do here, I should mention, is just export a little object with find(artist), and related artists. That's it. Everything else will be hidden. There will be private methods, hidden from the public, but they have these two composable pieces, to go play with over in the other files.
For our Spotify API, we'll take in a name of the artist. Then, we'll do our HttpGet of our first call here. Here it is. We'll just grab it inside of that, and paste it here. We have our result. That is in this name here. It should be parsed in as the query.
Then, we have our result, which is the artist. With the artist...I'm sorry, it's not in the artist at all. It's actually artists and Items, over here, as your member from the API docs. We have our result. What we'll do is just map over that result, to get the artists, and then the items off of that. That way, we'll be working with the set we want, and we don't need the rest of this information.
Then, finally, once we've got all the artists, we just want the best match. We'll just grab the first one. Of course, we have to write a little first function.
We don't want to do unsafe actions anywhere in our code, so calling Xs.zero might return a null, and this would be very bad for our users. We don't want our users to be hit with a null out of nowhere if they don't find the artist.
Let's go ahead and throw this in a free() null level. We'll go ahead and pull in either. This is from Folktale now, not the one we defined earlier, but same, same idea. We have our first, except now we have a problem, because find(artist) was returning a task of an artist, but now it's returning a task of an either artist.
We know just by what we had sketched out earlier, over here on our index, that we we would like to map, or we would like to chain right into related artists, which is another task, but we won't be able to do that very well with a task holding an either.
Let's go ahead and just chain our either to Task. We'll say, if it cannot get the first thing, we'll just reject this whole Task as a failure. That's just a decision we're making for this one piece. We could have used other things, including [indecipherable 3:32] transformers or traversals and folds, and whatnot, to clear that up.
We'll just go ahead and turn that either into a Task here. Task got rejected. Task got up, and this is that natural transformation that we've seen before. Now we can get the artist. Grab all the items, grab the first item, and turn it into a successful or a rejected task. Let's go ahead and just do the other method, right here, which is related artists, which takes an ID.
This second call up here. We'll just paste this right into that. Sure enough, we have our second call here. It passes in an ID. Then, instead of getting items, just gets that list of artists, and there we are.
Let's give it a shot. Let's see, with all that we've written here and what we're including over here as our basic workflow, we could go see if this is what we expect. Let's run it. Oh, it's a task. Looks like we are mapping into another task, here, which duplicates that, so we can just chain instead.
Now, let's run this. Oh, goodness! That's a lot of output here. It says, "Cannot read property 'Items' of undefined."
Result to artist.items. Interesting. That looks like the output. Let's go investigate. What I can do here is just do a quick cheat here. Once we get back our result, we'll do a map, and we'll get our result here. We'll just do a little console.log, right in the middle, remembering to return the results afterwards.
OK, let's try this again. We want to get rid of that error. Yes, here it is, right above it is the result. We'll zoom all the way to the top. Look at this, the quick list. OK, here we are, and it's starts with artists, and here is Items. so it looks like it should work.
Oh, you know what? We're not parsing with JSON, so we can get rid of...Looks like we haven't parsed it at all, it's just a string here. We can go ahead and JSON.parse() right here, and this should do the trick. Now, I guess we have to do the same for down here.
Parsing isn't very safe. This will throw an error, which gets rid of all the purity and doesn't work well with async, and all of that. Let's go ahead and wrap this in a little "try...catch," and we'll use the Folktale version. We'll call it parse and we'll say either.try JSON.parse(). This is just the way it works in Folktale, but this is just our "try...catch" helper.
We can go ahead and just parse right here.
Then we will turn it into a Task right afterwards. That way, we won't have to worry about eithers. We'll just reject if we cannot parse. This workflow must be the same for this and our related artists, so let's go ahead and pull it into a little function called getJSON.
Then, we'll get take our URL and just run this little workflow here. It's our little HttpGet with a URL, we'll parse it, and we'll turn it into a Task. OK, so, getJSON goes here, and getJSON goes here.
Get rid of all this. Now, it's hopefully just a list of two, and it is. Here we are. We have artists. It's a little hard to look at here, with all these data. All we're really interested in is names. Why don't we go ahead and map over the artists?
Then, we'll go artist.name, right there, and we'll just take a look at what we have here. Oh, undefined. Related artists is actually an array. That's right. That's why I type Helper. It's very good sometimes. We now have artist.name, just like that, OK?
Here we are. We have two arrays of the similar artists, well, the related artists. Our next step, we have to figure out how to take this list of lists and find the commonality. We want to combine these two lists into a new list.
A little bell should be going off in your head, right now, saying, "Semigroups."