type declarations for movies integrations; cleanup

main
Inga 🏳‍🌈 11 months ago
parent b8f3cac3fc
commit 7a18087a1b
  1. 6
      src/integration/movies/internal.spec.ts
  2. 9
      src/integration/movies/internal.ts
  3. 54
      src/integration/movies/omdb.spec.ts
  4. 29
      src/integration/movies/omdb.ts
  5. 77
      src/integration/movies/types.ts

@ -1,9 +1,9 @@
import { describe, it, expect } from '@jest/globals'; import { describe, it, expect } from '@jest/globals';
import { createLocalMoviesClient } from './local'; import { createInternalMoviesClient } from './internal';
describe('createLocalMoviesClient', () => { describe('createInternalMoviesClient', () => {
const client = createLocalMoviesClient(); const client = createInternalMoviesClient();
it('returns data for internal movie id', async () => { it('returns data for internal movie id', async () => {
const result = await client.getMovieMetadataByInternalId(11528860); const result = await client.getMovieMetadataByInternalId(11528860);

@ -2,12 +2,15 @@ import movie1 from '../../resources/movies/3532674.json';
import movie2 from '../../resources/movies/5979300.json'; import movie2 from '../../resources/movies/5979300.json';
import movie3 from '../../resources/movies/11043689.json'; import movie3 from '../../resources/movies/11043689.json';
import movie4 from '../../resources/movies/11528860.json'; import movie4 from '../../resources/movies/11528860.json';
import { InternalMoviesProvider } from './types';
const movies = [movie1, movie2, movie3, movie4]; const movies = [movie1, movie2, movie3, movie4];
export const createLocalMoviesClient = () => { export const createInternalMoviesClient = (): InternalMoviesProvider => {
return { return {
getMovieMetadataByInternalId: async (internalId: number) => movies.find(({ id }) => id == internalId), getMovieMetadataByInternalId: async (internalId: number) =>
getMovieMetadataByImdbId: async (id: string) => movies.find(({ imdbId }) => imdbId == id), Promise.resolve(movies.find(({ id }) => id == internalId)),
getMovieMetadataByImdbId: async (id: string) =>
Promise.resolve(movies.find(({ imdbId }) => imdbId == id)),
}; };
}; };

@ -7,31 +7,35 @@ describe('createOmdbClient', () => {
it('returns some data for the sample movie id', async () => { it('returns some data for the sample movie id', async () => {
const result = await client.getMovieMetadata('tt11873472'); const result = await client.getMovieMetadata('tt11873472');
expect(result).toMatchObject({ expect(result).toMatchObject({
'Actors': 'Cheryl Isheja, Elvis Ngabo, Diogène Ntarindwa', Actors: 'Cheryl Isheja, Elvis Ngabo, Diogène Ntarindwa',
'Awards': expect.any(String), Awards: expect.any(String),
'BoxOffice': expect.any(String), BoxOffice: expect.any(String),
'Country': 'Rwanda, France, Canada, United Kingdom, United States', Country: 'Rwanda, France, Canada, United Kingdom, United States',
'DVD': expect.any(String), DVD: expect.any(String),
'Director': 'Anisia Uzeyman, Saul Williams', Director: 'Anisia Uzeyman, Saul Williams',
'Genre': 'Musical, Sci-Fi', Genre: 'Musical, Sci-Fi',
'Language': 'Kinyarwanda, Kirundi, Swahili, French, English', Language: 'Kinyarwanda, Kirundi, Swahili, French, English',
'Metascore': expect.stringMatching(/^\d+$/), Metascore: expect.stringMatching(/^\d+$/),
'Plot': expect.any(String), Plot: expect.any(String),
'Poster': expect.stringMatching(/^http/), Poster: expect.stringMatching(/^http/),
'Production': expect.any(String), Production: expect.any(String),
'Rated': expect.any(String), Rated: expect.any(String),
'Ratings': expect.any(Array), Ratings: expect.any(Array),
'Released': '10 May 2023', Released: '10 May 2023',
'Response': 'True', Runtime: '105 min',
'Runtime': '105 min', Title: 'Neptune Frost',
'Title': 'Neptune Frost', Type: 'movie',
'Type': 'movie', Website: expect.any(String),
'Website': expect.any(String), Writer: 'Saul Williams',
'Writer': 'Saul Williams', Year: '2021',
'Year': '2021', imdbID: 'tt11873472',
'imdbID': 'tt11873472', imdbRating: expect.stringMatching(/^\d?\d(\.\d)?$/),
'imdbRating': expect.stringMatching(/^\d?\d(\.\d)?$/), imdbVotes: expect.stringMatching(/^\d+$/),
'imdbVotes': expect.stringMatching(/^\d+$/),
}); });
}, 10_000); }, 10_000);
it('returns undefined for non-existend movie id', async () => {
const result = await client.getMovieMetadata('tt99999999999');
expect(result).toBeUndefined();
}, 10_000);
}); });

@ -1,7 +1,17 @@
import fetch from 'node-fetch'; import fetch from 'node-fetch';
import PQueue from 'p-queue'; import PQueue from 'p-queue';
import { OmdbMovieData, OmdbMoviesProvider } from './types';
export const createOmdbClient = (apiKey: string) => { type OmdbResponse =
| {
Response: 'False';
Error: string;
}
| (OmdbMovieData & {
Response: 'True';
});
export const createOmdbClient = (apiKey: string): OmdbMoviesProvider => {
// Rate limit (according to readme, it's 1k per day; // Rate limit (according to readme, it's 1k per day;
// here we set it 1 per second, should be enough for the demo app goal) // here we set it 1 per second, should be enough for the demo app goal)
const queue = new PQueue({ const queue = new PQueue({
@ -18,8 +28,23 @@ export const createOmdbClient = (apiKey: string) => {
url.searchParams.append('i', imdbId); url.searchParams.append('i', imdbId);
url.searchParams.append('apikey', apiKey); url.searchParams.append('apikey', apiKey);
url.searchParams.append('plot', 'full'); url.searchParams.append('plot', 'full');
const response = await fetch(url); const response = await fetch(url);
const body = (await response.json()) as unknown; if (response.status == 404) {
return undefined;
}
const body = (await response.json()) as OmdbResponse;
if (body.Response !== 'True') {
if (body.Error === 'Incorrect IMDb ID.') {
return undefined;
}
throw new Error(
`Cannot fetch data from OMDB: ${body.Error}`,
);
}
return body; return body;
}), }),
}; };

@ -0,0 +1,77 @@
export type OmdbMovieData = {
Actors: string;
Awards: string;
BoxOffice: string;
Country: string;
DVD: string;
Director: string;
Genre: string;
Language: string;
Metascore: string;
Plot: string;
Poster: string;
Production: string;
Rated: string;
Ratings: {
Source: string;
Value: string;
}[];
Released: string;
Runtime: string;
Title: string;
Type: string;
Website: string;
Writer: string;
Year: string;
imdbID: string;
imdbRating: string;
imdbVotes: string;
};
type InternalMovieData = {
/**
* Description in local language
*/
description: string;
/**
* A whole number of minutes, presumably
*/
duration: number;
id: number;
imdbId: string;
/**
* Two-letter codes
*/
languages: string[];
/**
* Two-letter code
*/
originalLanguage: string;
productionYear: number;
studios: string[];
/**
* Title in local language
*/
title: string;
userrating: {
countStar1: number;
countStar2: number;
countStar3: number;
countStar4: number;
countStar5: number;
countTotal: number;
};
};
export type InternalMoviesProvider = {
getMovieMetadataByInternalId(
internalId: number,
): Promise<InternalMovieData | undefined>;
getMovieMetadataByImdbId(
imdbId: string,
): Promise<InternalMovieData | undefined>;
};
export type OmdbMoviesProvider = {
getMovieMetadata(imdbId: string): Promise<OmdbMovieData | undefined>;
};
Loading…
Cancel
Save