GraphQL is one of the hot choices for developers and its popularity is increasing day by day. With its increasing demand and popularity among front end developers, we think it may fully replace RESTful APIs in the future. Developed by Facebook, GraphQL claims to be the "better REST" and solves the problem of over-fetching and under-fetching that is prevalent with REST APIs.
GraphQL is query friendly and allows you to define the structure and format of the data you want to fetch. It also allows you to query multiple models in a single request. Here is an example
A single POST request was not only able to fetch data from 3 different models, i.e. user, posts, and followers but also format it as per the client's needs. On the other hand, it would have us taken 3 requests with a RESTful service to get the same data, plus it would need additional formatting and mapping to make it consumable by the client. GraphQL can help us save us several seconds of processing time and also shortens the response payload to a bare minimum.
What is a CRUD API?
CRUD stands for create, read, update, delete. They are the most basic operations that an API can offer. The client application should be able to seamlessly perform CRUD operations on the model. The faster these operations are, the slicker your client application will feel. Almost every web application needs to handle thousands of CRUD requests per minute. What happens when you do a Facebook post? A post object is created by calling the Facebook API and it is stored in the database. Every time you go to your timeline, the same post is fetched on the UI to display. When you update the post, an update operation takes place and the contents of the post are updated in the database. The user also has the option to delete a post and it is purged from the database. CRUD is the basic building block of every massive API or application that we use.
What will we create?
We are going to create a simple CRUD API using GraphQL to manage posts. Let's say we are talking about posts that are present on a blog site like this one. We will build the API that serves as the backend of the blog and lets you perform the basic CRUD operations needed by a client application. We will be using MongoDB as the database to store the posts. A NoSQL database is the ideal choice for lightweight or mid-sized applications, that have a flat data model structure, and hence we would go for MongoDB in this example.
Like any other spring boot project, we would start by navigating to Spring Initializr. It is a great place to bootstrap your development and avoid the pain of writing a ton of boilerplate code. Enter your project information and select the dependencies "Lombok", "Spring Data MongoDB" and "Spring Web". We will be adding other dependencies later on. Make sure to select Maven and Java 8 for your project.
Click generate and download the source code. Open the project in your favorite IDE. We will be using IntelliJ Idea for but you are free to use any Java IDE of your choice.
Add dependencies for GraphQL, JUnits and some other utilities that are required for this project to your pom.xml.
The additional dependencies added to the pom are described below:
GraphQL spring boot starter - Core GraphQL Java libraries
GraphIQL spring boot starter - For GraphIQL GUI used for sending requests
GraphQL Java Tools - GraphQL utilities and error handling
JUnit - For writing unit tests to test our GraphQL API
Joda Time - Used for date and time fields that utilize MongoDB's audit features
Sync your maven project to pull the dependencies. Make sure to stick to the versions that we have used for the dependencies. Incompatibility between two dependency versions can really screw up your code and give you a hard time. We will now set up the MongoDB database needed for this project.
Make sure you have MongoDB community server up and running on your local. If not, you can download and install it from here. You will also need Mongo DB Compass, which is a GUI application used to connect with your database and perform administration tasks.
Create application.yml file in your main/resources directory and add the following lines:
Verify that your MongoDB server is up and running on port 27017 using Compass or by entering "mongo" on your terminal.
Defining the GraphQL schema
The next step is to define our GraphQL schema which consists of queries and mutations. Queries are used to fetch data in GraphQL whereas mutations modify data. Add the below schema in a schema.graphqls file in main/resources directory.
A type in the schema file defines the data structure of an object. We have defined a Post and a User. A post can be liked by multiple users and hence a post will have a list called "likedBy" to store the list of users who like the post. A post can also have a list of comments on it. Note that a Query and Mutation are also defined as types, all operations being defined inside them. Apart from the basic CRUD operations on a post, we have methods to like a post and add a comment to a post. In GraphQL an input to a method cannot be the same as the type, so we need to create separate inputs called "PostInput" and "UserInput" for this purpose, we have only defined the fields that are necessary while taking input from the user in this object.
Writing Java Code
Now it's time to create a Java class to define the Post object. It should match with our graphql schema and have the same fields.
Create Post.java in the main/java/model directory.
The @Document annotation is used to specify the name of the document for MongoDB. All other annotations are from lombok and help us reduce boilerplate code like constructors, builders, etc. We also need to define the User class in the model directory. We must have the Lombok plugin installed and annotation processing enabled in IntelliJ for the annotations to work. Check this guide on steps to install it.
We will also need a Java class for the Post input type. Only id and content are the fields required for this class.
We will now create the MongoDB repository interface in main/java/repository
With the repository and POJOs created, now we need to do the wiring in resolver classes for the Query and the Mutation types. In the directory main/java/resolvers, create a class called QueryResolver.java
The @Component annotation ensures that the class is initialized at server startup. We have added two methods corresponding to the entries in the Query type of the graphql schema file. PostNotFoundException is thrown if the queried post is not found in the repository, we will define this class later.
We need to define another similar class for resolving the mutations. Let's call it MutationResolver.java.
We have created methods to perform actions on the post repository as per the methods defined in the schema file earlier.
We have already used PostNotFoundException in the resolver classes and now we need to create this exception class. Create the class in main/java/error directory.
Set up GraphQLErrorAdapter and GraphQLAPIErrorHandler classes that will help with error handling.
Enable Audit Fields
We need to make another minor change to enable the MongoDB audit fields like created time, updated time, and version. Add the @EnableMongoAuditing annotation to your main Spring Boot starter class.
We should be all set now and are ready to test our GraphQL API.
Test the API using GraphiQL
Navigate to http://localhost:8080/ in your browser and you should be able to see the GraphiQL interface. Send a request with variables to create a new post.
You should get a successful response with all the fields that were sent by us in the CreatePost mutation. Go ahead and add a few more posts so that we can test some queries. Then run the query below to get all posts.
GraphQL returns all posts in a list now. Notice that the liked by and comments fields are empty. We will use the methods in our mutations to set them. Copy the id for the first post and we will like it and add comments to it. Run the mutation below to add a like to the post.
A user is added to the liked by list and the version is incremented from 0 to 1 meaning that the bean was updated.
Let's add a comment to the post now using the addComment mutation.
A comment was also added to the post now. You can add multiple likes and comments to the post and then query all posts again to see them together.
See the multiple likes and comments in the first post. Similarly you can play around with the updatePost mutation to update and existing post or the post query to get a single post by id. Verify that all queries and mutations are working. We can also validate the data in MongoDB by opening Compass and checking the posts collection.
Congratulations on building your CRUD API with GraphQL and MongoDB. There are an endless number of things you can do with GraphQL, feel free to play around on your own.
As usual, you can find the source code for this API on my GitHub.
Subscribe to TechInjektion
Get the latest posts delivered right to your inbox