Skip to content

Commit

Permalink
Merge pull request #32 from JorrinKievit/feature/bearer-in-v3
Browse files Browse the repository at this point in the history
Allow the usage of a bearer token in v3 endpoints
  • Loading branch information
JorrinKievit authored Jul 14, 2024
2 parents c0a0736 + 544846f commit 37223b1
Show file tree
Hide file tree
Showing 35 changed files with 283 additions and 604 deletions.
6 changes: 6 additions & 0 deletions .changeset/angry-cycles-camp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"tmdb-js-node": minor
"tmdb-js-web": minor
---

Allow the usage of a bearer token in v3 endpoints
19 changes: 7 additions & 12 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"editor.defaultFormatter": "esbenp.prettier-vscode",
}
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,5 @@
"engines": {
"node": ">=18.0.0"
},
"packageManager": "pnpm@8.7.0"
"packageManager": "pnpm@9.1.1"
}
71 changes: 41 additions & 30 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,11 @@ export interface ITMDBAPI {
};
}

export interface Credentials {
apiKey?: string;
accessToken?: string;
}

export interface Http {
get<TResponse>(url: string, accessToken?: string): Promise<TResponse>;

Expand All @@ -637,33 +642,33 @@ export interface Http {
delete<TResponse, TBody = undefined>(url: string, body?: TBody, accessToken?: string): Promise<TResponse>;
}

const createV3Methods = (client: Http, apiKey: string, v3Url: string) => {
const createV3Methods = (client: Http, v3Url: string, credentials: Credentials) => {
return {
account: createV3AccountMethods(client, apiKey, v3Url),
authentication: createV3AuthenticationMethods(client, apiKey, v3Url),
certifications: createV3CertificationsMethods(client, apiKey, v3Url),
changes: createV3ChangesMethods(client, apiKey, v3Url),
collections: createV3CollectionsMethods(client, apiKey, v3Url),
companies: createV3CompaniesMethods(client, apiKey, v3Url),
configuration: createV3ConfigurationMethods(client, apiKey, v3Url),
credits: createV3CreditsMethods(client, apiKey, v3Url),
discover: createV3DiscoverMethods(client, apiKey, v3Url),
find: createV3FindMethods(client, apiKey, v3Url),
genres: createV3GenresMethods(client, apiKey, v3Url),
guestSessions: createV3GuestSessionsMethods(client, apiKey, v3Url),
keywords: createV3KeywordsMethods(client, apiKey, v3Url),
lists: createV3ListsMethods(client, apiKey, v3Url),
movies: createV3MoviesMethods(client, apiKey, v3Url),
networks: createV3NetworksMethods(client, apiKey, v3Url),
trending: createV3TrendingMethods(client, apiKey, v3Url),
people: createV3PeopleMethods(client, apiKey, v3Url),
reviews: createV3ReviewsMethods(client, apiKey, v3Url),
search: createV3SearchMethods(client, apiKey, v3Url),
tv: createV3TvMethods(client, apiKey, v3Url),
tvSeasons: createV3TVSeasonsMethods(client, apiKey, v3Url),
tvEpisodes: createV3TVEpisodesMethods(client, apiKey, v3Url),
tvEpisodeGroups: createV3TVEpisodeGroupsMethods(client, apiKey, v3Url),
watchProviders: createV3WatchProvidersMethods(client, apiKey, v3Url),
account: createV3AccountMethods(client, v3Url, credentials),
authentication: createV3AuthenticationMethods(client, v3Url, credentials),
certifications: createV3CertificationsMethods(client, v3Url, credentials),
changes: createV3ChangesMethods(client, v3Url, credentials),
collections: createV3CollectionsMethods(client, v3Url, credentials),
companies: createV3CompaniesMethods(client, v3Url, credentials),
configuration: createV3ConfigurationMethods(client, v3Url, credentials),
credits: createV3CreditsMethods(client, v3Url, credentials),
discover: createV3DiscoverMethods(client, v3Url, credentials),
find: createV3FindMethods(client, v3Url, credentials),
genres: createV3GenresMethods(client, v3Url, credentials),
guestSessions: createV3GuestSessionsMethods(client, v3Url, credentials),
keywords: createV3KeywordsMethods(client, v3Url, credentials),
lists: createV3ListsMethods(client, v3Url, credentials),
movies: createV3MoviesMethods(client, v3Url, credentials),
networks: createV3NetworksMethods(client, v3Url, credentials),
trending: createV3TrendingMethods(client, v3Url, credentials),
people: createV3PeopleMethods(client, v3Url, credentials),
reviews: createV3ReviewsMethods(client, v3Url, credentials),
search: createV3SearchMethods(client, v3Url, credentials),
tv: createV3TvMethods(client, v3Url, credentials),
tvSeasons: createV3TVSeasonsMethods(client, v3Url, credentials),
tvEpisodes: createV3TVEpisodesMethods(client, v3Url, credentials),
tvEpisodeGroups: createV3TVEpisodeGroupsMethods(client, v3Url, credentials),
watchProviders: createV3WatchProvidersMethods(client, v3Url, credentials),
};
};

Expand All @@ -683,26 +688,32 @@ export default class TMDBAPI implements ITMDBAPI {
v4: ITMDBAPI["v4"];

private client: Http;
private apiKey: string;
private apiKey?: string;
private accessToken?: string;

setApiKey(apiKey: string) {
this.apiKey = apiKey;
this.v3 = createV3Methods(this.client, this.apiKey, this.v3Url);
this.v3 = createV3Methods(this.client, this.v3Url, { apiKey, accessToken: this.accessToken });
}

setAccessToken(accessToken: string) {
this.accessToken = accessToken;
this.v3 = createV3Methods(this.client, this.v3Url, { apiKey: this.apiKey, accessToken });
this.v4 = createV4Methods(this.client, this.v4Url, this.accessToken);
}

constructor(client: Http, apiKey: string, accessToken?: string) {
constructor(client: Http, { apiKey, accessToken }: Credentials) {
if (!apiKey && !accessToken) {
throw new Error("Either apiKey or accessToken must be provided");
}

this.apiKey = apiKey;
this.accessToken = accessToken;

this.client = client;

this.v3 = createV3Methods(this.client, this.apiKey, this.v3Url);
this.v3 = createV3Methods(this.client, this.v3Url, { apiKey, accessToken });

this.v4 = createV4Methods(this.client, this.v4Url, this.accessToken);
}
}
Expand Down
10 changes: 5 additions & 5 deletions packages/core/src/utils/api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const buildV3Url = <TParams>(apiKey: string, url: string, params?: TParams) => {
export const buildV3Url = <TParams>(url: string, apiKey?: string, params?: TParams) => {
const searchParams = new URLSearchParams();
if (params) {
for (const [key, value] of Object.entries(params)) {
Expand All @@ -9,8 +9,9 @@ export const buildV3Url = <TParams>(apiKey: string, url: string, params?: TParam
}
}
}
const urlEndpoint = `${url}?api_key=${apiKey}${params ? `&${searchParams.toString()}` : ""}`;
return urlEndpoint;
if (apiKey) searchParams.append("api_key", apiKey);

return `${url}?${searchParams.toString()}`;
};

export const buildV4Url = <TParams>(url: string, params?: TParams) => {
Expand All @@ -24,6 +25,5 @@ export const buildV4Url = <TParams>(url: string, params?: TParams) => {
}
}
}
const urlEndpoint = `${url}${params ? `?${searchParams.toString()}` : ""}`;
return urlEndpoint;
return `${url}?${searchParams.toString()}`;
};
48 changes: 13 additions & 35 deletions packages/core/src/v3/account.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Http, ITMDBAPI } from "..";
import { Credentials, Http, ITMDBAPI } from "..";
import { AccountAddToWatchlistResponse } from "../types/v3/account/add-to-watchlist";
import { AccountGetCreatedListsResponse } from "../types/v3/account/get-created-lists";
import { AccountGetDetailsResponse } from "../types/v3/account/get-details";
Expand All @@ -24,62 +24,40 @@ const getAccountUrlWithId = (url: string, account_id?: number): string => {
return formattedUrl;
};

export const createV3AccountMethods = (client: Http, apiKey: string, apiUrl: string): ITMDBAPI["v3"]["account"] => {
export const createV3AccountMethods = (client: Http, apiUrl: string, { apiKey, accessToken }: Credentials): ITMDBAPI["v3"]["account"] => {
return {
getDetails: async (params) => {
const res = await client.get<AccountGetDetailsResponse>(buildV3Url(apiKey, `${apiUrl}account`, params));
return res;
return client.get<AccountGetDetailsResponse>(buildV3Url(`${apiUrl}account`, apiKey, params), accessToken);
},
getCreatedLists: async (params, accountId) => {
const res = await client.get<AccountGetCreatedListsResponse>(buildV3Url(apiKey, getAccountUrlWithId(`${apiUrl}account/{account_id}/lists`, accountId), params));

return res;
return client.get<AccountGetCreatedListsResponse>(buildV3Url(getAccountUrlWithId(`${apiUrl}account/{account_id}/lists`, accountId), apiKey, params), accessToken);
},
getFavoriteMovies: async (params, accountId) => {
const res = await client.get<AccountGetFavoriteMoviesResponse>(buildV3Url(apiKey, getAccountUrlWithId(`${apiUrl}account/{account_id}/favorite/movies`, accountId), params));

return res;
return client.get<AccountGetFavoriteMoviesResponse>(buildV3Url(getAccountUrlWithId(`${apiUrl}account/{account_id}/favorite/movies`, accountId), apiKey, params), accessToken);
},
getFavoriteTVShows: async (params, accountId) => {
const res = await client.get<AccountGetFavoriteTVShowsResponse>(buildV3Url(apiKey, getAccountUrlWithId(`${apiUrl}account/{account_id}/favorite/tv`, accountId), params));

return res;
return client.get<AccountGetFavoriteTVShowsResponse>(buildV3Url(getAccountUrlWithId(`${apiUrl}account/{account_id}/favorite/tv`, accountId), apiKey, params), accessToken);
},
markAsFavorite: async (params, body, accountId) => {
const res = await client.post<AccountMarkAsFavoriteResponse, typeof body>(buildV3Url(apiKey, getAccountUrlWithId(`${apiUrl}account/{account_id}/favorite`, accountId), params), body);

return res;
return client.post<AccountMarkAsFavoriteResponse, typeof body>(buildV3Url(getAccountUrlWithId(`${apiUrl}account/{account_id}/favorite`, accountId), apiKey, params), body, accessToken);
},
getRatedMovies: async (params, accountId) => {
const res = await client.get<AccountGetRatedMoviesResponse>(buildV3Url(apiKey, getAccountUrlWithId(`${apiUrl}account/{account_id}/rated/movies`, accountId), params));

return res;
return client.get<AccountGetRatedMoviesResponse>(buildV3Url(getAccountUrlWithId(`${apiUrl}account/{account_id}/rated/movies`, accountId), apiKey, params), accessToken);
},
getRatedTVShows: async (params, accountId) => {
const res = await client.get<AccountGetRatedTVShowsResponse>(buildV3Url(apiKey, getAccountUrlWithId(`${apiUrl}account/{account_id}/rated/tv`, accountId), params));

return res;
return client.get<AccountGetRatedTVShowsResponse>(buildV3Url(getAccountUrlWithId(`${apiUrl}account/{account_id}/rated/tv`, accountId), apiKey, params), accessToken);
},
getRatedTVEpisodes: async (params, accountId) => {
const res = await client.get<AccountGetRatedTVEpisodesResponse>(buildV3Url(apiKey, getAccountUrlWithId(`${apiUrl}account/{account_id}/rated/tv/episodes`, accountId), params));

return res;
return client.get<AccountGetRatedTVEpisodesResponse>(buildV3Url(getAccountUrlWithId(`${apiUrl}account/{account_id}/rated/tv/episodes`, accountId), apiKey, params), accessToken);
},
getMovieWatchlist: async (params, accountId) => {
const res = await client.get<AccountGetMovieWatchlistResponse>(buildV3Url(apiKey, getAccountUrlWithId(`${apiUrl}account/{account_id}/watchlist/movies`, accountId), params));

return res;
return client.get<AccountGetMovieWatchlistResponse>(buildV3Url(getAccountUrlWithId(`${apiUrl}account/{account_id}/watchlist/movies`, accountId), apiKey, params), accessToken);
},

getTVShowWatchlist: async (params, accountId) => {
const res = await client.get<AccountGetTVShowWatchlistResponse>(buildV3Url(apiKey, getAccountUrlWithId(`${apiUrl}account/{account_id}/watchlist/tv`, accountId), params));

return res;
return client.get<AccountGetTVShowWatchlistResponse>(buildV3Url(getAccountUrlWithId(`${apiUrl}account/{account_id}/watchlist/tv`, accountId), apiKey, params), accessToken);
},
addToWatchlist: async (params, body, accountId) => {
const res = await client.post<AccountAddToWatchlistResponse, typeof body>(buildV3Url(apiKey, getAccountUrlWithId(`${apiUrl}account/{account_id}/watchlist`, accountId), params), body);

return res;
return client.post<AccountAddToWatchlistResponse, typeof body>(buildV3Url(getAccountUrlWithId(`${apiUrl}account/{account_id}/watchlist`, accountId), apiKey, params), body, accessToken);
},
};
};
27 changes: 8 additions & 19 deletions packages/core/src/v3/authentication.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Http, ITMDBAPI } from "..";
import { Credentials, Http, ITMDBAPI } from "..";
import {
AuthenticationCreateGuestSessionResponse,
AuthenticationCreateRequestTokenResponse,
Expand All @@ -9,36 +9,25 @@ import {
} from "../types/v3/authentication";
import { buildV3Url } from "../utils/api";

export const createV3AuthenticationMethods = (client: Http, apiKey: string, apiUrl: string): ITMDBAPI["v3"]["authentication"] => {
export const createV3AuthenticationMethods = (client: Http, apiUrl: string, { apiKey, accessToken }: Credentials): ITMDBAPI["v3"]["authentication"] => {
return {
createGuestSession: async () => {
const res = await client.get<AuthenticationCreateGuestSessionResponse>(buildV3Url(apiKey, `${apiUrl}authentication/guest_session/new`));

return res;
return client.get<AuthenticationCreateGuestSessionResponse>(buildV3Url(`${apiUrl}authentication/guest_session/new`, apiKey), accessToken);
},
createRequestToken: async () => {
const res = await client.get<AuthenticationCreateRequestTokenResponse>(buildV3Url(apiKey, `${apiUrl}authentication/token/new`));
return res;
return client.get<AuthenticationCreateRequestTokenResponse>(buildV3Url(`${apiUrl}authentication/token/new`, apiKey), accessToken);
},
createSession: async (body) => {
const res = await client.post<AuthenticationCreateSessionResponse, typeof body>(buildV3Url(apiKey, `${apiUrl}authentication/session/new`), body);

return res;
return client.post<AuthenticationCreateSessionResponse, typeof body>(buildV3Url(`${apiUrl}authentication/session/new`, apiKey), body, accessToken);
},
createSessionWithLogin: async (body) => {
const res = await client.post<AuthenticationCreateSessionWithLoginResponse, typeof body>(buildV3Url(apiKey, `${apiUrl}authentication/token/validate_with_login`), body);

return res;
return client.post<AuthenticationCreateSessionWithLoginResponse, typeof body>(buildV3Url(`${apiUrl}authentication/token/validate_with_login`, apiKey), body, accessToken);
},
createSessionFromV4AccessToken: async (body) => {
const res = await client.post<AuthenticationCreateSessionFromV4AccessTokenResponse, typeof body>(buildV3Url(apiKey, `${apiUrl}authentication/session/convert/4`), body);

return res;
return client.post<AuthenticationCreateSessionFromV4AccessTokenResponse, typeof body>(buildV3Url(`${apiUrl}authentication/session/convert/4`, apiKey), body, accessToken);
},
deleteSession: async (body) => {
const res = await client.delete<AuthenticationDeleteSessionResponse, typeof body>(buildV3Url(apiKey, `${apiUrl}authentication/session`), body);

return res;
return client.delete<AuthenticationDeleteSessionResponse, typeof body>(buildV3Url(`${apiUrl}authentication/session`, apiKey), body, accessToken);
},
};
};
12 changes: 4 additions & 8 deletions packages/core/src/v3/certifications.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import { Http, ITMDBAPI } from "..";
import { Credentials, Http, ITMDBAPI } from "..";
import { CertificationsGetMovieCertificationResponse, CertificationsGetTVCertificationResponse } from "../types/v3/certifications";
import { buildV3Url } from "../utils/api";

export const createV3CertificationsMethods = (client: Http, apiKey: string, apiUrl: string): ITMDBAPI["v3"]["certifications"] => {
export const createV3CertificationsMethods = (client: Http, apiUrl: string, { apiKey, accessToken }: Credentials): ITMDBAPI["v3"]["certifications"] => {
return {
getMovieCertifications: async () => {
const res = await client.get<CertificationsGetMovieCertificationResponse>(buildV3Url(apiKey, `${apiUrl}certification/movie/list`));

return res;
return client.get<CertificationsGetMovieCertificationResponse>(buildV3Url(`${apiUrl}certification/movie/list`, apiKey), accessToken);
},
getTVShowCertifications: async () => {
const res = await client.get<CertificationsGetTVCertificationResponse>(buildV3Url(apiKey, `${apiUrl}certification/tv/list`));

return res;
return client.get<CertificationsGetTVCertificationResponse>(buildV3Url(`${apiUrl}certification/tv/list`, apiKey), accessToken);
},
};
};
16 changes: 5 additions & 11 deletions packages/core/src/v3/changes.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
import { Http, ITMDBAPI } from "..";
import { Credentials, Http, ITMDBAPI } from "..";
import { ChangesGetMovieChangeListResponse } from "../types/v3/changes/get-movie-change-list";
import { ChangesGetPersonChangeListResponse } from "../types/v3/changes/get-person-change-list";
import { ChangesGetTVChangeListResponse } from "../types/v3/changes/get-tv-change-list";
import { buildV3Url } from "../utils/api";

export const createV3ChangesMethods = (client: Http, apiKey: string, apiUrl: string): ITMDBAPI["v3"]["changes"] => {
export const createV3ChangesMethods = (client: Http, apiUrl: string, { apiKey, accessToken }: Credentials): ITMDBAPI["v3"]["changes"] => {
return {
getMovieChangeList: async (params) => {
const res = await client.get<ChangesGetMovieChangeListResponse>(buildV3Url(apiKey, `${apiUrl}movie/changes`, params));

return res;
return client.get<ChangesGetMovieChangeListResponse>(buildV3Url(`${apiUrl}movie/changes`, apiKey, params), accessToken);
},
getTVChangeList: async (params) => {
const res = await client.get<ChangesGetTVChangeListResponse>(buildV3Url(apiKey, `${apiUrl}tv/changes`, params));

return res;
return client.get<ChangesGetTVChangeListResponse>(buildV3Url(`${apiUrl}tv/changes`, apiKey, params), accessToken);
},
getPersonChangeList: async (params) => {
const res = await client.get<ChangesGetPersonChangeListResponse>(buildV3Url(apiKey, `${apiUrl}person/changes`, params));

return res;
return client.get<ChangesGetPersonChangeListResponse>(buildV3Url(`${apiUrl}person/changes`, apiKey, params), accessToken);
},
};
};
16 changes: 5 additions & 11 deletions packages/core/src/v3/collections.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
import { Http, ITMDBAPI } from "..";
import { Credentials, Http, ITMDBAPI } from "..";
import { CollectionsGetDetailsResponse } from "../types/v3/collections/get-details";
import { CollectionsGetImagesResponse } from "../types/v3/collections/get-images";
import { CollectionsGetTranslationsResponse } from "../types/v3/collections/get-translations";
import { buildV3Url } from "../utils/api";

export const createV3CollectionsMethods = (client: Http, apiKey: string, apiUrl: string): ITMDBAPI["v3"]["collections"] => {
export const createV3CollectionsMethods = (client: Http, apiUrl: string, { apiKey, accessToken }: Credentials): ITMDBAPI["v3"]["collections"] => {
return {
getDetails: async (collectionId, params) => {
const res = await client.get<CollectionsGetDetailsResponse>(buildV3Url(apiKey, `${apiUrl}collection/${collectionId}`, params));

return res;
return client.get<CollectionsGetDetailsResponse>(buildV3Url(`${apiUrl}collection/${collectionId}`, apiKey, params), accessToken);
},
getImages: async (collectionId, params) => {
const res = await client.get<CollectionsGetImagesResponse>(buildV3Url(apiKey, `${apiUrl}collection/${collectionId}/images`, params));

return res;
return client.get<CollectionsGetImagesResponse>(buildV3Url(`${apiUrl}collection/${collectionId}/images`, apiKey, params), accessToken);
},
getTranslations: async (collectionId, params) => {
const res = await client.get<CollectionsGetTranslationsResponse>(buildV3Url(apiKey, `${apiUrl}collection/${collectionId}/translations`, params));

return res;
return client.get<CollectionsGetTranslationsResponse>(buildV3Url(`${apiUrl}collection/${collectionId}/translations`, apiKey, params), accessToken);
},
};
};
Loading

0 comments on commit 37223b1

Please sign in to comment.