Why I Built A GraphQL Server For Spotify API
The story of why I built graphql-spotify for Sound for Spotify
Towards the end of last year, I wanted to work with Spotify’s music intelligence data about artists, tracks, and albums from its web API. Information about the listener’s top preferences, audio features of tracks and the genres classification on artists could produce some very insightful visualizations and engaging user interactions. With the help of GraphQL, I was able to iterate and scale a tiny React project into a fully-featured mobile-ready web app. Check it out here! Here is the story:
Initial Set Up
The app is built on top of a server-side rendered React+Next architecture. Redux and Dataloader are used for managing fetching, dependencies, caching and batching of the Spotify data. This is my go-to set up for a performance focused and developer focused development experience.
The need for multiple round trips to fetch data required by a view
Designed with simple REST principles, many Spotify endpoints return simplified versions of objects or object references from which the complete details can be retrieved. These under-fetching endpoints require the app to make additional roundtrip calls for the extra data needs to perform its functions. This is common among REST APIs where data model design is flat and normalized. For example, in order to display this view:
The required data fetching logic looks like:
- Fetch history containing simplified tracks and artists from /recently-played
- Fetch full artists referenced by the played tracks in batches from /artists
- Fetch audio features of the played tracks in batches from /audio-features
Also, notice that data from /artists & /audio-features are only utilized in the track’s expanded view, it could be optimized to only load when the user expands. Optimized data fetching is a clear must for the app’s performance.
Managing Fetching and Dependencies
In order to optimize fetching and manage data dependencies of each UI design, I created and connected pure redux containers to the presentation components when they are needed. The tried-and-true container pattern allowed me to neatly compose data fetching logic and presentational logic separately from each other. As long as the containers’ data requirements were maintained accurately, UIs always had the exact data they needed without worrying about over or under fetching from the API. For example:
Everything looked great! I kept the container and presentation layers well maintained, minimized the chances of over or under fetching from Spotify, and there was a good sense of separation of concerns, reusability and coding confidence.
So, Why GraphQL?
As I start to scale and iterate on the app, developer and performance concerns started becoming apparent:
Bad Developer Experience
- The data I used on my pages changed often, and the cost of maintaining containers with the exact data fetching requirements for each UI/UX case became too much.
- As more Spotify models were introduced to the Redux store, the cost of normalizing(flattening) data going into and denormalizing(nesting) data out of the Redux store was also growing out of control.
Bad User/Client Performance, Especially Mobile
From the user/browser’s point of view this was happening over the network:
During the initial response, data fetching logic is executed on the server side. Only a single round trip is needed before the page is rendered. However, when the app transitions between pages and views on the browser, the fetching logic is executed on the client side and often requires multiple round trips depending on the UI’s data needs before it renders itself. This is especially slow for mobile when round trips are much more expensive. The need to fetch all the data required by a UI with a single round trip to the server was highly desireable. In order to accomplish this, the logic related to the Spotify API has to be decoupled from the client and pushed into a server concern. It would look like this:
GraphQL Solves Them All
- Single round trip: The GraphQL server allows the app to get all its data needs in a single request by resolving Spotify resources to get it exactly what it needs, nothing more and nothing less.
- Goodbye, bad developer experience: The query language enables UI components to define the structure of the data required, and exactly the same structure of the data is returned from the server. This decouples the client from the Spotify endpoints, therefore eliminating the complex logic of fetching its data needs and its associated high maintenance cost. The deeply structured returned data makes integrations with existing components and creations of new components fast and painless.
If you are experiencing similar issue I encountered building Sound for Spotify, or want to build and iterate on applications fast while keeping great performance, go and check out GraphQL for your application! And give graphql-spotify a try for your Spotify data needs.