Recently, GraphQL has made a lot of buzz among the developers community, and it has been seeing a lot of attention because of the dynamicness and lot less redundant data fetching capabilities it packs under its hood. In this Code Tutorial, we will get to learn about:
- what GraphQL really is, why has it created such a hype amongst new age developers?
- How is it different from the REST approach, and finally
- We will be building our own API with GraphQL along with Code Tutorials.
So let's get into it 👨🏻💻
#1. What is GraphQL? A quick primer
Before understanding what GraphQL is, let’s first understand what Query Languages are. Query Languages are languages that request the data from a database (called queries) to a client side application through a server. A well known example is Structured Query Language, or SQL.
Coming to GraphQL, by definition -
“GraphQL is an open-source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data” (source: wiki).
But the question remains the same. What exactly is GraphQL? Simply put, GraphQL is a new age Query Language developed by Facebook that helps Application Programming Interfaces (APIs) fetch only that data which is request by the client, and nothing else, thus enormously reducing the redundant data at the API endpoint and making the requests blazing fast and developer friendly.
But, wasn’t that already being done by RESTful APIs 🤔? The answer is yes, but GraphQL is different (and also advantageous) than REST in a lot of ways.
- GraphQL is Client-Driven, whereas REST is Server Driven.
- Queries are organized in terms of Schema and strict typecasting in GraphQL, whereas REST has Endpoints for that task.
- GraphQL calls Specific data with single call. REST calls Fixed data with multiple calls.
- Instead of the GET, POST, PUT, DELETE operations in REST, GraphQL has Query, Mutation and Subscription for data manipulation.
Now that we know the “What”s and “Where”s of GraphQL, let’s dive straight into our favorite part. The Development 🤓.
#2. Let’s Play with GraphQL
In this section, we will learn about a step-by-step procedure of building an API using GraphQL and Express on top of Node.js. In the next section, we will be implementing these prerequisites into code and start our development for the API.
Prerequisites:
- Understanding of GraphQL
- Node Package Manager (or NPM) with version 10+
- Knowledge of basic querying and server-side programming.
We will be needing a Database to store the user data and everything else that a client side application can request for. For this, we will be using 📁 LowDB, which is a simple file-based JSON database for small projects in the localhost. Then we will be needing a middleware to connect our database system to the requesting frontend application. For this, we will be using the Express middleware with the GraphQL implementation of Express - the graphql-express library. Finally, we will be making a client side application using React which can request all the data from the local database and can perform operations on the database like Read, Write and Delete.
So our roadmap is pretty simple and straightforward 🛣️.
Create a Database Schema > Use a middleware server to query the database > Create a frontend application to use the data.
If this is too much at once for you, do not worry as this is article is being written kept in mind that the reader is a first timer for GraphQL and basic querying as usual.
With that being done, let’s dive into the CODE
.
#3. Setting up Express GraphQL
Let’s begin with the basic project structure of a Node.js application. Begin a new project in a new folder.
$ mkdir graphql-example
$ cd graphql-example
Use NPM to intiialize a project
$ npm init -y
Install the required dependencies for Express, MongoDB (Mongoose) and some additional dependencies required for the function of Express.
$ npm install express mongoose body-parser cors --save
Apollo Server is a community-maintained open-source GraphQL server that works with all Node.js HTTP server frameworks, so next we are going to download and save that.
$ npm install apollo-server-express --save
This should’ve created a package.json and a package-lock.json file within your folder. These files contains the information regarding our environment, the dependencies and the specific versions to run those dependencies.
This means our environment is ready and we can now start developing the integrated server and API. We are going to write the Schema inside the index.js file.
In the index.js
file, start off by writing this code.
const express = require('express');
const mongoose = require('mongoose');
const schema = require('./schema');
const bodyParser = require('body-parser');
const cors = require('cors');
const { ApolloServer } = require('apollo-server-express');
const url = "mongodb://localhost:27017/moviesdb";
const connect = mongoose.connect(url, { useNewUrlParser: true });
connect.then((db) => {
console.log('Connected correctly to server!');
}, (err) => {
console.log(err);
});
const server = new ApolloServer({
typeDefs: schema.typeDefs,
resolvers: schema.resolvers
});
const app = express();
app.use(bodyParser.json());
app.use('*', cors());
server.applyMiddleware({ app });
app.listen({ port: 4000 }, () => console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`));
In line number 1 to 6, we’re implementing the necessary modules. Note that here we have imported the ./schema, but we haven’t created that yet. We will be doing this in the next step.
In line number 9 to 14, we are connecting the project to the mongoDB database and logging any error we face to the console.
In line number 16 to 19, we’re creating a new Apollo Server with
typeDefs
andResolver
. We’ll be defining those in the ./schema later in this tutorial.In line 21 to 26, we’re firing up the Express Server at port 4000, when we can actually be able to interact with what we’re building.
GraphQL has two main principles in order to work: types
and resolvers
. We defined them in Apollo Server. We’ll import them from the file we’ll create later.
For the time being, let’s create the file models/movie.js
that’ll contain the movie-Mongoose model.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const movieSchema = new Schema({
name: {
type: String,
required: true
},
rating: {
type: Number,
required: true
},
producer: {
type: String,
required: true
}
}, {
timestamps: true
});
var Movies = mongoose.model('Movie', movieSchema);
module.exports = {Movies, movieSchema};
We’re going to build a simple movie app, where we can show, add, edit, and delete movies. That way we’ll get through the basics of GraphQL, which is the main goal of this article.
In lines 4 to 19, we’re basically determining the schema of the database that is going to hold the data of movies. Every movie is going to have a Name and a Producer of type String and a Rating of type Number.
#4. Designing the Schema
So now let’s move on to the schema.js
file where we’re going to build our GraphQL API.
Create a new file in the root of the folder by the name of schema.js
and add the following code.
const { gql } = require('apollo-server-express');
const Movie = require('./models/movie').Movies;
const typeDefs = gql `
type Movie {
id: ID!
name: String!
producer: String!
rating: Float!
}
type Query {
getMovies: [Movie]
getMovie(id: ID!): Movie
}
type Mutation {
addMovie(name: String!, producer: String!, rating: Float!): Movie
updateMovie(id: ID!, name: String!, producer: String!, rating: Float): Movie
deleteMovie(id: ID!): Movie
}
`
In this, we’re building the schema. We defined the Movie type which will have an ID, name of the movie and the producer, and a rating of type Float. The “!” after the types shows that these field are necessary.
Unlike REST approach of getting different tasks done at different endpoint URLs, GraphQL can create operations in a single endpoint. That is what we have done in line line 11 onwards. The type Query determines the GET operations, and type Mutation determines the modification operations like POST, DELETE, etc. In getMovies, we’re returning a list of all available movies in our database and in getMovie we’re getting the specific movie by the ID of that movie.
Now we’re going to link these with the Mongoose Database queries that are going to perform the actions in the database. And this is done by Resolvers. Resolvers are functions that connects schema fields and types to various backends. It can read, write and delete data from and to anywhere in the database, be it SQL, NoSQL or Graph based database.
Here’s how we’re going to implement Resolvers in our code:
const resolvers = {
Query: {
getMovies: (parent, args) => {
return Movie.find({});
},
getMovie: (parent, args) => {
return Movie.findById(args.id);
}
},
Mutation: {
addMovie: (parent, args) => {
let movie = new Movie({
name: args.name,
producer: args.producer,
rating: args.rating,
});
return movie.save();
},
updateMovie: (parent, args) => {
if (!args.id) return;
return Movie.findOneAndUpdate(
{
_id: args.id
},
{
$set: {
name: args.name,
producer: args.producer,
rating: args.rating,
}
}, {new: true}, (err, Movie) => {
if (err) {
console.log('Something went wrong when updating the movie');
} else {
continue;
}
}
);
}
}
}
module.exports = {typeDefs,resolvers};
This is the basic logic of MongoDB and CRUD application and is not in the scope of explanation of this article since it is majorly focussed on GraphQL. Although the logics are pretty simple and straightforward for anyone to understand so do skim through it once.
With this, we’re done with a basic Movie API which can perform all the CRUD Operations on a database of movies. To test this out, we’re going to fire up our node server and open the browser in http://localhost:4000/graphql which will open up the GraphQL Playground.
$ node index.js
🚀 Server ready at [http://localhost:4000/graphql](http://localhost:4000/graphql)
Once the Playground UI opens up, we’re first going to create a Movie Record for the database since it would be empty initially.
And now let’s list out all the movies in the database
So we have successfully created a Movie API where we can perform all the CRUD operations on a single endpoint, as well as ask for just the data that we want resulting in blazing fast API response and a developer friendly return object that makes development fast and super easy.
In the next part, we will be using this API in a React Project, along with a brief summary of what we did.
Till then, you can SUPPORT MY WORK here. hope you enjoyed. Stay Safe y'all
Top comments (0)