A Detailed Tutorial on How to Build an API App Based on GraphQL and Trailblazer: Part 2
- 8460 views
- 5 min
- Apr 15, 2019
This article is the second part of the detailed guide on how to build an API app using such technologies as GraphQL and Trailblazer. In the first part of our tutorial, we’ve discussed the benefits of the chosen technologies, set up the project, configured our gems and implemented some user features. Let’s proceed with the main features of the ToDo list.
3. Main features of the to-do list
The main entities in our to-do List will be Project, Task, and Comment. Every Project consists of a set of Tasks and every Task can contain multiple Comments.
3.1. Project features
Let’s start with creating a Project model.
After that, we can proceed to code the ‘create’ operation for a Project. Let’s start with tests:
3.1.1. Implement an operation for creating a project
The operation looks like this:
3.1.2. Implement a GraphQL mutation for creating a project
Now we need to describe the GraphQL part. And again, we start with tests:
The response will look like this:
We need to describe the GraphQL type Objects::Project:
We should mention that in our type, we described the user field of type Objects::User. This gives us an opportunity to also receive data on its author when requesting a Project object.
Add this mutation to the root mutation:
Here’s how the mutation looks:
3.1.3. Implement the operation for updating the project
Let’s write the operation for Projects::Update. Here are the tests for it:
The operation and contract are very simple:
3.1.4. Implement a GraphQL mutation for updating the project
We’ll write a mutation for updating the project the same way we wrote our mutation for creating it. Here are the tests for the project update mutation:
And here’s the response schema:
Don’t forget to add this mutation to the root mutation:
Here’s the mutation itself:
3.1.5. Implement an operation for destroying a project
The final action for Projects is destroying them.
Here’s how we write a test for the destroy operation:
The operation in this case is going to be without a contract:
Here’s what the test for the mutation to destroy a project will look like:
The response schemas:
We’ll add our new mutation to the root mutation:
Here’s the code for this mutation:
3.1.6. Updating the GraphQL Objects::User object
At this stage, we can update the GraphQL Objects::User object so that when we request data by a user, we can get their projects:
Let’s check that we can get a user’s data with their projects:
3.2. Task features
Let’s generate a model:
Writing a concept and mutations (create, update, destroy) for the Task model will be similar to doing so for the Project model; the only difference is in the model attributes. You can find more details in this commit. The GraphQL object for tasks will be as follows:
Now we can update Objects::Project with a new field:
Let’s check if we can get tasks through the project:
The next step is to create the last entity: Comment.
3.3. Comment features
This entity is responsible for adding comments to tasks.
Comments can be created and deleted. There’s nothing unique in writing an operation and mutation for deleting a Comment. The code is similar to what we wrote for Projects and Tasks. If you want to check out the whole codebase, you can find it here.
3.3.1. Implementing an operation for creating comments
When we create a comment, there’s one additional feature to consider: attachments. That’s why we’ll consider this code in detail. Let’s start with tests for operations:
For attachments, we’ll use the carrierwave gem.
Generate an uploader and mount it on the model:
Here’s what the contract and operation for creating a comment looks like:
3.3.2. Implementing a GraphQL mutation for creating a comment
Now we need to write a GraphQL mutation for creating a comment. Let’s start with tests:
Here’s what the response schemas will look like:
Now in our mutation we get a new type, Upload, that’s provided by the apollo_upload_server gem.
Here’s what the mutation for creating comments looks like:
And here’s the GraphQL object for comments:
Don’t forget to add this mutation to the root mutation:
Let’s run our tests and check that they pass. That’s it for the comments.
We have a new GraphQL object and we can update objects that we’ve created before, so in the query “me” we should get comments on each task in our projects.
To pass the tests, let’s update Objects::Task:
The basic functionality of our to-do list is completed.
4. Authorization feature
Let’s assume that we need to implement a feature for displaying all users. At the same time, a user should be able to see only data of their own projects.
We can assume that our test and response schema will be as follows:
Let’s update Objects::User so that we need to go through authorization to display projects. For authorization, we’ll use the pundit gem.
The operation used to display a user’s projects will contain Policy::Guard and looks like this:
If authorization fails, we’ll call the exception Pundit::NotAuthorizedError:
This exception will be handled by our ErrorHandler and call another exception: GraphQL::ExecutionError.
Start tests and check if they pass. This step completes the implementation of the to-do list.
One of the biggest advantages of GraphQL is that you don’t need to write documentation. The GraphQL scheme that we’ve described above is documentation itself.
After all the work we’ve done, we can also test our app in the GraphQL IDE with the help of the graphiql-rails gem that we installed previously. For that, we’ll start our server and go to http://localhost:3000/graphiql. To test requests with authentication, you can use the Chrome extension ModHeader.
Don’t forget to subscribe to our blog if you want more detailed tutorials on the most popular technologies, and feel free to ask questions below.