trevor-scheer / spotify-showcase

A Spotify clone that showcases the Apollo GraphQL platform.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Apollo Client

React + Apollo Spotify Showcase

Screenshot 2023-03-07 at 5 13 26 PM

Architecture

The overall API architecture is made up of two GraphQL servers, one exposing subscription/mutation functionality and the other exposing query functionality. Both GraphQL servers use the Spotify REST API as their datasource, but we are hosting the subscription server on dedicated infrastructure (Railway) and the other on serverless functions (Netlify).

The Apollo Router routes incoming traffic from the client application and integrates with GraphOS to receive schema updates and report usage metrics.

graph LR;

subgraph "Netlify"
  web["Website\n(client app)"]
end

subgraph "Railway"
  router{"Apollo Router"}
  playbackSubgraph["Playback Subgraph\n(subriptions/mutations)"]
  spotifySubgraph["Spotify Subgraph\n(queries)"]
end

subgraph "Apollo"
  schema["Schema Pipeline"]
  usage["Usage Reporting"]
end

subgraph "Spotify"
  spotifyREST[Spotify REST API]
end

web <--> router
router <-->|Schema Updates\nUsage Reporting| Apollo
router <--> spotifySubgraph
router <--> playbackSubgraph
playbackSubgraph <--> spotifyREST
spotifySubgraph <--> spotifyREST

classDef spotifyBox color:#FFFFFF,fill:#1DB954,stroke:#FFFFFF,stroke-width:2px;
classDef netlifyBox color:#014847,fill:#FFFFFF,stroke:#32e6e2,stroke-width:2px;
classDef railwayBox color:#000000,fill:#FFFFFF,stroke:#000000,stroke-width:2px;
classDef apolloBox color:#3f20ba,fill:#FFFFFF,stroke:#3f20ba,stroke-width:2px;

class Spotify spotifyBox
class Netlify netlifyBox
class Netlify-Function netlifyBox
class Railway railwayBox
class Apollo apolloBox

*Note: We are using only the Spotify REST API as our datasource for demonstration purposes. The subscriptions subgraph implements a polling mechanism that we host on a dedicated infrastructure while the "query" subgraph is hosted on serverless infrastructure*

Getting started

  1. Clone this repo

What do you want to do next with this demo app?

I want to play around with the public version of the demo

  1. Visit the public Apollo Explorer instance to interact with the graph (No GraphOS account required)
  • Query the graph (Spotify account required) - OAuth workflow with be initiated from Apollo Explorer to login to our Spotify account to run any operation
    • Try having your Spotify app playing on your phone or desktop and then run this mutation
  • View the graph's schema

I want to re-create this demo in my GraphOS account

  1. Create a personal API key
  2. Run the clone script with the API key
APOLLO_KEY={YOUR_API_KEY} npm run graphos-demo

I want to run the client app locally

  1. Install dependencies
npm install
  1. Start the client app
npm start
  1. Visit the website at http://localhost:3000

*Note: We're currently working on subscriptions support with rover dev so the app is pointing at the deployed production url when running locally. You can change the URL the client application is pointing at by editing the .env.development file with VITE_SERVER_HOST set to the desired URL (most likely locally in the next steps)

I want to run the backend locally - using Docker

To run the current backend locally, you will need to start an Enterprise trial to utilize all the GraphOS features. You will need to create this demo (outlined above) in the enterprise trial org using APOLLO_KEY={YOUR_API_KEY} npm run graphos-demo.

  1. In the graph you re-created this demo in, create a Graph API key in the settings page
  2. Create a .env file at the root of this repository and add in the following variables:
APOLLO_GRAPH_REF={YOUR_DEMO_GRAPH_ID}@prod
APOLLO_KEY={YOUR_GRAPH_API_KEY}
CALLBACK_URL=http://router:4000
  1. Start the router and subgraphs:
npm run docker:run
  1. If you want to run any queries through Apollo Explorer, you'll need to disable persisted queries. The default mode of this repo uses the registered persisted queries list. You can disable this in the router/router.yaml by commenting out the persisted_queries configuration and restarting the docker:run command.

I want to run the backend locally

To run the current backend locally, you will need to start an Enterprise trial to utilize all the GraphOS features. You will need to create this demo (outlined above) in the enterprise trial org using APOLLO_KEY={YOUR_API_KEY} npm run graphos-demo.

  1. In the graph you re-created this demo in, create a Graph API key in the settings page
  2. Create a .env file at the root of this repository and add in the following variables:
APOLLO_GRAPH_REF={YOUR_DEMO_GRAPH_ID}@prod
APOLLO_KEY={YOUR_GRAPH_API_KEY}
CALLBACK_URL=http://127.0.0.1:4000
  1. Download the latest router binary to the router folder

  2. Start the subgraphs:

npm run start:spotify && npm run start:playback
  1. In a new terminal, start the router:
