Framework Modeling Turnkey

Getting data from anywhere- like for example Spotify – that is Oauth2 protected

Number 1 to get a successful integration going is : Read the documentation of the service you want to connect with – also read MDriven wiki and articles like this!

Number 2; remember that security is very often a precision sport – “close” does not cut it and often gives you the same error as “a mile away”.

In this example I will connect as a user (not a server, since a server cannot browse user data, only generic data) to Spotify and use their rest api to get some data that I will persist in my database.

I will also use the AutoForm-functionality in MDriven to get a UI to browse the fetched data with zero effort .

Gaining access

You will need to request an account for the protected service you want to read from. In spotifys case you get a developers account from here https://developer.spotify.com/dashboard/

Once you have that you create an “application” or “client” or “credential” – every service provider seems to call it something new – basically you want the service to become aware of the service you are building. The end goal is to get Client ID and a Client Secret that you will keep safe and private, and you will need to present these to the service at some stages in your integration flow.

image

Above you can see that I have 2 applications registered with the spotify api service, MDrivenRestCase and MDriven2

You can have as many as you need – this level is just to give you a unique key in order to let you in later on.

Starting communication

The spotify documentation states that I must have the user (for which I want to ask the spotify api) to login for me – it is not allowed to browse just any users data – the user needs to offer their consent to give you access.

We must send the user to a page at spotify – and we should send along what we want access for (grants) and how spotify will let us know the session code – if the user allows us to do what we ask:

https://accounts.spotify.com/authorize?response_type=code&client_id=OBFUSCATED394cd100968bd683f&scope=user-read-private user-read-email user-library-read&redirect_uri=’+
SysSingleton.oclSingleton.GetSystemUrl+’DWV?v=SpotifyAccess’

The yellow part: boiler plate and part of the contract with spotify

The green part: my identity as an integrating application that spotify gave me when registering as an app

The orange part: the grants that I want the logging in spotify user to accept the application doing – defined by the spotify documentation

The blueish part: if the user says “ok” spotify will direct the browser to go to the provided address and send along a key that I must use to get further – this key is often referred to as the access code – the url we send in is only a template, spotify will append the code to the end once it actually uses it

Note that we compute the redirect url with some logic and send the result to spotify : SysSingleton.oclSingleton.GetSystemUrl+’DWV?v=SpotifyAccess’

Read up on what SysSingleton.oclSingleton.GetSystemUrl can do for you here: https://wiki.mdriven.net/index.php/SysSingleton_GetSystemUrl , but as you may guess it gives your application address in runtime – if you know it you could just as well have used a fixed string, but it may be practical to defer this to runtime to allow for many environments to use the exact same code.

Further more the sent in url continues with +’DWV?v=SpotifyAccess’ – read more on what the DWV verb can do for you here : https://wiki.mdriven.net/index.php/DisplayWithVariables – basically it will allow you to receive data from the html parameters so that you may use them in your solution.

To do all these steps in MDriven I create a class for a Session and call it OneSession:

image

Then I do ViewModel that is rooted in an object of class OneSession, and a GlobalAction to show this :

image

image


image

I say that the text that comes out of the expression should be treated as a html link in ui – this way the user can click on the compiled link and end up at spotify to enter the credentials – or if spotify finds a valid cookie indicating that the user already did this and it should be considered still valid – then jump right back to us with the code.

image

Spotify will now use the template redirect-url and append it with &code=theaccesscodevalidforthisappforashortwhile

As turnkey gets the call with DWV?v=SpotifyAccess it will look for such a viewmodel and if there are additional parameters – as there will be since spotify append &code=theaccesscode – turnkey will look for a matching viewmodel variable and set its value accordingly.

For this purpose we declare the code variable:

image

Combined it will look like this:

2020-01-27_17h09_05

Get the Access Token from the Access code

Now we have the access code – we now must exchange this for an Access token (this step may seem like a bit of overkill but it is standard Oauth2 stuff ).

I can get the Json containing the Access token with a simple rest Post call if I give all the correct details (it is packed in a json object also called the JWT-token):

