Everything I Learned in My 1st Year as a SWE: GraphQL
A beginner's crash course in GraphQL & REST APIs.
Year 1 Was Scary I'm Not Going To Lie.
I initially joined PayPal as a software engineering intern during the summer of 2020. I had a great experience interning for the Checkout team and was given the opportunity to be converted to a full-time employee in September of 2020. This past year has been such an amazing journey that came with many challenges, opportunities, and growth. Going from being a student to a working engineer at an enterprise-level company was a huge change and I was thrust into a world of new technologies, new tools, new vocabulary, and new ways to define success. Becoming a working engineer in the industry had been one of my goals for so long, but when I finally reached my goal I was big scared because I felt like I knew so little. I would get nervous to talk in meetings because I felt like I didn't know the right technical words to use, I would ask my co-workers to proofread my slack messages before sending them out, and my heart would be beating out of my chest on demo days. It was honestly a terrifying experience to go from usually being in the top x percentage as a student in terms of grades and achievements, to feeling dumb and confused most of the time.
In this series, I'll be sharing all the tools and technologies that I've picked up in my first year in the hopes of helping other entry-level engineers on their journey.
In this post I'm hoping to answer the following questions:
What is an API and how are they used?
What is a REST API?
What is GraphQL & why is it used as an alternative to REST?
API
When I was trying to learn GraphQL, every article I came across compared it to REST APIs. As a beginner, this was so confusing because they were trying to teach me something new by framing it against another new thing. So let's start with what an API is and more specifically what a REST API is. If you google API, you'll get vague answers telling you that the acronym stands for "application program interface." But what does this really mean? An API is a middleman that allows your product or service to communicate with other products/services.
The best way I was able to understand what an API really is was by taking this idea of an interface and using it to think of a user interface. A user interface is made up of the elements on the screen that a user can see. Think of buttons, navbars, links, etc. These elements exist to create a usable method for users to take certain actions. For example, the click of a button will direct you to a new page, or clicking on the nav bar will expand it to show other options. Without a user interface, a user would have to go down to a lower level and perhaps run scripts to access the functionality of an application. The user interface creates an easy and simple way for users to achieve a certain goal. An API does just that - it creates an easy way for services to access data or functionality of some other service or program.
REST API
A REST API is just an API that follows certain rules and architecture that have been defined and are mostly used to facilitate communication between different web services. A REST API requests information via the HTTP protocol and returns a response with information that you may use to serve up in your application. For example, if you were building a music app that recommends a newly released album daily, you would need to compile a list of new releases to choose from and then some functionality in your app to display these. You could either create a database and add all the albums you wanted to include and manually update this every time a new release came out, or you could use make a request to Spotify's REST API which accesses Spotify's database of playlists and say "Hey, give me a project that was just released on Spotify please."
The REST API architecture makes information requestable by services, like your music app, by presenting a list of endpoints that look like this:
https://api.spotify.com/v1/browse/new-releases
The endpoints start with a base URL, in this case, api.spotify.com, and then branch off from there. Spotify engineers who built their API sat down and thought about the best way to break up all of the information that they want people to access into different endpoints. There's an endpoint for accessing new releases, an endpoint to add a user as a follower of a specific playlist, an endpoint to access information about a podcast episode, and you can check out all available endpoints here . There's a bunch of endpoints that were defined by Spotify engineers to best suit their needs.
Problems with REST
Rigid Endpoints
Because these endpoints are designed by other engineers to best suit their needs, it most likely means that they are not best suited for your needs. You are forced to work with predefined endpoints and you may not know what type of response will come back from a given request.
https://api.spotify.com/v1/browse/new-releases
Just by looking at this endpoint, we have no idea what kind of response we'll get back from a GET request. Does it tell us the month it was released so we can categorize it by month? Does it tell us the genre of music its in? Does it tell us how many times its been streamed so far? We have no idea and as a developer, you would like to know exactly what kind of data you can expect.
Overfetching
If we make a request to access the playlist API by hitting this endpoint api.spotify.com/v1/playlists/{playlist_id}, this is what we would get back as a response:
{
"albums" : {
"href" : "https://api.spotify.com/v1/browse/new-releases?country=SE&offset=0&limit=20",
"items" : [ {
"album_type" : "single",
"artists" : [ {
"external_urls" : {
"spotify" : "https://open.spotify.com/artist/2RdwBSPQiwcmiDo9kixcl8"
},
"href" : "https://api.spotify.com/v1/artists/2RdwBSPQiwcmiDo9kixcl8",
"id" : "2RdwBSPQiwcmiDo9kixcl8",
"name" : "Pharrell Williams",
"type" : "artist",
"uri" : "spotify:artist:2RdwBSPQiwcmiDo9kixcl8"
} ],
"available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "ID", "IE", "IS", "IT", "JP", "LI", "LT", "LU", "LV", "MC", "MT", "MX", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "SE", "SG", "SK", "SV", "TR", "TW", "US", "UY" ],
"external_urls" : {
"spotify" : "https://open.spotify.com/album/5ZX4m5aVSmWQ5iHAPQpT71"
},
"href" : "https://api.spotify.com/v1/albums/5ZX4m5aVSmWQ5iHAPQpT71",
"id" : "5ZX4m5aVSmWQ5iHAPQpT71",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/e6b635ebe3ef4ba22492f5698a7b5d417f78b88a",
"width" : 640
}, {
"height" : 300,
"url" : "https://i.scdn.co/image/92ae5b0fe64870c09004dd2e745a4fb1bf7de39d",
"width" : 300
}, {
"height" : 64,
"url" : "https://i.scdn.co/image/8a7ab6fc2c9f678308ba0f694ecd5718dc6bc930",
"width" : 64
} ],
"name" : "Runnin'",
"type" : "album",
"uri" : "spotify:album:5ZX4m5aVSmWQ5iHAPQpT71"
}, {
"album_type" : "single",
"artists" : [ {
"external_urls" : {
"spotify" : "https://open.spotify.com/artist/3TVXtAsR1Inumwj472S9r4"
},
"href" : "https://api.spotify.com/v1/artists/3TVXtAsR1Inumwj472S9r4",
"id" : "3TVXtAsR1Inumwj472S9r4",
"name" : "Drake",
"type" : "artist",
"uri" : "spotify:artist:3TVXtAsR1Inumwj472S9r4"
} ],
"available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GB", "GR", "GT", "HK", "HN", "HU", "ID", "IE", "IS", "IT", "JP", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "SE", "SG", "SK", "SV", "TR", "TW", "UY" ],
"external_urls" : {
"spotify" : "https://open.spotify.com/album/0geTzdk2InlqIoB16fW9Nd"
},
"href" : "https://api.spotify.com/v1/albums/0geTzdk2InlqIoB16fW9Nd",
"id" : "0geTzdk2InlqIoB16fW9Nd",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/d40e9c3d22bde2fbdb2ecc03cccd7a0e77f42e4c",
"width" : 640
}
..........
}
}
You get back this super long response with a bunch of information that's irrelevant to your app. All you needed was the name of the project, the artist name, and the cover art to display in your app. This problem is known as overfetching. In a small application like the mock music app we're describing, it's not a big enough issue to cause any noticeable lag in our application, but it is annoying. Now you have to work with this JSON response to filter out what you need.
Underfetching
Underfetching refers to getting a response from a REST API that doesn’t contain all of the information you require, forcing you to make multiple requests to different end points until all of your data needs are met. For example, if our app has a homepage where we want to display our daily new release, the users profile picture and name, and their most played playlists we have no way of doing this with just the /browse/new-releases endpoint. This doesn't contain all of the information that we need. So we'd have to make a request to api.spotify.com/v1/browse/new-releases, a request to api.spotify.com/v1/me, and a request to api.spotify.com/v1/me/playlists.
All of these requests are independent of each other and some requests may take longer to complete than others, leaving you waiting for all of your data to paint your screen correctly.
Underfetching is problematic because not only do you have to make multiple requests which eat away at your apps ability to load quickly, but these multiple requests all take an indiscriminate amount of time to complete.
GraphQL
This is where GraphQL comes to save the day 🦸♀️. GraphQL is a query language for your API that allows you to fetch data declaratively - AKA you can tell it exactly what data you want, and it'll return just that. No more, no less. Instead of working with rigid endpoints that are predefined for you, you can write custom queries to receive the data you need. The GraphQL equivalent to GET is a query, and a mutation is the equivalent to POST, PUT, DELETE, or PATCH. Queries just fetch information and mutations update data and then fetch the newly updated data. You can use GraphQL with any programming language and you can even fetch data from multiple sources.
Schema
As a developer, you design your GraphQL schema which defines the capabilities of your GraphQL server - think of this like your dictionary. In the schema, you define all of the possible data you can query. In the schema, you define object types, which represent a kind of object you can fetch and all of the properties you can request about that object. The schema for our project might look like this:
type Album {
artistName: String!
numberOfSongs: Int!
coverArtLink: String!
}
type Playlist {
name: String!
coverArtLink: String!
totalDuration: String!
}
type UserInfo {
name: String!
profilePicLink: String!
likedSongs: Int!
topGenre: String!
}
Queries
In theory, we would describe a bunch of other object types to represent everything we will need to query for our app, and then we could write custom queries to fetch these objects! Instead of making multiple requests with the REST API, now we could write a query to get a new album, user profile information, and their playlists for our app's homepage:
{
query homepageView {
Album {
artistName
numberOfSongs
coverArtLink
}
UserInfo {
name
profilePicLink
}
Playlist {
name
coverArtLink
}
}
}
With this one query, we are able to request all of the information our app needs that would have taken 3 separate requests with the REST API! We also are only fetching exactly what we need and aren't tied to fetching every single property that exists on each object, and we're not stuck with a bunch of extra data that our app doesn't need. The response would look like this:
{
"homepageView" {
Album {
"Kendrick Lamar"
10
"assets/artists/kendrick_lamar"
}
UserInfo {
"Camila Ramos"
"assets/users/camila_ramos/photo"
}
Playlist {
"Today's Chill"
"assets/playlists/todays_chill"
}
}
}
You'll notice that the response has an identical shape to the query. Because we're asking for very specific data, we can always anticipate what our response is going to look like.
Resolvers
You tell GraphQL how to come up with the answers to your query. In the schema, you've defined what type of each field's response will be, but the resolvers are where you tell GraphQL how to come up with your data. Each field on each type you define has a resolver function that is written by you, the developer. When you query a field, the corresponding resolver is called to generate the response to your query. Here's an example from the GraphQL documentation on how a resolver in JS would look for a type called 'human.'
Query: {
human(obj, args, context, info) {
return context.db.loadHumanByID(args.id).then(
userData => new Human(userData)
)
}
}
Conclusion
The five major problems with REST APIs were
- Rigid endpoints
- Overfetching
- Underfetching
- Multiple requests
- No idea what the response will be
We saw how GraphQL solves all of these problems and makes the developer experience 100x better. If this article helped you understand APIs or GraphQL, leave a comment and let me know 🙏.