Skip to content

Commit

Permalink
fix: stringify array query parameters using the comma format
Browse files Browse the repository at this point in the history
The default format that 'axios' uses for stringifying array query parameters doesn't match what
Spotify's API endpoints expect.
  • Loading branch information
adamgrieger committed Jun 27, 2020
1 parent 04bdc69 commit aaa78bc
Show file tree
Hide file tree
Showing 11 changed files with 44 additions and 44 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@
},
"devDependencies": {
"@spotify/web-scripts": "^7.0.1",
"@types/qs": "^6.9.3",
"husky": "^4.2.5",
"typedoc": "^0.17.7"
},
"dependencies": {
"axios": "^0.19.2"
"axios": "^0.19.2",
"qs": "^6.9.4"
}
}
4 changes: 2 additions & 2 deletions src/apis/AlbumsApi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe('AlbumsApi', () => {
expect(response).toEqual(getAlbumsFixture.albums);
expect(httpMock.get).toBeCalledWith('/albums', {
params: {
ids: 'foo,bar',
ids: ['foo', 'bar'],
},
});
});
Expand All @@ -78,7 +78,7 @@ describe('AlbumsApi', () => {
expect(response).toEqual(getAlbumsFixture.albums);
expect(httpMock.get).toBeCalledWith('/albums', {
params: {
ids: 'foo,bar',
ids: ['foo', 'bar'],
market: 'baz',
},
});
Expand Down
2 changes: 1 addition & 1 deletion src/apis/AlbumsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class AlbumsApi {
const response = await this.http.get<GetAlbumsResponse>('/albums', {
params: {
...options,
ids: albumIds.join(','),
ids: albumIds,
},
});
return response.albums;
Expand Down
10 changes: 5 additions & 5 deletions src/helpers/getAuthorizationUrl.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ describe('getAuthorizationUrl', () => {
state: 'baz',
}),
).toBe(
AUTHORIZE_URL.concat('?client_id=foo')
.concat('&redirect_uri=bar')
.concat('&response_type=token')
.concat('&scope=streaming%20app-remote-control')
AUTHORIZE_URL.concat('?scope=streaming%20app-remote-control')
.concat('&show_dialog=true')
.concat('&state=baz'),
.concat('&state=baz')
.concat('&client_id=foo')
.concat('&redirect_uri=bar')
.concat('&response_type=token'),
);
});
});
7 changes: 3 additions & 4 deletions src/helpers/getAuthorizationUrl.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import qs from 'qs';
import { AUTHORIZE_URL } from '../constants';
import { AuthorizationScope } from '../types/SpotifyAuthorization';
import { stringifyParams } from './stringifyParams';

