Spotify.NET/assets/js/16b2da92.5fd63768.js
2022-01-25 19:32:34 +00:00

1 line
12 KiB
JavaScript

"use strict";(self.webpackChunkspotify_api_docs=self.webpackChunkspotify_api_docs||[]).push([[9400],{3905:function(e,n,t){t.d(n,{Zo:function(){return c},kt:function(){return h}});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?o(Object(t),!0).forEach((function(n){a(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):o(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function s(e,n){if(null==e)return{};var t,r,a=function(e,n){if(null==e)return{};var t,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)t=o[r],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var p=r.createContext({}),l=function(e){var n=r.useContext(p),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},c=function(e){var n=l(e.components);return r.createElement(p.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},u=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=l(t),h=a,f=u["".concat(p,".").concat(h)]||u[h]||d[h]||o;return t?r.createElement(f,i(i({ref:n},c),{},{components:t})):r.createElement(f,i({ref:n},c))}));function h(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,i=new Array(o);i[0]=u;var s={};for(var p in n)hasOwnProperty.call(n,p)&&(s[p]=n[p]);s.originalType=e,s.mdxType="string"==typeof e?e:a,i[1]=s;for(var l=2;l<o;l++)i[l]=t[l];return r.createElement.apply(null,i)}return r.createElement.apply(null,t)}u.displayName="MDXCreateElement"},1099:function(e,n,t){t.r(n),t.d(n,{frontMatter:function(){return i},contentTitle:function(){return s},metadata:function(){return p},toc:function(){return l},default:function(){return d}});var r=t(3117),a=t(102),o=(t(7294),t(3905)),i={id:"5_to_6",title:"5.x.x to 6.x.x"},s=void 0,p={unversionedId:"5_to_6",id:"5_to_6",isDocsHomePage:!1,title:"5.x.x to 6.x.x",description:"SpotifyAPI.Web",source:"@site/docs/5_to_6.md",sourceDirName:".",slug:"/5_to_6",permalink:"/SpotifyAPI-NET/docs/5_to_6",editUrl:"https://github.com/JohnnyCrazy/SpotifyAPI-NET/edit/master/SpotifyAPI.Docs/docs/5_to_6.md",version:"current",lastUpdatedBy:"dependabot[bot]",lastUpdatedAt:1643139046,formattedLastUpdatedAt:"1/25/2022",sidebarPosition:5,frontMatter:{id:"5_to_6",title:"5.x.x to 6.x.x"},sidebar:"docs",previous:{title:"UWP",permalink:"/SpotifyAPI-NET/docs/example_uwp"}},l=[{value:"SpotifyAPI.Web",id:"spotifyapiweb",children:[{value:"Initialization",id:"initialization",children:[]},{value:"Proxy",id:"proxy",children:[]},{value:"Calling API Endpoints",id:"calling-api-endpoints",children:[]},{value:"Error/Header Handling",id:"errorheader-handling",children:[]}]},{value:"SpotifyAPI.Web.Auth",id:"spotifyapiwebauth",children:[{value:"Authorization Code Auth",id:"authorization-code-auth",children:[]}]}],c={toc:l};function d(e){var n=e.components,t=(0,a.Z)(e,["components"]);return(0,o.kt)("wrapper",(0,r.Z)({},c,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"spotifyapiweb"},"SpotifyAPI.Web"),(0,o.kt)("h3",{id:"initialization"},"Initialization"),(0,o.kt)("p",null,"In ",(0,o.kt)("inlineCode",{parentName:"p"},"5.x"),", a new ",(0,o.kt)("inlineCode",{parentName:"p"},"SpotifyWebAPI")," instance could be created without supplying necessary values, since they were implemented as properties. With ",(0,o.kt)("inlineCode",{parentName:"p"},"6.x"),", necessary values have to be given in the constructor and ",(0,o.kt)("inlineCode",{parentName:"p"},"SpotifyWebAPI")," has been renamed to ",(0,o.kt)("inlineCode",{parentName:"p"},"SpotifyClient"),". Also, ",(0,o.kt)("inlineCode",{parentName:"p"},"SpotifyClientConfig")," has been introduced to give a better configuration experience, including retry handlers, automatic authenticators and proxy configurations."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'// OLD\nvar spotify = new SpotifyWebAPI { AccessToken = "YourAccessToken" };\nvar spotify = new SpotifyWebAPI(ProxyConfig); // No access token - invalid\n\n// NEW\nvar spotify = new SpotifyClient("YourAccessToken");\n\nvar config = SpotifyClientConfig\n .CreateDefault()\n .WithToken("YourAccessToken");\nvar spotify = new SpotifyClient(config);\n\nvar config = SpotifyClientConfig\n .CreateDefault()\n .WithAuthenticator(new ClientCredentialsAuthenticator(CLIENT_ID, CLIENT_SECRET)); // takes care of access tokens\nvar spotify = new SpotifyClient(config);\n')),(0,o.kt)("p",null,"For some performance guides, have a look at the ",(0,o.kt)("a",{parentName:"p",href:"/SpotifyAPI-NET/docs/configuration"},"Configuration Guide")),(0,o.kt)("h3",{id:"proxy"},"Proxy"),(0,o.kt)("p",null,"In ",(0,o.kt)("inlineCode",{parentName:"p"},"5.x"),", the proxy configuration could be passed to the ",(0,o.kt)("inlineCode",{parentName:"p"},"SpotifyWebAPI")," constructor. In ",(0,o.kt)("inlineCode",{parentName:"p"},"6.x"),", they're part of the HTTP Client. The built-in http client supports proxies out of the box:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'var httpClient = new NetHttpClient(new ProxyConfig("localhost", 8080)\n{\n User = "",\n Password = "",\n SkipSSLCheck = false,\n});\nvar config = SpotifyClientConfig\n .CreateDefault()\n .WithHTTPClient(httpClient);\n\nvar spotify = new SpotifyClient(config);\n')),(0,o.kt)("h3",{id:"calling-api-endpoints"},"Calling API Endpoints"),(0,o.kt)("p",null,"In ",(0,o.kt)("inlineCode",{parentName:"p"},"5.x"),", there was one big instance to support all API endpoints. Parameters to these endpoints were passed directly as method parameters. Optional parameters were nullable and could be excluded. In ",(0,o.kt)("inlineCode",{parentName:"p"},"6.x"),", every endpoint group (",(0,o.kt)("inlineCode",{parentName:"p"},"albums"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"tracks"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"userprofile"),") has their own API-Client, which is available as a property in a ",(0,o.kt)("inlineCode",{parentName:"p"},"SpotifyClient")," instance. While URI path parameters are still passed as method parameter, query and body parameters are now passed as a grouped class instance, where required parameters are needed in the constructor and optional parameters can be supplied as properties. All endpoints are also only implemented as async methods."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},"// OLD:\nPrivateProfile profile = await spotify.GetPrivateProfileAsync();\nvar playlists = await spotify.GetUserPlaylists(profile.Id, 100, 0);\n\n// NEW:\nPrivateUser user = await spotify.UserProfile.Current();\nvar playlists = await spotify.Playlists.GetUsers(user.Id, new PlaylistGetUsersRequest\n{\n Limit = 100,\n Offset = 0\n});\n")),(0,o.kt)("p",null,"All required arguments are checked for non-null values. If it's null, the methods will throw a ",(0,o.kt)("inlineCode",{parentName:"p"},"ArgumentNullException")),(0,o.kt)("h3",{id:"errorheader-handling"},"Error/Header Handling"),(0,o.kt)("p",null,"In ",(0,o.kt)("inlineCode",{parentName:"p"},"5.x"),", all response models included a base error model, with properties like ",(0,o.kt)("inlineCode",{parentName:"p"},"Headers"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"Error")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"HasError"),". This was not a good decision since response models should be clean and only contain API response data. In ",(0,o.kt)("inlineCode",{parentName:"p"},"6.x"),", error handling is ",(0,o.kt)("inlineCode",{parentName:"p"},"Exception")," based. For example, if the access token is invalid, calling API endpoints will throw a ",(0,o.kt)("inlineCode",{parentName:"p"},"APIUnauthorizedException"),". If you hit the API too many times, the method will throw a ",(0,o.kt)("inlineCode",{parentName:"p"},"APITooManyRequestsException"),". They all derive from a base exception ",(0,o.kt)("inlineCode",{parentName:"p"},"APIException"),", which is also thrown in more general cases, e.g bad request input parameters. If you're interested in the headers of the last response, you can use ",(0,o.kt)("inlineCode",{parentName:"p"},"spotify.LastResponse"),", ",(0,o.kt)("strong",{parentName:"p"},"make sure there is only one thread using this instance!")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},"// OLD:\nPrivateProfile profile = await spotify.GetPrivateProfileAsync();\nif(profile.HasError())\n{\n // handle error\n}\nvar headers = profile.Headers(); // access to headers\n\n// NEW:\ntry\n{\n PrivateProfile profile = await spotify.GetPrivateProfileAsync();\n var response = spotify.LastResponse; // response.Headers\n}\ncatch (APIUnauthorizedException e)\n{\n // handle unauthorized error\n // e.Response contains HTTP response\n // e.Message contains Spotify error message\n}\ncatch (APIException e)\n{\n // handle common error\n // e.Response contains HTTP response\n // e.Message contains Spotify error message\n}\n")),(0,o.kt)("p",null,"More Info: ",(0,o.kt)("a",{parentName:"p",href:"./error_handling"},"Error Handling")),(0,o.kt)("h2",{id:"spotifyapiwebauth"},"SpotifyAPI.Web.Auth"),(0,o.kt)("p",null,"In ",(0,o.kt)("inlineCode",{parentName:"p"},"5.x"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"SpotifyAPI.Web.Auth")," contained every logic related to the OAuth flows. In ",(0,o.kt)("inlineCode",{parentName:"p"},"6.x"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"SpotifyAPI.Web.Auth")," is only required if you need a HTTP Server for handling OAuth responses. For example, if you're in a ASP.NET environment or just use the ",(0,o.kt)("a",{parentName:"p",href:"client_credentials"},"Client Credentials")," flow, there is no need to install ",(0,o.kt)("inlineCode",{parentName:"p"},"SpotifyAPI.Web.Auth")," anymore."),(0,o.kt)("h3",{id:"authorization-code-auth"},"Authorization Code Auth"),(0,o.kt)("p",null,"As an example, this shows how to convert a ",(0,o.kt)("inlineCode",{parentName:"p"},"5.x")," authorization code flow to ",(0,o.kt)("inlineCode",{parentName:"p"},"6.x"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-csharp"},'// OLD\nvar auth =\n new AuthorizationCodeAuth(_clientId, _secretId, "http://localhost:4002", "http://localhost:4002",\n Scope.PlaylistReadPrivate | Scope.PlaylistReadCollaborative);\nauth.AuthReceived += AuthOnAuthReceived;\nauth.Start();\nauth.OpenBrowser();\n\nprivate static async void AuthOnAuthReceived(object sender, AuthorizationCode payload)\n{\n var auth = (AuthorizationCodeAuth) sender;\n auth.Stop();\n\n Token token = await auth.ExchangeCode(payload.Code);\n var spotify = new SpotifyWebAPI { AccessToken = token.AccessToken };\n await PrintUsefulData(spotify);\n}\n\n// NEW\nvar config = SpotifyClientConfig.CreateDefault();\nvar server = new EmbedIOAuthServer(new Uri("http://localhost:5000/callback"), 5000);\nserver.AuthorizationCodeReceived += async (sender, response) =>\n{\n await server.Stop();\n var tokenResponse = await new OAuthClient(config).RequestToken(new AuthorizationCodeTokenRequest(\n _clientId, _secretId, response.Code, server.BaseUri\n ));\n\n var spotify = new SpotifyClient(config.WithToken(tokenResponse.AccessToken));\n}\nawait server.Start();\n\nvar loginRequest = new LoginRequest(server.BaseUri, _clientId, LoginRequest.ResponseType.Code)\n{\n Scope = new[] { Scopes.PlaylistReadPrivate, Scopes.PlaylistReadCollaborative }\n};\nBrowserUtil.Open(loginRequest.ToUri());\n')),(0,o.kt)("p",null,"While it is more code to write, there is a better seperation of concerns. For example, it is able to construct a ",(0,o.kt)("inlineCode",{parentName:"p"},"LoginRequest")," without starting a server. This ",(0,o.kt)("inlineCode",{parentName:"p"},"LoginRequest")," can also be used to forward the user to in a web-based context. The same auth server ",(0,o.kt)("inlineCode",{parentName:"p"},"EmbedIOAuthServer")," can be used to receive ",(0,o.kt)("inlineCode",{parentName:"p"},"AuthorizationCodes")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"ImplictGrants")," responses."))}d.isMDXComponent=!0}}]);