Skip to content

Commit

Permalink
Merge pull request #164 from apollographql/dataloader-caching
Browse files Browse the repository at this point in the history
Add Dataloader and caching for Tracks
  • Loading branch information
michael-watson authored Oct 12, 2023
2 parents ce4005c + 48aae7a commit b7d1f5d
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 11 deletions.
10 changes: 8 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
"skipFiles": ["<node_internals>/**"],
"cwd": "${workspaceFolder}/subgraphs/playback",
"program": "${workspaceFolder}/subgraphs/playback/src/index.ts",
"outFiles": ["${workspaceFolder}/subgraphs/playback/dist/**/*.js"],
"outFiles": [
"${workspaceFolder}/subgraphs/playback/dist/**/*.js",
"${workspaceFolder}/shared/spotify-api/dist/**/*.js"
],
"preLaunchTask": "tsc: build - subgraphs/playback/tsconfig.json"
},
{
Expand All @@ -21,7 +24,10 @@
"skipFiles": ["<node_internals>/**"],
"cwd": "${workspaceFolder}/subgraphs/spotify",
"program": "${workspaceFolder}/subgraphs/spotify/src/index.ts",
"outFiles": ["${workspaceFolder}/subgraphs/spotify/dist/**/*.js"],
"outFiles": [
"${workspaceFolder}/subgraphs/spotify/dist/**/*.js",
"${workspaceFolder}/shared/spotify-api/dist/**/*.js"
],
"preLaunchTask": "tsc: build - subgraphs/spotify/tsconfig.json"
},
{
Expand Down
79 changes: 79 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"docker:build:spotify": "docker build -t subgraph-spotify -f ./subgraphs/spotify/Dockerfile .",
"docker:build:playback": "docker build -t subgraph-playback -f ./subgraphs/playback/Dockerfile .",
"docker:build:router": "docker build -t showcase-router -f ./router/Dockerfile ./router",
"docker:run":"docker-compose --env-file=./.env up --build",
"docker:run": "docker-compose --env-file=./.env up --build",
"format": "prettier . --write",
"lint": "concurrently \"npm:lint:*\"",
"lint:format": "prettier . --check",
Expand All @@ -25,7 +25,7 @@
"build": "npm run build -ws",
"graphos-demo": "ts-node scripts/demo.ts",
"generate:mocks": "npm run generate:mocks -w spotify-api",
"generate:pq":"generate-persisted-query-manifest",
"generate:pq": "generate-persisted-query-manifest",
"start": "npm run start:client",
"start:all": "concurrently \"npm:dev -w playback-subgraph\" \"npm:dev -w spotify-subgraph\" \"npm:start:router\"",
"start:client": "npm run start -w client",
Expand Down Expand Up @@ -60,6 +60,7 @@
},
"dependencies": {
"@apollo/generate-persisted-query-manifest": "^1.0.0",
"@apollo/server-plugin-response-cache": "^4.1.3",
"@graphql-codegen/cli": "^4.0.1",
"@graphql-codegen/fragment-matcher": "^5.0.0",
"@graphql-codegen/typescript": "^4.0.1",
Expand Down
1 change: 1 addition & 0 deletions shared/spotify-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@apollo/server": "^4.9.3",
"@apollo/utils.fetcher": "^2.0.1",
"@apollo/utils.keyvaluecache": "^2.1.1",
"dataloader": "^2.2.2",
"typescript": "^5.1.6"
},
"devDependencies": {
Expand Down
12 changes: 8 additions & 4 deletions shared/spotify-api/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Spotify, SpotifyDataSource } from 'spotify-api';
import path from 'path';
import { GraphQLError } from 'graphql';
import { ConditionalKeys } from 'type-fest';
import DataLoader from 'dataloader';

export type OmitNever<T> = Omit<T, ConditionalKeys<T, never>>;

Expand Down Expand Up @@ -385,13 +386,16 @@ export class SpotifyClient extends RESTDataSource implements SpotifyDataSource {
);
}

getTrack(
private trackLoader = new DataLoader(async (ids) => {
const trackList = await this.getTracks({ ids: ids.join(',') });
return ids.map((id) => trackList.tracks.find((track) => track.id === id));
});

async getTrack(
id: string,
params?: Spotify.Request.QueryParams.GET['/tracks/:id']
) {
return this._get<Spotify.Response.GET['/tracks/:id']>(`/tracks/${id}`, {
params,
});
return this.trackLoader.load(id);
}

getTrackAudioFeatures(trackId: string) {
Expand Down
2 changes: 1 addition & 1 deletion shared/spotify-api/src/dataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export interface SpotifyDataSource {
getTrack(
id: string,
params?: Spotify.Request.QueryParams.GET['/tracks/:id']
): Promise<Spotify.Response.GET['/tracks/:id']>;
): Promise<Spotify.Object.Track | undefined>;
getTrackAudioFeatures(
trackId: string
): Promise<Spotify.Response.GET['/audio-features/:id']>;
Expand Down
1 change: 1 addition & 0 deletions subgraphs/spotify/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
},
"dependencies": {
"@apollo/server": "^4.9.3",
"@apollo/server-plugin-response-cache": "^4.1.3",
"@apollo/subgraph": "^2.5.5",
"@graphql-tools/mock": "^9.0.0",
"@graphql-tools/schema": "^10.0.0",
Expand Down
3 changes: 2 additions & 1 deletion subgraphs/spotify/src/resolvers/PlaybackItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ export const PlaybackItem: PlaybackItemResolvers = {
return 'Track';
}
},
async __resolveReference(playbackItem, { dataSources }) {
async __resolveReference(playbackItem, { dataSources }, info) {
(info as any).cacheControl.setCacheHint({ maxAge: 60, scope: 'PRIVATE' });
// This is strictly for a demo, not a good practice
const id = playbackItem.id;
try {
Expand Down
3 changes: 2 additions & 1 deletion subgraphs/spotify/src/resolvers/Track.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ export const Track: TrackResolvers = {
is_playable === undefined ? true : is_playable,
previewUrl: prop('preview_url'),
trackNumber: prop('track_number'),
__resolveReference: (track, { dataSources }) => {
__resolveReference: (track, { dataSources }, info) => {
(info as any).cacheControl.setCacheHint({ maxAge: 60, scope: 'PUBLIC' });
return dataSources.spotify.getTrack(track.id);
},
};
2 changes: 2 additions & 0 deletions subgraphs/spotify/src/utils/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ContextValue } from '../types/ContextValue';
import logger from '../logger';
import * as Sentry from '@sentry/node';
import { resolve } from 'path';
import responseCachePlugin from '@apollo/server-plugin-response-cache';

const schemaPath = existsSync('schema.graphql')
? 'schema.graphql'
Expand All @@ -35,6 +36,7 @@ export const server = new ApolloServer<ContextValue>({
introspection: true,
logger,
plugins: [
responseCachePlugin(),
{
async requestDidStart() {
return {
Expand Down

0 comments on commit b7d1f5d

Please sign in to comment.