export type GetAuthorizationUrlOptions = {
scope?: AuthorizationScope[];
Expand All @@ -14,12 +14,11 @@ export function getAuthorizationUrl(
responseType: 'code' | 'token',
options?: GetAuthorizationUrlOptions,
) {
return `${AUTHORIZE_URL}?${stringifyParams({
return `${AUTHORIZE_URL}?${qs.stringify({
...options,
client_id: clientId,
redirect_uri: redirectUri,
response_type: responseType,
...(options?.scope && { scope: options.scope.join(' ') }),
...(options?.show_dialog && { show_dialog: options.show_dialog }),
...(options?.state && { state: options.state }),
})}`;
}
10 changes: 9 additions & 1 deletion src/helpers/spotifyAxios.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import axios from 'axios';
import { spotifyAxios } from './spotifyAxios';
import { BASE_API_URL } from '../constants';
import { paramsSerializer, spotifyAxios } from './spotifyAxios';

jest.mock('axios');

Expand All @@ -27,6 +27,7 @@ describe('spotifyAxios', () => {
Authorization: 'Bearer token',
'Content-Type': 'application/json',
},
paramsSerializer,
url: 'foo',
method: 'GET',
});
Expand All @@ -45,6 +46,7 @@ describe('spotifyAxios', () => {
Authorization: 'Bearer token',
'Content-Type': 'image/jpeg',
},
paramsSerializer,
url: 'foo',
method: 'GET',
});
Expand All @@ -56,3 +58,9 @@ describe('spotifyAxios', () => {
await expect(spotifyAxios('bar', 'GET', 'token')).rejects.toThrow('foo');
});
});

describe('paramsSerializer', () => {
it('should stringify arrays using the comma format', () => {
expect(paramsSerializer({ foo: ['bar', 'baz'] })).toEqual('foo=bar%2Cbaz');
});
});
8 changes: 7 additions & 1 deletion src/helpers/spotifyAxios.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import axios, { Method, AxiosRequestConfig, AxiosError } from 'axios';
import axios, { AxiosError, AxiosRequestConfig, Method } from 'axios';
import qs from 'qs';
import { BASE_API_URL } from '../constants';

export type SpotifyAxiosConfig = AxiosRequestConfig & { contentType?: string };
Expand All @@ -18,6 +19,7 @@ export async function spotifyAxios<T>(
Authorization: `Bearer ${accessToken}`,
'Content-Type': contentType ?? 'application/json',
},
paramsSerializer,
url,
method,
});
Expand All @@ -28,3 +30,7 @@ export async function spotifyAxios<T>(
throw new Error(err.message);
}
}

export function paramsSerializer(params: any) {
return qs.stringify(params, { arrayFormat: 'comma' });
}
20 changes: 0 additions & 20 deletions src/helpers/stringifyParams.spec.ts

This file was deleted.

5 changes: 0 additions & 5 deletions src/helpers/stringifyParams.ts

This file was deleted.

8 changes: 4 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import axios from 'axios';
import qs from 'qs';
import { AlbumsApi } from './apis/AlbumsApi';
import { ArtistsApi } from './apis/ArtistsApi';
import { BrowseApi } from './apis/BrowseApi';
Expand All @@ -24,7 +25,6 @@ import {
GetRefreshedAccessTokenResponse,
GetTemporaryAppTokensResponse,
} from './types/SpotifyAuthorization';
import { stringifyParams } from './helpers/stringifyParams';

type SpotifyWebApiOptions = {
accessToken?: string;
Expand Down Expand Up @@ -150,7 +150,7 @@ export class SpotifyWebApi {
): Promise<GetRefreshableUserTokensResponse> {
const response = await axios.post<GetRefreshableUserTokensResponse>(
TOKEN_URL,
stringifyParams({
qs.stringify({
code,
grant_type: 'authorization_code',
redirect_uri: this.redirectUri,
Expand Down Expand Up @@ -179,7 +179,7 @@ export class SpotifyWebApi {
): Promise<GetRefreshedAccessTokenResponse> {
const response = await axios.post<GetRefreshedAccessTokenResponse>(
TOKEN_URL,
stringifyParams({
qs.stringify({
grant_type: 'refresh_token',
refresh_token: refreshToken,
}),
Expand Down Expand Up @@ -210,7 +210,7 @@ export class SpotifyWebApi {
async getTemporaryAppTokens(): Promise<GetTemporaryAppTokensResponse> {
const response = await axios.post<GetTemporaryAppTokensResponse>(
TOKEN_URL,
stringifyParams({
qs.stringify({
grant_type: 'client_credentials',
}),
{
Expand Down
10 changes: 10 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,11 @@
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==

"@types/qs@^6.9.3":
version "6.9.3"
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.3.tgz#b755a0934564a200d3efdf88546ec93c369abd03"
integrity sha512-7s9EQWupR1fTc2pSMtXRQ9w9gLOcrJn+h7HOXw4evxyvVqMi4f+q7d2tnFe3ng3SNHjtK+0EzGMGFUQX4/AQRA==

"@types/react-dom@^16.8.4":
version "16.9.6"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.6.tgz#9e7f83d90566521cc2083be2277c6712dcaf754c"
Expand Down Expand Up @@ -6674,6 +6679,11 @@ qrcode-terminal@^0.12.0:
resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819"
integrity sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==

qs@^6.9.4:
version "6.9.4"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==

qs@~6.5.2:
version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
Expand Down

0 comments on commit aaa78bc

Please sign in to comment.