30 Days of Python - Day 19 - The Spotify API - Python TUTORIAL

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey there welcome to day 19 and this one we're gonna be integrating with the Spotify API a big part of the reason to do this is to get familiar with integrating with API it's that's one thing the other thing is to see a new way of actually authenticating with a different kind of API that's using base64 we'll talk about that shortly and then we also want to actually see how we can analyze data in a different way and maybe data that you really care about like I would love to know about more songs and more music than I currently do I love music I'm sure everyone does but the idea here is to take Python and help us do all of this let's go ahead and get started all right so good a developer that's Spotify comm is gonna look very similar to this this is where you'll end up working with the API and quite a bit and of course I'm gonna select dashboard here once you go to dashboard you'll be prompted to log in or you'll see something like this my case I already have an app on here so you can create a new app we'll do that in just a moment the next thing is I'm gonna go ahead and open up Doc's and a new tab with control click or command click to be on the system you're on and then inside of these Doc's what we're gonna be using is the Web API I am NOT using the playback SDK and I'm also not going to be analyzing based off of a user the playback SDK requires JavaScript I think that's a little bit more advanced than what we need to do here in 30 days of Python and then the Web API requires an actual web application to authenticate our users we are not going to be doing that we're just gonna be authenticating a baseline application that doesn't actually authenticate users again that's a little bit more advanced and it requires us to have a lot more knowledge on building web applications which you might have you also might not so I'm gonna go with just some basic analysis into some of these actual songs now this analysis of course does it mean that's not going to be useful I think you'll still be useful but that's the gist of what we're going to be covering so make sure that you already have a account on Spotify and then once you do we're going to go ahead and jump into vs code and to make a day 19 folder in here so day 19 and then inside of that folder I'm gonna make a new virtual environment so let's change into that folder and i'm also gonna install jupiter notebooks typically speaking when I work with api's I use Jupiter notebooks it's really a lot faster to be able to test any given end point in fact a lot of things I design with these days is through Jupiter notebooks first and then coming back into you know actually using Python files and interactive Python in the future now I will also show you a way to export a jupiter notebook to a python file so that's also a critical piece to you know building a really sustainable application is being able to have it as actual Python not Jupiter notebooks okay with that being said let's go ahead and do Pippy MV install and again I'm using Python 3.8 and I'm gonna be installing Jupiter and I also will need to install some other things but I'm not gonna do that just yet instead I'll just leave this in as just Jupiter let me go ahead and let that finish and then we'll come back alright so now with that done let's go ahead and activate the virtual environment with Pippy and B shell and then Jupiter notebook before hit enter I'm gonna just tell you that you can do that exact same thing in one line with Pippy and V run Jupiter notebook both of those commands work and you don't actually need to activate the shell to use Pippy and be run okay so with this I'm going to go ahead and make a new folder like I always do and we'll rename this into notebooks and let's rename it correctly no book nut not no bookcase no books okay so the very first one we're gonna just call this off so this is a baseline authentication now what we need to do is go into our dashboard and create a new app so in here we'll go ahead and sit great new app and you have to give it some details so my app is gonna be CFE app - this is a testing app for CFE app I guess the type of thing that I'm building well what I'm gonna stick with is just a desktop application and we'll say next and in this case it's a non-commercial application because I'm just you know testing things out I don't need it to be a commercial application and I'll go ahead and hit submit and then I'll bring you me to here now a couple critical things that we need is the client ID inside of off I'll go ahead and add client ID this of course is very very common next I'll show my client secret now of course if you need to change your client secret just hit reset at any time and it changes so client secret okay so obviously what we need to do is use these two things to actually get some sort of token to then in the future actually you know authenticate with this service so I'm going to go ahead and do the exclamation mark think they call it a she bang pip install requests any Python requests to actually use the API well I don't need Python requests there are other ways to do this but of course I enjoy using Python requests cuz it's super easy okay so next we need to actually use these two items to authenticate with the API so there's there's a couple different ways on how we do this first we have to grab our token so we have to do a lookup for a token this token is for future requests okay so basically we use the client ID and the client secret to get a token that token will expire at some point and then we use that token every time we do our request in the future so it's essentially we authenticate one time it's kind of like when you log into a service yourself you authenticate one time oftentimes with that service without you knowing has a token attached to your session so you're able to actually continuously access that session without logging in we're doing roughly the exact same thing here all right so now we need to authorize our client so to do this let's go ahead and jump into the documentation under Doc's go to general and guides and then in these guides you want to look for the authorization guide and if we scroll down a little bit we will see authorization flows this is a very common thing for api's and clients like ours we have a client that we're building to actually authenticate with each other authorization flows is a common way to do that sometimes it's called authentication in this case it's called authorization flows the reason for that has to do with how a user authenticates with your client and Spotify at the same time there's a way to do that it's a little bit outside the scope of what we're doing here what we're doing here is the client credentials so we actually want the client credentials flow because all that's gonna require if we click on that is our client ID and secret key and then we'll get our access token all right so this doesn't give me any information to our user whether it's accessing or managing their data all it does is gives me general information about the service which we'll see in just a little bit so we'll grab our client ID and secret key but if we actually look at this flow we can see it visualized here this might not make a whole lot of sense but that's essentially how the flow works but if we scroll down a little bit we see that we have our we need to actually have our application request authorization I mean that's the purpose of you know this whole notebook is to do that authorization nanos this right here if you're not familiar this is a URL request no big surprise here and it's a method of host so an HTTP request to be more specific so I'm gonna grab this URL here and let's bring it into our notebook I'll go ahead and call this the token URL and then the method I already noticed the method was post rather host and then if we scroll down a little bit we've got a request body parameter here grant type applying credentials it is required so we actually have to add this in here so what I'm going to do is then I'll call this token data and we want to use what it set forth which was grant type as the parameter or the key and then the value is going to be client credentials hey hopefully no this is like shockingly hard to understand the next part is the header of this post request must contain authorization with this okay let's go ahead and add that in as a new dictionary and I'll call this the token header and it's authorization and then I'll go ahead and grab this whole thing here bang so most of you might have never used a base64 encoded string even if you have maybe you haven't seen it in this format or maybe you just are interested in using the Spotify API and you already know how to do this that then you can skip the auth part I don't assume that you know don't know how to actually create one of these so your gut instinct might be like okay I'm gonna just ignore this base encoded thing and I'm gonna make a the way I know how to make it and cut it string so I'm gonna go ahead and say that my let's put it above this will go above here and I'll say client creds equals two well I see that it's client ID : client secret let's go ahead and just copy this paste it in here and use an F string for this if you hit shift and then curly brackets it will put it at the front and back of that so I'm able to do that um so now I can actually go ahead and use an F string here and put in those client credentials okay so this often works this works for many other services but of course if we try this is going to give me an error it's gonna say that it does not work so remember it said base64 encoded string so I don't think this is actually that complicated but it is a little bit different so the first thing that we need to talk about is bytes in general so if I run this cell here and I want to get the type of this data not with that indentation sure why did that we get a straight okay so to turn this into bytes what we can do is do dot encode that will turn it into a byte string as we see here it's the same data all right so it's it didn't change anything so it's not actually base64 encode it's not encoded other than the fact that it's bytes and of course to decode that any byte string we can just call decode encode decode and this didn't really do anything but that's how you do it so how do you actually turn this into a base64 encoded string so what I want to do is I need to import base64 so we'll go ahead and import it import base64 and now what I'm going to do is say client creds let's call it B 64 equals 2 and now it's base64 dot B 6-4 in code and then we're going to go ahead and pass in these client crits right it's shift enter and again error type error specifically it's saying a bytes like object is required not a string well I passed it in a string all right so I didn't actually change that the type is still string so I just need to encode this into a byte there we go so let's actually take a look at that a 64 encoded string this is a lot different than what I had okay so this is a more secure way to pass these credentials a lot harder to sniff this out specifically I mean it's not possible but it's definitely a lot easier to see oh these are critics t4 encoded string notice that it is a byte so if I actually do type here it says bytes so to actually pass it into my token header I actually have to decode this one so I can pass it in here and then do dot decode here and it didn't decode the base64 string it just decoded the white string that it returned as we can see here right so it's not in bytes I didn't decode it let's take a look at what happens all right so notice that it's now it has a byte string within a regular string that's definitely not what we want okay so we just decode it and then that turns it into a base64 encoded string ready to go so you also might be like well how do i decode a base64 string well I'll just show you an example this so we just use base64 not b64 decode and then the base64 coded string and there we go so we get that same byte string from the client credentials here and that's what's actually gonna happen on their API on the backend side it will do something very similar to this decode that string and then do the verifications that it needs to okay so now that we've got all of that I will leave this in here for you so just for reference to actually just call and do the request I've got everything needed for getting the auth token okay so you can use curl I'm gonna use Python request but this is showing you how to use curl you could do the same data in here on our command line using curl but some of you might be on a Windows machine so we're gonna go ahead and use a Python request here I'm going to go ahead and import requests and come down and its really simple we'll say R equals two requests not post remember this method up here and then our URL which is going to be our token URL and then our data that we're going to be passing is just data Logan data and then our header or headers is going to be equal to touken header let's actually call it token headers we might need to add one potentially so let's go ahead and just print out our JSON hopefully that actually prints out something we refresh and we get an access token here a name expires and 3600 seconds gives you the token type of bearer now we'll we'll use this in just a little bit but the idea here is that we now have our token so I did mention that there might be other headers that we might need I scroll up a little bit you you might actually need to actually pass in these headers from time to time as application HTTP xww form URL encoded you might have to do it you also might not need to in the case of using Python requests I don't actually need to with other libraries or maybe not even using Python you might actually need to actually pass in those headers to make sure it's treated as such so I'll just leave it like this and so now the access token that I'll use is going to be related to that response okay so let's go ahead and say token response data certainly not token data because I have it up here okay so the access token is going to be like that and then expires in so expires I'm going to go ahead and use that same token response grab expires ends now again these are seconds what I can also do is import date/time all right so the the day time object and I'll go ahead and say now equals to date time date time dot now this will give me the exact time of now whenever this request is happening and then all I'm going to do is the expire is going to be instead of leaving like that will say expire in or rather expires in and then it expires equals to now plus date time that time Delta seconds equals to expires in so this will give me a date time object that is relative to now based off of these expiration so if I need to refresh that token I can just check expires based off of this right so like did expire and essentially if now or rather if expires is less than now then it will give me a true or false value right so this is will push it into the future and then if of course expires is in the past then this is a false value and then I'll have to rerun B token itself so that's some of my off I'm gonna go ahead and restart and clear output and I'll just run it all just to make sure it's working now one of the things that I'll probably want to do when I actually implement this is the make sure that my request has a correct status code so valid request is equal to our art our dot status code in range 200 a 299 this of course will give me a boolean value so this will give me a valid request and then I can do all of these other things as well so let's go ahead and just put this down here and fella quest so if L request and we get all that stuff right so that's authentication now we actually need to use that access token for something but I'm gonna go ahead and first wrap this up into its own function in that last part we extracted an access token as well as an expiration so these items are state items or state like items as in they'll change over time so what we want to do is create a class that can respond to those changes so we can make our API calls through that class instead of doing them through functions like we've seen so I'm gonna go ahead and duplicate this last notebook and we're gonna go ahead and rename it the two and I'll save this base API client class okay so inside of here what I need to do is just declare our first class so I'll just get rid of some of these items here and I'll say class and we're gonna give this the Spotify API and it's just an object so you can pass in object you don't need to and there's a couple things that I definitely need and that is the access token I'm gonna go ahead and set that equal to none and then the expiration and I'll also set that equal to none or maybe just expires or rather access token expires because we might need another expiration it's possible and you could set it equal to none or already to a date and time object so date time about date time but now all right so it expires right now so as soon as this created it's already expired essentially ok and then I also might want my client ID for reusability we'll say none and my client secret also say none ok so what I want to do is create a initializer function called init and in this case I'm going to actually pass in my client ID and client secret you can pass in any other keyword arguments if you need and we could just run the initial super init class which is not really necessary in this case but I'll do it because every once in a while you might want to you know inherit from somewhere else so like for example if we wanted to inherit from Python requests perhaps in the future we can just change this class to doing that so that's why I often use super init from the get-go if you're not familiar with this just to go ahead and do that and realize that that can call any class that it's inheriting from itself so that's pretty cool so now with this I will just go ahead and say self dot client ID equals to this client ID and then self dot client secret equals to this client secret ok so I also want to probably have a method for authenticating so we'll go ahead and do define and maybe we'll call it instead of authenticating but extract access token makes itself and then it's going to return something but what it really needs to do is all of this right this and this right here and then finally this Hey so again I'm going to go ahead and add some of these items onto my class object itself so the token URL then the token data and token headers are going to be other methods in here but a fine and we'll say get token header itself will return something and then to find get token data Elf turn something okay so the token data is simple it's just the grant time of credentials here all right and then we want to get the toget headers we have to actually do that base64 stuff again Logan header is going to return that same thing you need to create those credentials how do we do that well I can create another method for that now the reason I'm creating all these different methods is so that I can test each one individually if I need to in the future or you can see where the formatting issue actually happens go ahead and get rid of this and let's go ahead and say get client credentials makes itself and we want to actually put a little note here triple strings and we'll say it returns a base64 encoded string so string is the key part here not bytes so again we'll go ahead and come down and grab our encoding portion here so the first thing is the client credentials string and then encoding it returning the decoded version of that odhh okay so then what that means then and here we will just say self thought get those client credentials and pass that in there okay so of course client ID and client secret have to actually be updated in here so I'll go ahead and say by an ID equals to self-taught client ID and client secret equals to self that client secret will say if client secret equals to nun or client ID equals to none we'll go ahead and raise an exception and say you must set Lyon tidy and client secret okay cool so the next thing of course is going to be actually extracting that token and all that data so we need to put these methods into use methods gonna be course requests post and then all of this data so I'm just gonna copy and paste it just like that and then cut it out and we will now extract it okay I'm gonna go ahead and delete all of these references and I don't think I need them any longer so let's go ahead and hit to lead here and of course the first thing is the token URL which we set on the class itself so self dot token URL right so token URL the token data is well self token data equals the cell type get touken data okay and then the token headers equals the self that get token header headers let's call this token headers again okay so then it will actually do the request and then this valid request line I actually don't need both of those things in there I can just have one response.data now I can just call this data doesn't need to say response data because I have it unique to this is actual method itself let's come in here and just narrow things down a bit so expires well now I'm going to go ahead and set self dot expires Eagles to expire so let's just double check that that's what we called it I have it in as access token expires so if that access token expires here and then one other thing I did not add was access token did expire I'll go ahead and say true as a default so then down here I can say self dot access token didn't expire being equal to you know that and expiration should be greater than that so it will definitely be false okay so perhaps instead of calling this extract access token it should probably call like perform off perform off like perform off authorization or authentication and then here I can return back false like if it's not in that and here I can return back true as in eight data authenticate and it did authenticate fine so I'm actually going to reverse that order and tab this back with shift tab and now what I'll say if r dot status code is not in that range then I'll return false otherwise I'll go ahead and run through here okay so this is now a reusable spotify api object and so let's go ahead and give it a shot so run it notice that it says date and time is done find it's going to make sure I did all those imports so now I'll go ahead and grab that class and say client equals to the are Spotify API remember we need to pass in our client ID and our client secret Hey so now we've got our client seat client in there and then we do client dot perform off the inter comes back and it's true so now I can do client access token and I should see an access token but I don't and that's because they actually didn't set it here so we need to set it as self that access token equals to that access token so let's run all that again and now I actually have an access token okay so this is the base API client class the reason I'm calling it base is because I intend to add to this um like I intend to add something like what will only really be doing is client that search right so you could call client as Spotify instead and of course that will be a little bit more explicit as to how you want this to work but the goal here is to make a reusable client ID and I don't think what we did here is too far of a stretch on creating your own API client now why Spotify doesn't have one of these themselves like why don't they create one I'm not actually sure there's a number of api's that do but it does give us a really nice opportunity to learn how to do it ourselves and realize hey it's not really all that hard now another thing is like well why did I decide on these methods well I wanted something as straightforward as possible right so each one of these functions does one thing and one thing really well the one thing that I probably could still improve on is how I do this perform off in other words maybe this portion right here is like handling a successful authentication and and there's like a handler specifically for that like a function that handles the response data specifically that is called right here instead of what I just did I'm not gonna do that I think this is fine as is but it is something that you could do to improve this there's this baseline API client class that we have but now that we've got this let's go ahead and actually use this access token I will say that there is another glaring problem that I have with this perform off here and that is actually getting the access token itself because if it does expire we want to automatically perform this authentication so I will have to revisit how we access or grab that access token as well and we want to go ahead and use that access token from our API client but before we do let's go ahead and take a look at the documentation on developer that's what apply comm into Docs and then web api and reference so I'm gonna hit ctrl click to open it up in a new tab or command click depend on what system you're on now this is definitely different than the reference for the web playback SDK so the web playback SDK has a bunch of hash tags in front of it and it's definitely driven through JavaScript so definitely do not grab the web playback SDK this is really cool but it requires us to know a la JavaScript I'm and of course that's a little bit outside the scope of 30 days of Python now the web api on the other hand is not this is the one we will be using we'll do some search we'll find some things about different artists albums and all that so this is the API reference that we want to use and we have to actually have that access token to grab these things and of course I don't have access to the user's profile I won't have access to the playlists but the things that I can do is something like search so search is definitely what I'm gonna be focusing a lot on search albums and artists I'm just because it's by far the easiest thing to implement now we've got a search in point here notice it's a get request to this URL here and the things that's required is authorization and this is the token that comes back from that original client authorization which of course we'll talk about in just a moment but that's the only required parameter as far as authorization or authentication goes the next thing is the actual query and the type of query it is so this will certainly be the very first one that we use so I'm going to go ahead and copy this get call here and we'll go into our notebooks and I'm going to duplicate the second notebook that we created and we'll turn it into a use touken use access okay all right so we'll scroll to the bottom and that's actually where we get our access token so I'll go ahead and set it equal to access token and we'll do a kernel restart and run all so how we actually use the access token goes back to the documentation for that guide and the authorization guide I just want to show you where it is because every once in a while you might forget how these things work so you're get the token back and this is the token example here gives you a type of bearer and then you use that bear token instead of basic inside of authorization which I believe is what we use before all right so basic token here and then bearer here all right so the original one is a basic authentication that's how you do your client and then going forward to actually use our token we use the bearer token okay so now I actually have this token this means that I'm going to go ahead and actually do an API call so in this case I'll say header and this is going to be awful authorization and Bearer and then our token which is access token and we put our they're the endpoint we'll be using or the URL we'll be using is that one the data that we want to actually have is q4 query and then I'll just go ahead and say time as in time by hans zimmer which we'll talk about in a moment again in the documentation for that in points for search we see authorization header we've got that we've got the query parameter is a very common used query parameter Q or query either one and we'll talk about how to actually do more robust queries in a little bit the type that I have to put here I actually have to include type as an argument as well so type and in my case I'm going to be using track okay so back in here we've got my data and I'll go ahead and say type is track okay and definitely use the capitalization that they did I actually capitalized the T it should be lower cased I'll probably have an error if it's capitalized okay maybe not it's certainly possible okay so without actually going into too much depth of like what absolutely needs to be happening this is how I do it I grab the bare minimum of things and then I run the request so R equals two requests that get and the end point the data and then the headers let's keep consistent and call that headers and then I'll go ahead and just print out the art of status code so run that I get a four hundred so we do our dot text see what it is and I'm getting alfe formed or a legal request that's all we know so my intuition about this was wrong I actually did incorrect look up here and I actually already know why but this is very common as to how you'll end up doing this so if we look back at the search itself the very arguments for the data as we see that we've got this query parameter here and the type but we want to see is an actual working example of this all right so if I scroll down a little bit I actually see a working example down here okay so the URL right here is actually showing me that I'm not passing additional data but rather I'm passing arguments in to the URL itself so the actual endpoint has the arguments themselves in other words I need to combine these two into one so I'm going to go ahead and call that a lookup URL and we'll give it an F string itself now again your intuition might be oh well let's just combine these two and pass it in so an endpoint and then data and then we want to change our request also have just the URL and the headers much like the documentation is showing us here with curl even if you're not familiar with curl you can see that it says curl get there's only a URL here and then there's only the header data here there's not something for the data itself like the data is right in line with this call um so what that means is that we could try this again and I'll go ahead and print out vlookup URL and I run it again and this time it says a 404 so that means page not found as we see the text is now actually JSON so I can use JSON again and they'll say service is not found so of course I need to actually realign how this URL looks because that is not how you actually pass URL parameters at all so what we can do is use a library called URL encode and this is it right here so you'll do from URL live dot parse import URL encode and this URL and code library we can just wrap around a data dictionary and that will actually turn it into your a URL ready string as we can see by passing it this time as you see it now says Q equals the time ampersand type equals to track and if you have a very long dictionary with a bunch of key value pairs it's gonna have all of those items in there so in order for this to actually work on a URL because it's still not working is we actually have to use a question mark on here okay so question mark and then our URL encoded string or you are encoded data so with that I can go ahead and run it this time actually get a response so I go ahead and do JSON and there's my response of that data right so I can actually continue to do stuff like this so if I copied this same data I'm gonna leave that authorization header up there but just change a few things for this data perhaps I don't need the endpoint either I'll just change the requested data and I'll print out the our JSON I don't even look up stuff anymore okay that I want let's go ahead and just try a another one and we'll go ahead and say a Lannister always pays his debts we're on that one and there we go we get some tracks in here we'll take a look at that data a little bit more later but that's how you can quickly and easily search anything on Spotify and it gives you back the actual data from there so we've successfully now authenticated and worked with the API from here on out it's just a matter of parsing through a lot of this data making a little bit more efficient and then maybe even going through the documentation yourself and trying to find different things that you might be interested in like artists for example this might be another one that you want to go and take a look at so the endpoints for this are certainly different than the search but not a whole lot different one of the main differences here for this individual resource of artists like you want to get one single artist this one says you are gonna be passing in an ID well how do you actually find an artists ID well it comes back to doing that search which is something we want to make a little bit more robust and that's why I started with search in the first place and using this access token but really I don't actually want to copy and paste this code over and over again really what I want to do is make my clients better and actually have some convenience methods to just do that search in general and then also you know handling our authentication token if it expires - alright let's go ahead and create a resource enabled client and of course building off the needle lasts a notebook I'm gonna go ahead and duplicate it and we will rename this one or resource enabled client okay so what this means is I just want to have a search method in here so define search okay so this search method I wanted to actually perform in that exact search that I did before which was all of this okay so to do that of course I'm going to go ahead and grab this and access token is that first thing that'll need to get so I'm gonna have to do self dot get access token something along those lines so the get access token actually is very similar to you know this perform off here except this perform off is not actually getting the access token so what I need to do is I need to actually run a another method to get the access token and if the access token exists and hasn't expired will return it if it doesn't exist or it expired then we'll run perform off again so let's go ahead and do that I'm gonna define get access token it's gonna take in itself and it's gonna return something so by default I'm just going to go ahead and say do off and it's gonna be self dot perform off and if well let's actually change it from do off to off done so if not off done then we'll go ahead and raise an exception and we'll say authentication failed okay and then assuming that it doesn't fail then we can go ahead and say we can grab this access token we can also grab when it expires the token we don't need to call it access token and expires the reason I don't need to call it access token is because this whole method is all about the access token so that's going to be the token that I want and all we need to do here is set a now equaling to date time date time dot now and if expires is less than now then we need to self dot perform off and then we'll return the exact same method here now you will see that there's a little bit of a loop which we'll talk about in a second okay so self not perform off call that otherwise we'll return this to this token okay so realistically this right here we we don't we don't actually need okay I just showed you that that it might be a method that you end up wanting to do because it's gonna be performing off but really this is going to perform the authentication here and if it is false perhaps the actual raise exception should actually happen inside of perform off instead of returning false so I'll go ahead and just say raise exception not authenticate quiet okay so then that means then in this get off token here to look for the token it's gonna check whether or not expires and then it's going to compare it at a expiration from now okay it's gonna run this we also want to say L if token equals to none then we want to return the same loop here okay and then finally we'll go ahead and return that token so now that we've got that we will pass it in with our headers and then we'll perform our search so let's go ahead and add in the parameters we want which this case is going to be query and then let's look at the search documentation again or this is called type and I actually want to call this is search type instead of type because as you know type itself is a Python a built-in Python operator and in this case I'll just go ahead and say artist as my default itself I'm going to add it into this URL and code instead of the default that I had the search type going to come in here in points the same and then we'll go ahead and say if our two status code in range 200 and 299 will want to return back the actual data which would be our JSON otherwise we'll return back an empty lookup so typically what I do is actually reverse this logic here and if it's not in that range then I return back that empty dictionary otherwise I returned back the JSON so if status code not in range 200 to 99 which really should just be a 200 call but this is just a more of a catch-all there so now I have my search of course I haven't actually verified that this portion is actually working so let's go ahead and give it a shot I'm gonna restart and clear the output and then instead of perform off I'm gonna go ahead and do search and the query itself will again be time and the type or rather the search type is going to be Trek Hey so I'll get rid of all of these other ones but edit delete cells and let's run all of the imports that we need and I'm getting a search type with time coming back as this empty dictionary here okay so let's go ahead and see why first off I'm gonna go ahead and print out this lookup URL okay so we've got a capital T track so just to be safe I'm just gonna always say lower on that search type and there you go all right so again making sure that the actual type that we're doing is lowered the query I don't think has to be lowered that it can be upper case or lower but the actual type the search type itself needs to be lowered that's just something I found through my research so we just supposedly do that there we go now we have a way to search for things so what I want to do is actually add a couple more attributes to this that I know I'll probably want so the first thing is going to be like to find get album and it's going to take in itself and then some sort of arguments which I won't put yet I'll say pass and then maybe I'll also go ahead and grab the artist forget artist and then any other resource on the guide that I might me so of course you could go in through the API and find all the different ones that you might want to have now of course artist and album are up there with exactly what we want so I'm going to go ahead and go into the albums and I see here's the base URL all right so it's the exact same base URL that we've been using now you have a few different parameters in here related to that base URL so you've got the album itself that passes an ID the album tracks which has the ID and it gives the tracks in return and then the album's themselves right artists very similar ID and then their albums and and so on of course there's another resource for tracks very similar there's another one for track itself an individual track with the ID so so what I'm gonna be focusing on is just a single you know lookup for one album one artist and so on but the methodology that we're using can be applied across all of these other things so going back in here for the artist and album the individual item we're going to get the actual ID for this resource so I'm going to use underscore ID and underscore ID okay and then what I what I want to see in the documentation is exactly how it's done so first we've got the base URL here that appears to be the same for both album and artist so I'll go ahead and just say base URL and we paste this in both places make sure I got that correct and then the next thing is the artists slash ID so I can actually copy all of this notice is that V ones there but it's also here you don't put V one twice you just put it one time so the actual URL the end point ends up being more like this it's getting rid of that that ends up being the actual end point and then we will pass the underscore ID that we pass into the argument this actually ends up being the artist end point itself and realistically the album one isn't any different so as you already see possibly is a pattern of how these lookups work for artist and album a search is certainly I'm not a whole lot different but the biggest difference with search is it has this encoding of data so we actually add a bigger and more robust URL in general but these are the two end points so realistically what I want to do is create a new method here and I'm going to call this get resource and it's going to be self and then the ID itself so underscore ID and then the resource type now by default I'll go ahead and say albums and this is just how I'm gonna go ahead and do it I'm gonna bring all of these things together so I'll have his base URL I'll just make it one URL string I don't I don't actually need multiple URL strings for this Hey so I can also pass inversion so I'll just leave that version in there just in case if the API version does end up changing we can change that resource version pretty easily so we're going to pass in that resource version B resource type and then finally that ID or the lookup ID right so let's call this the lookup ID instead of just ID and then this is where we want to grab our authorization header token so all this stuff so now I need to actually come back here and say not just the token but to find get access header make sense elf we could also say get resource header so this is the headers that we actually want for all of our resources so the get resource call and the search call so I'll go ahead and grab these two things here bring it up into this resource header and then we'll just return these headers okay so now down in here I'll go ahead and say headers equals to get South get resource header and then our equals two requests that get at endpoints and headers equals to headers and then if our status code not in range 200 to 299 we'll just return an empty dictionary otherwise we'll return our JSON so then that means get album we'll just call this it'll just be literally return self-thought get resource and then the lookup ID is just going to pass in that ID the resource type I'm going to be explicit and say albums and then the version is still v1 so I actually don't need to change that version at all so I'll leave it out okay and then with that I can use that exact same thing inside of get artists and this time the resource type is artists okay and then my search method I can change my actual headers to being exactly like we just did with get resource row headers equals to self thought get resource header okay so now in theory we'll be able to use all of this go ahead and give it a shot so I'll reinitialize this class here reinitialize the API do a search I get a search here notice that I've got artists in here looks like this might be an artist ID I believe that it is so let's go ahead and try that and I'll just go ahead and say Spotify get artists passing that ID and there we go if I actually get an artist there this artist doesn't have all their albums here which is fine but it does have who they are so we've got hip hop hop rap and so on and so the actual artists themselves name is NF not really sure who that is so that's probably not who I was intending to look for so let's go ahead and do a Lannister always pays his debts this time it's Ramin Djawadi that is definitely the person I'm looking for sorry if I pronounce his name wrong that's how I always pronounce it but now I can actually get that artist and there is and then the album let's go ahead and find that album not there it's gonna be after available markets from that first look up and here's the name that looks like the name of the album there and this looks like the ID no that's not the ID for that album this is the ID right here and we even get the actual URL for that album right there so we're actually calling that same URL and so now I'll do Spotify that get oops Spotify get album and now I can actually look up that exact same album so cool so now our resource enabled client is there right so we have a few different resources of course you could take these a little bit further and perhaps you would even have a sub class for artists themselves right so you might even take this even further by making another object specifically for artists and for albums so you can get all of the data about it but I just want some baseline data here I do actually want to improve the search feature because I want to have more than just a some sort of query I want to have a more robust query in there so that's something we still do now we're gonna make our queries a little bit more robust that is we're gonna actually include a artists name and the track name at the same time and be able to do a search like that and a few other things so let's go ahead and copy our last notebook and we'll rename it and there's going to be five robust we research and this up and I'm gonna restart and clear the output for all of these actually no longer need requests at the top here any longer by all means delete that okay so what do I need to do is update how this portion works but really it's all about the query itself so I need to be able to adjust how this query is happening and I needed to actually be able to handle a more robust query than just a string in other words I need to be able to pass in a dictionary here very similar to this but just slightly different so what I'm gonna do actually is create a nother method called search and then I'm change this method to being base search okay so in this method I'm gonna actually this is how I'm going to set up the query itself so the search query here is really going to be the query parameter query so I won't be doing this data in code here but instead I'll be passing in those query params and the data in code will be happening down here so we'll say self and query equals to none okay so with that that just means that my final result will return self dot based search and the query whatever that data ends up being right so the search sighs I still absolutely want to include that up here as well right I don't actually need it in the base search any longer because we don't need a URL and code it's up there I just need it up here okay cool so this is the same same exact thing but now what I want to do is a couple things number one if query is none I give it stays none I'll go ahead and raise an exception and say a query is required a big deal there next I want to say if is instance query and dictionary then I want to actually handle that as my query okay so as of now I'll just go ahead and leave it in as a string because let's look at the documentation as to what it is that I'm trying to accomplish with this little block so looking in the search documentation for writing a query guidelines there's a number of things that we need to do here notice it does say in encode in spaces so if we look at the documentation for a search resource or endpoint we can see that there's writing a query guidelines now this is actually really interesting it will help you design better queries overall I'm going to be doing some of the basics of this but I think it's important to include it because we want to get the best results we possibly can even with just some simple querying so the first thing is notice that it says encode spaces and of course this is something we do with that URL encode method that we imported that function up here that was made to actually change all of the data into the percent 20 or URL encoded spaces so the next thing is keyword matching this is not exactly something we will do just yet or the operator stuff but instead what we're gonna do is the field filters and what this will allow me to do is pass in key value pairs that I'm looking for specifically right so like I want a specific album the album name and then a specific artist and the artist name and I want that returned in an album or the same things true with a track so I actually want it with I'm going to do an example of it with using a track but the idea is that I'm now gonna pass the query a actual dictionary or a string so either one right so getting comments out the artist related stuff so in here the track go ahead and say is a Lannister always pays his debts and then the artist is I'll just go ahead and say Romijn and the search type I'll give or the response that I want is not a track but rather an artist this time okay so I want to know who the entire artist is now this is a pretty pretty specific song so it probably will get the search really accurate but that's not really the point the point is how do we convert this into a query parameter that it actually s for so what it asks for is to separate the key value pairs by a colon so here's the key here's the value percent 20 is space as it mentions up here but that's how URLs like the web browsers actually do spaces so if I go to any given page at the end of it and do a space and hit enter notice that it does percent 20 there let's go back it so we've got our key value pairs as key value colon and so on and we already know that URL encode will do those percent signs for me and it also does the an ampersand for me as well or does it do the percent twenty I don't know that's a good question but let's go ahead and actually go into our back into our notebook here and what I want to do is now turn this query into a string because the query is an instance of a dictionary so that means it is a dictionary so I need to update that query so the final results of that query to being a string itself so what I'm going to do is a space bar here - empty space got join and I want to join what will end up being a list so to turn a dictionary into a list if you're not already familiar it goes like this so key you can do ki RK V this is going to be a string substituted item here and then it's for K comma V in a dictionary so in this case query not items and what that will do is loop through all of the key value pairs and then set the item or each iteration a a new item in the list itself that will give me that list in line and of course you could break this out so you don't have to do it in one line but that's essentially how it works if you're not already familiar with that hopefully you are okay so why did I add this space in here well I already know that URL encode will encode that space as it needs to or at least I'm pretty sure it will so I'll go ahead and print that out so now that I've got that let's go ahead and try this search here let's go to make sure that I've got everything imported and ran every cell ran we run Spotify and we do a quick search here and the URL encode didn't do percent 20 I just did a plus instead which is fine that's the same kind of URL encoding that you can use if you wanted percent 20 you could just put or sent 20 here and what that join will do is take either side of the list or every single item in the list and join it like that but I like using the space because then instead of relying on what I remember about how to do this encoding I just use a package that does the remembering for me so your own code is one of those packages of course this is not actually a very good search anyway like you're likely not going to be searching an artist by a track name I mean you might but realistically what you would end up doing is actually searching that track maybe with the artist in there and then saying search type is track and then that would give you the artist that you're looking for as in at least it's inside of one of those track results and of course earlier I also was looking for a track called time and I didn't have an artist in there just yet and I did a search and you know Billy Elish was one of the first ones that came up now you might be looking for Billy Elish in my case was looking for a different artist and you know perhaps you forgot the artist name so you could also try and actually guess what the artists name is and I'll just say Hans that question mark was an accident did Hans and it actually gives me back hans zimmer that's the artist that i was actually looking for well let's say for instance I forgot that and I wanted a search time but I did not want to search Billy eyelash like I want to remove that from result this is where operators come in so you can actually pass in a operator and by default they'll say none and then I'll also add in a operator query and also say none so right below this is instance I'll go ahead and write out if operator it's not equal to none and operator query is not equal to none then I'll go ahead and do this now first and foremost I'm going to just assume that operator is a string so go ahead and do operator equals to operator dot upper this will make it a capital I string this is actually very apparent in the ER documentation it says operators must be specified in uppercase really it can only be or or not I believe those are the only two operators that they have at this point maybe and is one of them but it's probably just or or not so then I'll go ahead and say if operator equals to or or operator equals to not so I want to actually do operate it up lower just to verify this Paul so he wanted one of those two things okay so now I'll actually make sure that that operator is the uppercase version next is the actual query so I actually want the query the operator query to be is an instance of a string this same query this robust query here does not work as far as my Tesco with the operator query itself so then I just update my final query to be in query the string of query and then the operator so I'll just go ahead and use that space there so the operator here and then finally the operator query okay No so now I'll go ahead and run this that search still works let's go ahead and copy that I'll put another one down here this time I'll go ahead and say the query equals to time operator equals to not and then the operator query equals to Billy Elish I do a search and I'm getting nothing back okay so it's still looking for that search type so in this case not actually coming back because it's looking for a track that has a name of time and not Billy Elish and so perhaps the actual encoding for this operator was done incorrectly which is something we could try out or what I could do instead is use specific songs so song names or song titles and in this case let's say danger not zone and take a look at the response for that we get juice world a different song here because really if we search for the query without an operator of danger zone Kenny Loggins comes up first so what you're gonna want to do is when you're doing these operators is think of it in terms of matching queries right so if you're looking for one artist and not another artist that's what you would search not what I did before were it was a song name and then not by this specific artist perhaps was a way to exclude that artist but that's starting to get a little bit too advanced it's just really nice to know that there are more advanced searching features that are in here and we just covered a few of them right and I would imagine that Spotify has API is going to get better and better over time and I would also imagine that your search will improve based off of the access token that you're using so I believe that the relevance goes up if you actually have authenticated users in there I didn't find documentation on that itself but it would stand to reason that if you're using an access token from an authenticated user that it would actually give better search results for what that user would be more likely to be searching versus just general search results that might not be true I might be assuming a lot here but Spotify itself works that way like what I search for on my Spotify versus yours is gonna be drastically different results based on our own preferences and all that and I think this search function it stands to reason this search function would be would be a good example of that cool so we now have a very or a lot more of a robust query searching the operator thing I don't think you would use a whole lot so of course now it's like we need to be able to parse all of this data out and do all that I think that's beyond the scope of actually just building this client but what I want to do is polish this off and turn a Jupiter notebook into a Python file and have it be so I can import it and consistently use it not just open up Jupiter notebooks but rather being share it across all of my different Python projects and then all I would need to do is just change the client ID and the client secret now let's go ahead and actually convert any Jupiter notebook to a Python file it's pretty simple at its core but if we want to automate it it takes a little bit more effort so I'm gonna go ahead and duplicate the last notebook that I created and I'm gonna rename this to Spotify client the reason I'm doing it this way versus how I did with the other ones has to do with the pipe the Python file results the thing that I actually want this to be called at the end of the day is going to be Spotify client PI so I'll leave it in as Spotify underscore client rename it as that we'll open this thing up and now what I want to do is actually delete all of the things that are related to the notebook so all of these examples that I ran I want to delete those so go ahead and hit edit delete cells and then also the client ID and secret I want to go ahead and delete that and then all of my imports I'm gonna go ahead and put at the top and I'm gonna just reorganize them to the built-in Python features and then I thought requests and I'll go ahead and delete this cell and there we go okay so this is our baseline actual client itself so what I want to do is actually export this client of course I can do file and then download as and then Python this will download it as a Python file course you're gonna want to keep it and there we go we've got our spotify client but that's not an automated way to do it and I don't made a way to do it would be using something called in be convert so notebook convert so with that's still running them open up visual studio code and open up a couple new Python windows here and we'll just do Pippy and V shell close down the Explorer for a moment and still in day 19 here I'm gonna go ahead and do Pippy and the install and B convert to NB convert I'll let that install and I will just open up the PIP file so we can see that that's now one of our requirements there's mb convert so with this will allow me to do is just run a simple command to actually create a jupiter notebook sorry rather create a python file from Jupiter itself the command is Jupiter MB convert - - to Python and then the actual document that I want to change so mine was in notebooks slash and it was Spotify client top iy i py and be and enter that should actually create the client for me you know created inside of notebooks so if I CD into notebooks I see that I have that Spotify client in there again I can remove that and run that again so again the command let's go ahead and break these down a little bit the command again is Jupiter MB convert - to Python and then the client that I want to use now I'm in the same client same location as this one so I can just copy and paste it and there it converted it so there it is I can also use this command to just do all of my Python notebooks by using a star here oops we want to make sure there's a space in between that and that literally converts all of them of course I don't actually want all of them but that is a way to do it so with that in mind let's go into day 19 and I'm gonna go ahead and delete all of those recently created Python files so let's go ahead and go reveal this in finder or the File Explorer depend on what you are on and then we'll organize it by kind and then we'll throw those all the way okay cool and going back into our Python shell here so in our project what I want to do is I want to make a new script file here and I'll just call this convert dot Sh if you're on when if you're on Windows you're going to be doing convert at ps1 the command is just here for reference and it's Jupiter Mb convert to Python and then in this case I have it remember it's in the root of day 19 so it's gonna be notebooks slash and this is the Spotify client pi okay so maybe convert Spotify client that in both of these files here and I'll do see the into it PWD show mod + X this is for Windows and Mac users or rather Mac & Linux users not Windows users do the SH and then convert the SH and it's giving me a it's not actually finding this this call here but let's try that again by running it there not allowing me to run this oh yes because I put this in as dot py hey so you caught that but it's you know we got to convert the actual notebook file not a Python file so let's go ahead and try it again and we run that and bears are converted client pretty cool but what I actually want is to add in - output - dirt and I'll do dot slash and we'll go ahead and say clients or rather client okay and I'll put this into ps1 as well wait we actually might want this flag at the front just to make sure that all the flags are front and then the final notebook source is at the end it's going to run that again and that time it actually did it okay so if you were to call this somewhere else like say in a notebook oh well you totally could so let's go back into the Jupiter notebooks and of course in the Spotify client if you call it in here that will also be exported the actual call will be exported as well we don't want to do that so instead I'll just go ahead and make another notebook and I'll just call this six export client and it's going to be calling the exact same thing and this time the output Durer is dot dot flash right so one directory behind and then to that output windows you might actually have to use that slash I don't think so but you might so let's go ahead and try that again with the shebang or the exclamation mark first actually maybe that's not called shebang and I remember anyway so we do this of course it's not in notebooks anymore it's now local well nope and now it's exporting looks like it's done we can come in to whether it's in Jupiter and looking in the client or its MVS code so again if I delete this directory here and come back into export client the actual docx or the notebook itself there's another way to do it okay so yeah and you can also run Jupiter notebooks themselves so you could automate automatically run this notebook where it converts it as well but again I showed you a few different ways on how you can convert it to a Python file automatically I think that's important when it comes to building clients you test it out in a Jupiter notebook you do that over and over again you don't have to I mean at this point we we definitely don't have to test it out on a Jupiter notebook and also another thing you can do is inside of your Jupiter notebook or any given notebook we can import that client as well all right so now I can go seven and let's say import client so I think I have one in the same directory that I'm in looking at new notebooks here I do have one right here so I can just do from Spotify client import all and that shouldn't run an error and just like what we saw with this robust query search I'll go ahead and actually use that client so I give the client ID and secrets and then I just initialize it then I can use it just like we've seen over and over initialized used cool so that is how we work with the Spotify API and hopefully this also showed you how to build your own API client now the one that I created absolutely can be used by anyone now you just need to change this stuff that's it this is an example of how it could be used by literally anyone and when it comes to working with api's this is a method that I would recommend you do is try to make it as usable by anyone because then you and a year from now if you need to reuse this you can look at all your API clients and be like oh yeah that one's really easy to use I just pass in a client ID and secret and boom it's ready to go right that is definitely something that you are going to want to do as you're designing more and more of your API and now Spotify doesn't have one or at least not that I know of I'm sure there is a Python client library for Spotify that's really good that's not necessarily Spotify made but somebody else made it that might be the one you actually in abusing instead of what we did here but the idea of this is to actually get deeper and deeper into actually building your own API clients so you know exactly what's going on the other thing about this is if you rely on somebody else's API client and they stop supporting it as in they don't improve it on you might be a little bit lost or your application might be at risk potentially I mean that that's also likely not gonna happen because somebody else might pick up the slack and then you can also copy a lot of these open-source clients anyway but I also like to have a really fundamental understanding of how to build my own API clients if for some reason the other ones go down it's not always the case but it is sometimes is so thanks so much for watching day 19 hopefully got a lot out of this please let me know if you have any questions or you'd like to see more with the Spotify API
Info
Channel: CodingEntrepreneurs
Views: 60,299
Rating: 4.9823008 out of 5
Keywords: djangourlshortcfe2018, Mac OS (Operating System), Python (Software), web application development, installing django on mac, pip, django, beginners tutorial, trydjango2017, install python, python3.8, django3.0, python django, web frameworks, install python windows, windows python, mac python, install python mac, install python linux, pipenv, virtual environments, 30daysofpython, beginner python, python tutorial, spotify api, python spotify, rest api, python rest api
Id: xdq6Gz33khQ
Channel Id: undefined
Length: 85min 50sec (5150 seconds)
Published: Sun Apr 26 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.