accessTokenResult:=selfVM.RestPost(‘https://accounts.spotify.com/api/token’,’OBFUSCATED_CLIENT_IDd683f’,’OBFUSCATED_CLIENT_SECRET3058′,‘HeadersAuth’)

The yellow part is a variable of type string that will hold the returned json

The green part is the client id and secret we got from the app-registration – they will be send as basic authentication as stated in the spotify documentation.

The orange part is the ViewModel nesting class holding the post parameters that we want to send – what they should be must be found in the documentation of the service we connect to:

The bluish part is the address for access token request found in the spotify documentation

image

Note that the we here send in also the value of the variable code – that we got from the redirect after user spotify login.

Putting the above described call in a button and it will look like this:

2020-01-27_17h25_57

The JWT token looks like this:

image

And the property called access_token is the one I want in order to call the api to get any information about the user.

Get your hands on the Access_token so that you can get going

Ok – now we almost have the access_token, I say almost since it is packed in a json formed string – and we need to get its value somehow. Multiple ways to get to content in Json is available in MDriven – I will choose this one selfVM.JsonToObjects(WhatClass,WhatJson) : ObjectOfWhatClass.

It is a common need to unpack Json as data – MDriven has a function to help you with defining matching classes. Copy the JSon so that you have on the clipboard. Then create or pick a class in a diagram – right click and choose “Add attributes, assoc. and classes from clipboard json” – MDriven will populate your diagram to match the json:

image

With the following expression I can now create a new instance of the class DataForAccessToken – and expect all the values from the JWT token to be available in this object.

vDataForAccessToken:=selfVM.JsonToObjects(DataForAccessToken,accessTokenResult)

Using the access token to get some stuff

Finally we are all set to get data from the api. There are loads of possibilities – this will get get the users current tracks with a get:

jsonresult:=selfVM.RestGet( ‘https://api.spotify.com/v1/me/tracks’ ,  ‘Bearer’ ,  vDataForAccessToken.access_token,  ” )

Note that we now use the retrieved access_token as a Bearer token – and this is such a common case that MDriven will understand this if you send in the user as Bearer.

The data comes back as json – and we assign it to the jsonresult variable. It turns out to be a deep hierarchy of stuff:

{
   “href” : “https://api.spotify.com/v1/me/tracks?offset=0&limit=20″,
   “items” : [ {
     “added_at” : “2019-07-25T23:03:21Z”,
     “track” : {
       “album” : {
         “album_type” : “album”,
         “artists” : [ {
           “external_urls” : {
             “spotify” : “https://open.spotify.com/artist/11lfQgLbVZRnR7tbtAnzhk”
           },
           “href” : “https://api.spotify.com/v1/artists/11lfQgLbVZRnR7tbtAnzhk”,
           “id” : “11lfQgLbVZRnR7tbtAnzhk”,
           “name” : “Barcode Brothers”,
           “type” : “artist”,
           “uri” : “spotify:artist:11lfQgLbVZRnR7tbtAnzhk”
         } ],
         “available_markets” : [ “AD”, “AE”, “AR”, “AT”, “AU”, “BE”, “BG”, “BH”, “BO”, “BR”, “CA”, “CH”, “CL”, “CO”, “CR”, “CY”, “CZ”, “DE”, “DK”, “DO”, “DZ”, “EC”, “EE”, “EG”, “ES”, “FI”, “FR”, “GB”, “GR”, “GT”, “HK”, “HN”, “HU”, “ID”, “IE”, “IL”, “IN”, “IS”, “IT”, “JO”, “JP”, “KW”, “LB”, “LI”, “LT”, “LU”, “LV”, “MA”, “MC”, “MT”, “MX”, “MY”, “NI”, “NL”, “NO”, “NZ”, “OM”, “PA”, “PE”, “PH”, “PL”, “PS”, “PT”, “PY”, “QA”, “RO”, “SA”, “SE”, “SG”, “SK”, “SV”, “TH”, “TN”, “TR”, “TW”, “US”, “UY”, “VN”, “ZA” ],
         “external_urls” : {
           “spotify” : “https://open.spotify.com/album/2gHDTP5A75V7oGRtwqIOWN”
         },
         “href” : “https://api.spotify.com/v1/albums/2gHDTP5A75V7oGRtwqIOWN”,
         “id” : “2gHDTP5A75V7oGRtwqIOWN”,
         “images” : [ {
           “height” : 635,
           “url” : “https://i.scdn.co/image/0872f9cca267f2eb85da4cb4a3b9bcc7257865c5″,
           “width” : 640
         }, {
           “height” : 297,
           “url” : “https://i.scdn.co/image/7fd553bb88de2bd52e55d68d5a8037c7011a5545″,
           “width” : 300
         }, {
           “height” : 63,
           “url” : “https://i.scdn.co/image/e4db6b0f9fffe3292ffd715281ec710e1f3dae79″,
           “width” : 64
         } ],
         “name” : “Swipe Me”,
         “release_date” : “2000-01-01”,
         “release_date_precision” : “day”,
         “total_tracks” : 15,
         “type” : “album”,
         “uri” : “spotify:album:2gHDTP5A75V7oGRtwqIOWN”
       },
       “artists” : [ {
         “external_urls” : {
           “spotify” : “https://open.spotify.com/artist/11lfQgLbVZRnR7tbtAnzhk”
         },
         “href” : “https://api.spotify.com/v1/artists/11lfQgLbVZRnR7tbtAnzhk”,
         “id” : “11lfQgLbVZRnR7tbtAnzhk”,
         “name” : “Barcode Brothers”,
         “type” : “artist”,
         “uri” : “spotify:artist:11lfQgLbVZRnR7tbtAnzhk”
       } ],
       “available_markets” : [ “AD”, “AE”, “AR”, “AT”, “AU”, “BE”, “BG”, “BH”, “BO”, “BR”, “CA”, “CH”, “CL”, “CO”, “CR”, “CY”, “CZ”, “DE”, “DK”, “DO”, “DZ”, “EC”, “EE”, “EG”, “ES”, “FI”, “FR”, “GB”, “GR”, “GT”, “HK”, “HN”, “HU”, “ID”, “IE”, “IL”, “IN”, “IS”, “IT”, “JO”, “JP”, “KW”, “LB”, “LI”, “LT”, “LU”, “LV”, “MA”, “MC”, “MT”, “MX”, “MY”, “NI”, “NL”, “NO”, “NZ”, “OM”, “PA”, “PE”, “PH”, “PL”, “PS”, “PT”, “PY”, “QA”, “RO”, “SA”, “SE”, “SG”, “SK”, “SV”, “TH”, “TN”, “TR”, “TW”, “US”, “UY”, “VN”, “ZA” ],
       “disc_number” : 1,
       “duration_ms” : 231986,
       “explicit” : false,
       “external_ids” : {
         “isrc” : “DKBKA0000802”
       },
       “external_urls” : {
         “spotify” : “https://open.spotify.com/track/06MaHjSGleJNvfsugH0mFi”
       },
       “href” : “https://api.spotify.com/v1/tracks/06MaHjSGleJNvfsugH0mFi”,
       “id” : “06MaHjSGleJNvfsugH0mFi”,
       “is_local” : false,
       “name” : “Dooh Dooh”,
       “popularity” : 49,
       “preview_url” : “https://p.scdn.co/mp3-preview/cb2a35fa9334d94af9d22ec482a3195f80d1a7ec?cid=edc3c2acfe634aa394cd100968bd683f”,
       “track_number” : 2,
       “type” : “track”,
       “uri” : “spotify:track:06MaHjSGleJNvfsugH0mFi”
     }

Interpreting the response

Luckily the same MDriven function we used for the access token works with any JsonData – and all properties and associations and new classes are added for us:

image

With this expression I can now transform the JSon-string to objects:

vTrackFetchResult:=selfVM.JsonToObjects(TrackFetchResult,jsonresult)

And to be able to browse all the data I add autoforms for all the classes in the model:

image

Conclusion

In this example I show how to obtain a jwt token from Spotify – and it is more or less the same for all Oauth2 services available.

I show how to retrieve json data from the spotify api and how to use json to automatically expand a model that fits.

I then show how to fill the model with the data from json.

Finally I show how to use the autoforms to gain a UI-access to all the data you have collected.

2020-01-27_18h05_57

The complete work I manually had to do to get here is what is in the ViewModel – and 90 percent of this flow will be the same for any OAuth2 service you want to talk to:

image

Ok but what if…

Now that you have integration infrastructure solved you will probably want to not just add data – you will probably want to update existing data – and merge – remove stuff from your database no longer valid and add new stuff not seen before. You need MDriven Tajson – for more on this read https://blog.mdriven.net/introducing-mdriven-tajson/.

Or maybe you wonder on how to expose your created information as a rest service? For more on this read here: https://wiki.mdriven.net/index.php/Rest_Services_In_MDriven#Exposing_ourselves_as_a_REST_service

Or maybe your use case is more user-centric – how to meet user requirements to pour excel data into your system and extract excel data out from your system. For more on this read here: https://wiki.mdriven.net/index.php/Excel_Plugin_Function

I know that when it comes to exposing information the need of authorization is never far behind – for more on this read here: https://wiki.mdriven.net/index.php/Information_security and https://wiki.mdriven.net/index.php/Access_control_system_in_MDriven

1+

Leave a Reply

Your email address will not be published. Required fields are marked *