(This article is part of an ongoing series on technical and soft skills from Nathan Thomas, a full stack software engineer studying and working at Lambda School based in Silicon Valley. Click here for the previous article in the series, a piece on “The Pursuit of Personal Fulfillment.”) Getting Started with GraphQL I don’t know if you’ve heard, but there’s a new kid on the block — it's called GraphQL. relatively It’s super fancy. 🎉 If you’re anything like me, you’ve built lots of RESTful servers. When you finally take a break to squash your existential dread and document 150 new endpoints, you might start wondering if there’s a better way to live your life. On top of that, you might start to notice that your server often delivers information that’s unneeded for a given request. When the client makes a request from your server, it ends up getting the entire forest along with the single tree of data (I know, my examples need work). too much This is where GraphQL comes in. GraphQL is fast replacing RESTful APIs everywhere you might look, and more-and-more companies are that it’s sped up their applications significantly. claiming As always, grab a cup of something good. ☕️ Strap in. This one’s crazy, but I think you’ll find it‘s worth it in the end. It’s Time to Start Thinking in Edges Graphs are all around us in life, and yet we never notice them. When you travel on public transit, discuss your family tree, or look at the stars and try to make out a bull or a large goat person shooting an arrow (like how I showed off my astronomy knowledge there?), we are unknowingly thinking in terms of graphs. In computer science, graphs are connected points, and these points are traditionally called or . The lines that connect these graphs together are called . Here’s an example of a simple graph: nodes vertices edges The graph above has five or ) and eight . Make sense, right? nodes ( vertices edges Without getting into the nitty gritty of in-depth graph theory, we can access various that are connected through by traveling along that edge to another . In our data, this means that we connect different data tables together in a way that has significant meaning (this will make more sense later in the article). nodes edges node This was one of the ways of thinking that allowed GraphQL to be born. Coupled with a general dissatisfaction for the current state of RESTful APIs in today’s data-heavy applications, decided to pioneer a new way to fetch data from their servers back in 2012 (and finally open-sourced it in 2015). By focusing on the data connections (instead of thinking in endpoints), they developed a new process for obtaining information from their servers. Facebook GraphQL is, at its core, a protocol disguised as a data-querying language. It is a layer that sits on top of your server and interfaces with both the server and the client. Here’s an example of a query from the front-end that we could write later once we have the server built out: { { username phone } } query getAllUsers id When we fire this off (which we’ll see how to do soon), we get the following JSON data back: { : { : [ { : , : , : }, { : , : , : }, { : , : , : }, { : , : , : }, { : , : , : } ] } } "data" "getAllUsers" "id" "1" "username" "admin" "phone" "(777) 777-7777" "id" "2" "username" "Chadrick54" "phone" "1-213-614-0707 x94837" "id" "3" "username" "Eva27" "phone" "396-178-0064" "id" "4" "username" "Audreanne_Luettgen65" "phone" "1-208-921-9879 x9843" "id" "5" "username" "Ahmed56" "phone" "(675) 410-7905 x6909" Notice how the data directly parallels the query that we made? That’s super declarative code. We’ll talk more about that in a bit. For now, let’s hop directly into the deep end and set up a server. 🔥 “Whatever affects one directly, affects all indirectly.” — Martin Luther King Jr. Setting Up the Server and Postgres Database We’ll be starting from a mid-way point with our server this time around (but if you want to learn how to build the barebones of an Express.js server from scratch, check out my previous article ). 👍 here Go ahead and clone for the starter files. This will catch you up to exactly where you need to be to follow along with this walkthrough. Once you clone it and open it up in your editor of choice (I’ll be using ), you should have something very much like this: this repository VS Code Make sure to use the command to install all of your node modules as well. Once these have finished downloading, feel free to poke through the repository a bit and see what code is already finished for you. yarn We’ll be building out our API to allow us to work with users and their corresponding favorite candy. I’ve already built out a lot of the core functionality along with the migrations and dummy seed data files, and we’ll just be focusing on implementing GraphQL. 👍 Go ahead and run the command in the root directory. You should see something much like this: yarn server However, our server isn’t fully wired up yet. Before we go any further, let’s head into our next section and hook up some good old-fashioned . PostgreSQL “We are all now connected by the Internet, like neurons in a giant brain.” — Stephen Hawking Setting Up PostgreSQL We’ll be using Heroku today for our database (purely because it’s super easy to grab a full instance of ), although you’re free to use a Docker instance or something else if you want. PostgreSQL If you haven’t already done so in the past, create a Heroku account and then click the "New" dropdown menu and "Create new app." If you see the screen below, you’ve gone the right direction: here Next, click on the "Resources" tab. It should look like this: Type "postgres" into the “Add-ons” search input and select the “Heroku Postgres” option that appears. You’ll then be asked if you want to provision a free Hobby-tier server, and you should say “yes.” After you do that, your screen should look like this: Click on “Heroku Postgres” in purple letters, and this will take you to a new screen. On that screen, select “Settings” from the tabs and then click the “View Credentials” link shown below: Grab the URI link listed in the resources. Here’s a fake link to demonstrate what it should look like: postgres://ridsyuidtuuo:1f63063581eef3f1a6f09575e26781d0e81eed0a82b5e1705b518a54937a4853@ec2-50-19-221-37.compute-1.amazonaws.com:5132/d7nnugsfg4ljnk Copy that link, and let’s head back over to our local server. Create a file called in your root directory and paste the following in: .env PORT= DATABASE_URL= 4000 < > your database URI link goes here This gives the boilerplate I made for you access to the PostgreSQL instance that you just set up, and we’re also assigning a custom port for your server. With all of that out of the way, we can get to work on GraphQL. Go ahead and take a break to step outside. Grab some more coffee or tea. finally Ready? Let’s go. 💪 GraphQL Structure In a normal RESTful API, we have our typical , , , and requests. These have been the gold standard for HTTP requests for years, and with good reason; they work, and they work well. GET POST PUT DELETE However, modern applications keep running into situations where developers have to build out an excessive number of endpoints. This can create a burden on the development process, and it certainly expands the amount of documentation that is required for the API. In contrast, GraphQL simplifies everything down to one endpoint, . Open up the file inside the api directory and look for the following code snippet: /graphql server.js server.use( , graphqlHTTP({ schema, : }) ); '/graphql' graphiql false This is the single endpoint, a gateway into our server. It will allow us to perform all of our queries and mutations (which replace our , , , and requests). In order for our server to work, our next step needs to be to flesh out the schema that we use in the code snippet above. Notice that there’s already an import statement in our file for it that looks like this: GET POST PUT DELETE server.js schema = ( ); const require '../schema/schema.js' Additionally, check out the middleware import that is also contained in our file. The import statement looks like this: expressPlayground server.js expressPlayground = ( ).default; const require 'graphql-playground-middleware-express' Out of the box, GraphQL comes with , an IDE to practice server calls in your browser. I’ve replaced it with (and turned off with the statement in the snippet at the beginning of this section) as it is much more robust and (which is obviously the most important quality in the development process 💅). GraphiQL GraphQL Playground GraphiQL graphiql: false better looking The configuration for this is also in the file with the following code: server.js server.get( , expressPlayground({ : })); '/playground' endpoint '/graphql' This allows us to use our new IDE. With your server running (which, just in case you shut it down, can be done with the command ), got to link in your browser. Your preferred browser will open up and you’ll be taken to a page that looks like this: GraphQL Playground yarn server localhost:4000/playground Doesn’t that dark mode in look amazing? If you’re seeing this, you’re in the right place. However, our server has a problem — We have an error (visible in the image above) that says that the server can’t be reached. It’s currently doing that because we still need to build out our queries, schemas, and migrate over our tables and data. GraphQL Playground Let’s flip over to the next section and get to work on our GraphQL server structure. “When one tugs at a single thing in nature, he finds it attached to the rest of the world.” — John Muir GraphQL Types GraphQL is a strongly-typed querying language. This means that it validates the types of data that we are manipulating while using it. In order for this to work, we have to define — These will correspond directly to the tables in our SQL database (although you are certainly free to use no-SQL databases like MongoDB with GraphQL), and correlate to the use of objects or structs in Object Oriented Programming with languages like Java, Golang, and C. Types In order to define a type, you must use imports from the dependency to define strings, integers, and other data types that you expect to receive through GraphQL for each field (username, email, etc.). Here’s an example of a that we’ll be using in our server: graphql UserType graphql = ( ); { GraphQLObjectType, GraphQLID, GraphQLString, GraphQLNonNull } = graphql; UserType = GraphQLObjectType({ : , : ({ : { : GraphQLID }, : { : GraphQLNonNull(GraphQLString) }, : { : GraphQLNonNull(GraphQLString) }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, }) }); .exports = { UserType }; const require 'graphql' const const new name 'User' fields => () id type username type new email type new pictureUrl type street1 type street2 type city type state type zip type type type phone type module Notice how we’re requiring the package and then destructuring out our types from it (strings, ID, object, etc.). We can then define a schema, or group of fields, of what we expect to receive for a given object of data (in this case, our users). Finally, we’re exporting our out to use later in our server. graphql UserType Go ahead and make a file called in the directory of the server in your server files. Look over the code below, and then put the following code into the file: types.js schema graphql = ( ); { GraphQLObjectType, GraphQLID, GraphQLString, GraphQLNonNull, GraphQLList } = graphql; UserType = GraphQLObjectType({ : , : ({ : { : GraphQLID }, : { : GraphQLNonNull(GraphQLString) }, : { : GraphQLNonNull(GraphQLString) }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLList(CandyType), resolve(parent, args) { Candy.findByUserId(parent.id); } } }) }); .exports = { UserType }; const require 'graphql' const const new name 'User' fields => () id type username type new email type new pictureUrl type street1 type street2 type city type state type zip type type type phone type candy type new return module See that field called ? That’s interesting, right? candy Remember how we were talking earlier about and how they connect , or , together? Well, this is where we’re defining an that will connect us along our graph in our database to another . Notice that we define the field as being a (which means it will essentially show up as an array of candy in our ) of . Furthermore, the resolver function returns a database query where we search for the parent’s property (essentially the user’s from the fields above). edges nodes vertices edge node candy GraphQLList JSON CandyType PostgreSQL id id We’ll use this field later to access data about the table associated with each user in the table. candy user However, we have a bit of a problem — we don’t have a that this field seems to be referencing. For time’s sake, I’m going to give you this code to copy-and-paste into your code right below the . Here’s the completed file code for you: CandyType UserType graphql = ( ); User = ( ); Candy = ( ); { GraphQLObjectType, GraphQLID, GraphQLString, GraphQLNonNull, GraphQLList } = graphql; UserType = GraphQLObjectType({ : , : ({ : { : GraphQLID }, : { : GraphQLNonNull(GraphQLString) }, : { : GraphQLNonNull(GraphQLString) }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLList(CandyType), resolve(parent, args) { Candy.findByUserId(parent.id); } } }) }); CandyType = GraphQLObjectType({ : , : ({ : { : GraphQLID }, : { : GraphQLNonNull(GraphQLString) }, : { : GraphQLNonNull(GraphQLID) }, : { : UserType, resolve(parent, args) { User.findById(parent.userId); } } }) }); .exports = { UserType, CandyType }; const require 'graphql' const require '../models/userModel.js' const require '../models/candyModel.js' const const new name 'User' fields => () id type username type new email type new pictureUrl type street1 type street2 type city type state type zip type type type phone type candy type new return const new name 'Candy' fields => () id type candyName type new userId type new user type return module We’ve now completed the circle. We have a that will pull information from our database (and even has the ability to query the user associated with each candy in the field above) but is also connected to its corresponding user (in a one-to-many relationship from the table to the table). CandyType user user candy We’re about to see how useful all of this is. The next sections will be crazy, but they’ll go really fast. We’ll have your server finished in no time. 🔥 🚒 GraphQL Queries Queries are analogous to requests on a RESTful API, but the way in which we can write them in GraphQL (which we saw at the beginning of this article) makes them really unique and extremely declarative. GET In software engineering, (in case you don’t want to spend the next 10 minutes waist-deep in that Wikipedia link) is any process that allows you to write your code in a way that describes it does instead of it does it. declarative design what how Create a new file in your directory called , and paste the following code into it. It’s a lot, but there’s a ton of repetition (as you’ll see soon) that makes it ultimately easy to learn: schema query.js graphql = ( ); Candy = ( ); User = ( ); { UserType, CandyType } = ( ); { GraphQLObjectType, GraphQLList, GraphQLID, GraphQLNonNull } = graphql; RootQuery = GraphQLObjectType({ : , : { : { : GraphQLList(UserType), : , resolve() { User.find() .then( { (res.length) { res; } ( ); }) .catch( { ( ); }); } }, : { : UserType, : , : { : { : GraphQLNonNull(GraphQLID) } }, resolve(parent, args) { User.findById(args.id) .then( { (res) { res; } ( ); }) .catch( { ( ); }); } }, : { : GraphQLList(CandyType), : , resolve() { Candy.find() .then( { (res.length) { res; } ( ); }) .catch( { ( ); }); } }, : { : CandyType, : , : { : { : GraphQLNonNull(GraphQLID) } }, resolve(parent, args) { Candy.findById(args.id) .then( { (res) { res; } ( ); }) .catch( { ( ); }); } } } }); .exports = RootQuery; const require 'graphql' const require '../models/candyModel.js' const require '../models/userModel.js' const require './types.js' const const new name 'RootQueryType' fields getAllUsers type new description 'Gets all users' return => res if return return new Error 'The users could not be found.' => () return new Error 'There was an error completing your request.' getUserById type description 'Gets a user by user ID' args id type new return => res if return return new Error 'The user could not be found.' => () return new Error 'There was an error completing your request.' getAllCandy type new description 'Gets all candy' return => res if return return new Error 'The candy could not be found.' => () return new Error 'There was an error completing your request.' getCandyById type description 'Gets a candy by candy ID' args id type new return => res if return return new Error 'The candy could not be found.' => err return new Error 'There was an error completing your request.' module Don’t worry. Like I said, it’s a lot of repetition. Let’s take the query at the end of the file above and dissect it (since it’s close to us right now and is a great example of the rest of the queries). getCandyById First, we define what “type” our query is supposed to return. We just coded those up in the last section, and we imported them at the beginning of this file. query.js Second, we have a description of the query. This will pop up in GraphQL Playground. It’s not necessary, but it’s a really nice touch for other developers to read in later when they’re testing out writing queries for our server. GraphQL Playground Next, we have our arguments, or . These are what we expect our server to receive when someone makes this query. In this instance, we have an argument of type . This is a unique import from the package that allows the argument sent to our server to be either a number or a string (i.e. 1 or “1”). args getCandyById id GraphQLID graphql Additionally, we have a function. This takes in properties (which we aren’t using here) as the first argument and (or arguments, our in this case) as the second one. We then proceed to query our database and return the response in our promise. If the data cannot be found, we return a new error with a message. resolve parent args id PostgreSQL Finally, navigate over to your file, and update it to look like this: schema.js graphql = ( ); { GraphQLSchema } = graphql; RootQuery = ( ); .exports = GraphQLSchema({ : RootQuery, : }); const require 'graphql' const const require './query.js' module new query mutation null We just imported the queries from query.js and placed it into our schema setup. The only thing we still need to do in order to use our server is to roll out some mutations. Hold onto your butts. 👍 “Invisible threads are the strongest ties.” — Friedrich Nietzsche GraphQL Mutations The final puzzle piece for our server is to upgrade our code with “mutations.” These are the GraphQL equivalents of , , and requests in a RESTful API. POST PUT DELETE Create a new file called and paste the following code in: mutation.js graphql = ( ); User = ( ); { UserType } = ( ); { GraphQLString, GraphQLNonNull, GraphQLID, GraphQLObjectType } = graphql; Mutation = GraphQLObjectType({ : , : ({ : { : UserType, : { : { : GraphQLNonNull(GraphQLString) }, : { : GraphQLNonNull(GraphQLString) }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString } }, resolve(parent, args) { User.insert(args) .then( { (res) { res; } ( ); }) .catch( { ( ); }); } }, : { : UserType, : { : { : GraphQLNonNull(GraphQLID) }, : { : GraphQLNonNull(GraphQLString) }, : { : GraphQLNonNull(GraphQLString) }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString }, : { : GraphQLString } }, resolve(parent, args) { User.update(args.id, args) .then( { (res) { res; } ( ); }) .catch( { ( ); }); } }, : { : UserType, : { : { : GraphQLNonNull(GraphQLID) } }, resolve(parent, args) { User.remove(args.id); } } }) }); .exports = Mutation; const require 'graphql' const require '../models/userModel.js' const require './types.js' const const new name 'Mutation' fields => () addUser type args username type new email type new pictureUrl type street1 type street2 type city type state type zip type type type phone type return => res if return return new Error 'The new user could not be created.' => () return new Error 'There was an error completing your request.' updateUser type args id type new username type new email type new pictureUrl type street1 type street2 type city type state type zip type type type phone type return => res if return return new Error 'The user could not be updated.' => () return new Error 'There was an error completing your request.' deleteUser type args id type new return module Once again, I know this looks like a lot, but it’s ultimately just a lot of repetition. Let’s look at the mutation here at the end of the file as an example. deleteUser Notice that we’ve once again defined our type, . In addition, we’re expecting an argument of . Finally, we are using a resolver function to ping our database and remove the row of user data where the matches the user. UserType id PostgreSQL args.id Look over the other mutations using this knowledge and see if you can figure out what everything else is doing. There’s nothing complicated here; it’s all just more of the same from what you’ve already seen. When you're done, update the file one more time to import our mutations and look like this: schema.js graphql = ( ); { GraphQLSchema } = graphql; RootQuery = ( ); Mutation = ( ); .exports = GraphQLSchema({ : RootQuery, : Mutation }); const require 'graphql' const const require './query.js' const require './mutation.js' module new query mutation Using GraphQL Playground It’s time to enjoy using our GraphQL server. 🍾 🎉 🎊 🙌 First, let’s migrate our data tables and seeds on by running the following commands in your terminal: PostgreSQL npx knex migrate:latest npx knex seed:run Once you’ve finished, run the command in your terminal (if you’re not already running your server) and click on the link. yarn server localhost:4000/playground Then, write the following query in the lefthand side of the screen and press the “play” button: query { getAllUsers { id username email street1 city state zip type phone candy { id candyName } } } This queries our server for all users and returns the fields above that we requested. Your instance should look like this: GraphQL Playground Finally, let’s do a quick mutation. Open a new tab in , and paste the following mutation into the lefthand side of the screen before pressing the “play” button: GraphQL Playground mutation { addUser ( username: email: street1: city: state: zip: phone: ) { id username email street1 city state zip type phone } } "martymcfly" "outoftime@future.com" "9303 Lyon Drive" "Hill Valley" "CA" "95420" "(777) 777-7777" This should create a new user and return data as we’ve specified in the return fields we expect above. Your browser window should look like the following: See if you can write other mutations and queries out. You can check out the various ones available to you (along with the types we created on the server) by clicking on the and tabs on the righthand side of the page: DOCS SCHEMA Conclusion Now that we’ve been through a full tour of duty with GraphQL, hopefully you can see why people enjoy using it. It’s simple (once you get it set up), and it’s honestly a lot of fun. See if you can go back to the file and make all of the mutations for the , including a , , and . mutations.js CandyType createNewCandy updateCandyById deleteCandyById Finally, as you continue to build out APIs, GraphQL is a great choice; pairing it with makes middleware implementation easy, and our PostgreSQL setup means you can now scale this framework with one of the most popular databases out there. Express.js If you end up building something awesome, feel free to tweet me with it. I’d love to see what you can create. 🏗 Additional Resources for Your Journey — The official documentation on GraphQL is excellent and a great way to get started with customizing this server for your own application GraphQL Documentation — Apollo-Boost is a quick and easy way to get started writing front-end mutations and queries for your application with GraphQL Apollo-Boost — A brilliant article on best practices while writing your resolver functions in GraphQL Resolver Best Practices Thanks for reading. 🔥 Nathan ( , , , and ) GitHub LinkedIn Twitter Portfolio Site