GraphQL Queries with Node
Today I wanted to show you how you would build a very simple NodeJS backend complete with GraphQL. This will be more of an intro to GraphQL and it makes it easy to use something like Node as most people will have at the very least used JavaScript.
What is GraphQL?
GraphQL is a query language for your API, much like REST but a whole lot cooler. It uses the very popular JSON format to send and receive data. Instead of calling URLs for different models, you call the same endpoint but give it a different JSON query. I’m working with a list of NBA players, I have two queries, one to return a single player and one to return all of them.
This will return all players
query{ players { id firstName lastName team championships } }
This will return a single player
{ player(id: 1) { id firstName lastName team championships } }
The first keyword ‘query’ low and behold signifies that it's a query, technically you don’t need this but it's something nice to include so you can see from a glance that it's a query, there are other types but we will talk about them in a follow-up article.
Next, we have `players` this is the actual call we want to make, it's exactly like if you wanted to call players in rest you would do `url/api/players` this would grab you all the players. It works the same way in GraphQL but instead fo changing the URL each time you want a new model you keep the same URL eg. `url/api` and then send this query to it. Next, we have the fields we want to return from each one of those player objects. All the text nested inside players are all the fields we can return for each player object. Here we are returning, id, firstName, lastName, team, championships.
As you can see the two queries are very similar despite performing different functions.
Heres the response from calling `players`
{ "data": { "players": [ { "id": 1, "firstName": "Kobe", "lastName": "Bryant", "team": "Los Angeles Lakers", "championships": 5 }, { "id": 2, "firstName": "Giannis", "lastName": "Antetokounmpo", "team": "Milwaukee Bucks", "championships": 0 }, { "id": 3, "firstName": "LeBron", "lastName": "James", "team": "Los Angeles Lakers", "championships": 3 }, { "id": 4, "firstName": "Kevin", "lastName": "Durant", "team": "Golden State Warriors", "championships": 2 } ] } }
As you can see everything comes back as JSON, which makes it extremely easy to work with. All the data gets returned under a data key and the data structure looks exactly the same as we described it. We get back an array of ‘Player’ objects. It's very simple, we specify what we want to be returned and the server goes off and grabs it in the same structure. These are all the fields on the Player object, but what happens if I only wanted the team that each player plays on? Simple, you just remove the other fields:
query{ players { team } }
{ "data": { "players": [ { "team": "Los Angeles Lakers" }, { "team": "Milwaukee Bucks" }, { "team": "Los Angeles Lakers" }, { "team": "Golden State Warriors" } ] } }
You didn’t have to call another endpoint, you just dropped the unnecessary fields. It couldn’t get simpler than this.
Let's take a look at the code that does everything. To follow along you will need to create a new folder and run
npm init
Once that has been done create a file called
server.js
Install the following dependencies
npm install graphql express express-graphql —save
Paste the following code in
var express = require('express'); var express_graphql = require('express-graphql'); var { buildSchema } = require('graphql'); // GraphQL schema var schema = buildSchema(` type Query { player(id: Int!): Player players: [Player] }, type Player { id: Int firstName: String lastName: String team: String championships: Int } `); //player data var playersData = [ { id: 1, firstName: 'Kobe', lastName: 'Bryant', team: 'Los Angeles Lakers', championships: 5 }, { id: 2, firstName: 'Giannis', lastName: 'Antetokounmpo', team: 'Milwaukee Bucks', championships: 0 }, { id: 3, firstName: 'LeBron', lastName: 'James', team: 'Los Angeles Lakers', championships: 3 }, { id: 4, firstName: 'Kevin', lastName: 'Durant', team: 'Golden State Warriors', championships: 2 } ] //returns a single player const getPlayer = args => { const id = args.id; return playersData.filter(player => { return player.id == id; })[0]; } //returns all players const getPlayers = () => { return playersData } const root = { player: getPlayer, players: getPlayers }; // Create an express server and a GraphQL endpoint const app = express(); app.use('/api', express_graphql({ schema: schema, rootValue: root, graphiql: false })); app.listen(4000, () => console.log('GraphQL Server Now Running On localhost:4000/api'));
Run the following command
node server.js
And you're done.
Despite looking like it's not working it is and if you change the field `graphiql: false` to `graphiql: true` you get a graphical editor for GraphQL, which is pretty cool, however, I like to use an external tool called Insomnia, so I leave it off.
What does all the code do?
Well, it starts an express app on port 4000. This express app contains a schema and a root value. The schema is a string template of all the calls you can make and the data structures they will return. The root value is the resolvers that contain the logic of how to get that data. You can’t return the data unless you know how to get it first and on the other hand, you can’t return the data if you don’t know what you're returning.
Root: contains all the resolvers which are functions that handle how to get the data. In order to return a single `player` you need their id, so the resolver will pass that id, grab the array of data and then filter out all the players that don’t have the matching id. As this is just an example you can use the filter but in a real-world application you would be talking to a database, that database would handle the filter given the id.
The schema contains the logic on the structure of the query and the structure of that returning data.
var schema = buildSchema(` type Query { player(id: Int!): Player players: [Player] }, type Player { id: Int firstName: String lastName: String team: String championships: Int } `);
The type of `Query` specifies that what's inside are query functions as opposed to GraphQLs other two types which are Mutation and Subscription. These are all the queries that a frontend could call on this API. You can see it contains `player` and `players`, they both have return types of `Player` which is the data structure to be returned as shown below the queries. The data structure consists of all the fields that can be called you can all anywhere from 1 to all of them at a time. Do note that you can have fields that contain other objects, this is one of the most powerful features of GraphQL and will be covered at a later date. I would like to point out that the queries have two different return types and that's because `player` returns a single `Player`, where are `players` returns many, thus it returns an array of `Player`.
Let's summarize it all
GraphQL allows you to query one endpoint with a structure that will represent exactly what you will get in return. The beauty of GraphQL is that you only query what you need, you don’t have to create separate REST endpoints for different scenarios, you simply add or remove the fields as you see fit. This gives you an extremely flexible API, you don’t waste time and data sending items that aren’t needed.
GraphQL contains resolvers and schemas, the resolvers tell the server how to get the data and the schema tells it what structure to return. This results in the API being very opinionated in it's the deliverance of data, making the life of a frontend developer just a little bit easier, furthermore, it makes your life as a backend developer easier. Gone are the days where you have these crazy REST endpoints that return huge amounts of data when you only need a handful of fields, gone are the days where you need to create a new endpoint specifically to address the first problem of to much data. You create one data structure and then the basic CRUD functionality and you've solved most of the use cases.
GraphQL isn’t without its flaws which will be talked about at a later date, but it is just about the best thing since sliced bread and it's really not hard to learn. You could pick up most of the concepts in an afternoon and put a lot of them into practice right away. If you’re feeling really adventurous you might want to try Elixir and their implementation of GraphQL, Absinthe.
I’m always learning something new and with Pluralsight I can have unlimited access to all things programming. But hold on, it’s not just programming. There’s photoshop, visual communication, manufacturing and design. There's a whole bunch! Sign up today and get a free 10-day trial!