APOLLO_KEY={YOUR_DEMO_GRAPH_ID}@prod APOLLO_GRAPH_REF={YOUR_GRAPH_API_KEY} CALLBACK_URL=http://127.0.0.1:4000 npm run start:router
  1. If you want to run any queries through Apollo Explorer, you'll need to disable persisted queries. The default mode of this repo uses the registered persisted queries list. You can disable this in the router/router.yaml by commenting out the persisted_queries configuration and restarting the start:all command.

Debugging the subgraphs or client locally with VS Code

There are launch configurations for the client project and subgraph projects. You can navigate to the debug tab of VS Code and launch any of the projects. They will default to the following urls:

Subgraph responsibilities

playback - This subgraph has been designed to handle the Subscription/Mutation operations for our graph. The subgraph is hosted on a dedicated piece of infrastructure (Railway) because it needs to be long lived with subscriptions support.

spotify - This subgraph handles all of the Query operations for our graph and is hosted on serverless infrastructure (Netlify/AWS Lambda). Hosting in serverless is more cost effective for this single service in our overall architecture.

Feedback survey

If you used the React + Apollo Spotify Showcase and have two minutes then we'd really appreciate it if you filled out this survey - it really helps us improve!

Exploring the codebase?

If you're exploring the codebase and not sure where to get started, try the following:

Client

  • client/src/router.tsx - This defines all routes used in the app. To view the source code for a given route, follow the import for the route component.
  • client/src/index.tsx - This is the entry point to the client app. This defines the providers used in the app.

Server

  • server.ts - This defines the Apollo GraphQL server used to serve the Spotify GraphQL schema.
  • server/src/resolvers/ - This defines the resolvers used to resolve types and fields in the schema. The file names correspond to their respective types in the schema.
  • server/src/dataSources/spotify.ts - Defines the Spotify client used to make REST calls to Spotify's REST API.

About

Apollo Client's newest features unlock powerful UI development capabilities when used with React 18. Using Suspense via useSuspenseQuery is one such capability, as is useBackgroundQuery. Both of these will be shipped in 3.8.0. These hooks, along with the already-available useFragment hook and the GraphQL @defer directive, comprise a toolkit for the UI developer to implement the render-as-you-fetch pattern throughout the component tree.

@jerelmiller started building this application while building useSuspenseQuery in an effort to dogfood the changes with a non-trivial app. Apollo Client and GraphQL are built to be both approachable and scalable; to-do apps are the former but not the latter. A Spotify clone - and it really is a clone (👀 that CSS) - offered a much more robust proving ground for the functionality we were building. As the team used it more and more, we decided that if we open-sourced it then the community could use it to try things out for themselves.

So, here you go! It's our hope that you are able to use this app to do any or all of these things:

  • Listen to music 🎧
  • Learn how to use React Suspense
  • See how the features in Apollo Client 3.7 and 3.8 work
  • Try the GraphQL @defer directive
  • Experiment with GraphOS by turning a monograph into a supergraph
  • Get some concrete code samples to inspire your own applications
  • Use as a template for reporting bugs

Maintainers

Name Username
Ben Newman @benjamn
Alessia Bellisario @alessbell
Jeff Auriemma @bignimbus
Hugh Willson @hwillson
Jerel Miller @jerelmiller
Lenz Weber-Tronic @phryneas

Spotify API + GraphQL

This app implements a GraphQL API on top of Spotify's REST API. The GraphQL server aims to mirror the REST API as much as possible, including the field names and returned values. While it's tempting to patch the REST API in areas that make it difficult to consume (such as a separate endpoint to check if a track is in the user's library), this presented a good opportunity to showcase how a developer can use Apollo Client's capabilities to effectively build an app with these kinds of shortcomings.

There are, however, a few cases where the GraphQL API differs from the REST API.

  • This Spotify GraphQL API returns full object types in some areas where Spotify returns "simplified" object types. For example, fetching a track via the /tracks/:trackId endpoint gives you the full track data, but fetching tracks through the /albums/:albumId endpoint gives you a simplified track type. In these cases, the GraphQL API consolidates these distinct types into a the full object type (i.e. Track.)

  • Paginated fields use a Relay-style connection type. This allows the GraphQL API to express edge-specific data and pagination information in a natural way.

  • Endpoints that accept a market parameter are omitted in the equivalent GraphQL field. This is because, according to the documentation:

    If a valid user access token is specified in the request header, the country associated with the user account will take priority over this parameter.

    The GraphQL server only works with authenticated users via an access token, so maintaining this parameter was unnecessary overhead.

  • The GraphQL serves fields using camelCase. The Spotify REST API returns fields using snake_case. While not strictly enforced in the spec, GraphQL fields are commonly written in camelCase form.

About

A Spotify clone that showcases the Apollo GraphQL platform.

License:MIT License


Languages

Language:TypeScript 98.7%Language:JavaScript 0.4%Language:Shell 0.4%Language:CSS 0.2%Language:HTML 0.1%Language:Dockerfile 0.1%Language:MDX 0.1%Language:SCSS 0.0%