I recently started learning GraphQL and like I’ve learnt throughout my developer journey, the best way to learn a new technology is by building a project you want with it. I decided to build an API with GraphQL endpoints based off an already existing REST API using Ruby-on-Rails.
We would be using PostgreSQL so we can deploy our API to Heroku.
This tutorial is based off the splendid tutorial on GraphQL in rails by Isa Levine on dev.to.
GraphQL has two ways of interacting with databases.
a. Query — this allows us to get data (“Read” in CRUD)
b. Mutation — this allows us to change information, including adding, updating, or removing data (“Create”, “Update”, “Destroy” in CRUD)
- Create a new Rails API app called corona-ql
3. Go to congif/application.rb, uncomment require “sprockets/railtie”. We need to do this in order to use the GraphiQL playground — a place where we can query our database.
4. Add the gems httparty, ‘sprockets’, ‘~>3’, graphql and graphiql-rails and run bundle update. We specifically need sprockets v3 because things break in the later version of sprockets. After adding all these gems, your gemfile shoud look like below.
5. Let’s create a table for countries. We only need to create a country name column here, all other columns will be automatically generated by GraphQL. Let’s also create a Summaries table.
rails g model Country country_name
rails g model Summaries
6. Let’s create and migrate our db.
rails db:create db:migrate
7. Next, let’s actually install GraphQL so it can create all the files that we need automatically.
rails g graphql:install
If you head to app > graphql, you will see all the files automatically generated by the command we ran above.
If you’re familiar with building Rails APPs, you would already know that Rails is based on the MVC architecture and we access different methods/actions in our apps via a route. In GraphQL on the other hand, there is only one route.
If you check your routes.rb file, you can see that a route was automatically generated for us. Now, let’s also add the route that gives us the GraphiQL playground.
8. Next, let’s seed our database with country names. We would be using the API created by NovelCOVID. They’ve done a great job of creating and maintaing the API. Head to your db/seeds.rb file and add the following code.
We are using the HTTParty gem here to grab the data. Then we use the inbuilt JSON objet to parse the response to JSON. The response is an array. We then loop through the array we receive, get the country names and use that to create a record of names for each country in the database.
We can check that the names were successfully created in the db by checking in our rails console.
It should return a list of 100+ country names.
9. Now that we have seeded our data, let’s create our GraphQL objects representing our models.
rails g graphql:object country
rails g graphql:object summary
The commands above will generate two files for us within our graphql directory. country_type.rb and summary_type.rb.
Let’s test that graphiql works. Fire up your rails server with rails s, head to localhost:3000/graphiql. If it loads an interface, then everything works and we can continue.
10. Head over to app > graphql > country_type.rb. In here, we would write commands to generate the additional columns we need on the fly. It would also contain the actions/methods to run to create these columns. Follow the code below, I’ve tried to explain some of the code with inline comments.
We create fields for each field(column) we want. We then create functions that supplies to those fields. The response from the request function is used to extract each of the information/fields we need from the response body of the external API we are calling.
Now, head over to the summaries_type.rb doc. In here, we would do something similar.
11. Now, let’s head to our query_type.rb file. The query_type file is the actual file that contains all our actions/methods that is called when a request is made to our API. I planned to use this API with a React frontend so I also have some methods that you may not need.
Before giving the code, let’s go over what each method does.
all_countries_limit: Takes 2 arguments — per_page and start. If I was implementing a pagination feature on my front end, I could easily use this to calculate how much data to load and from what point when the user clicks the page number they would like to view. As you’d see, I have see the default to return 10 country records at a time. This method returns all the fields in our country_type.rb with a limit per_page === per_page.
all_countries: This will return all the fields specified in our country_type.rb for every country in our database and sorts them in ascending order. I’m not a huge fan of running this query because of the amount of records it has to fetch from the external API which usually takes some time.
country_filter: country filter takes an argument of text and searches our database to find a country matching the input. This is a special method I’ve added with the front end app in mind. This method returns countries based on matches. For example, If you were searching for Nigeria but you only typed nig in the frontend, this method will return all the countries that contains nig in their country_name column.
summary: simple returns all the fields in our summary_type.rb
find_country: Takes in a country_name argument and does an exact match to return the country with that specific name. We’re making things a little easy for a potential front end application here. If a user were to enter a country_name with ALL CAPS or camelCase, our application will convert the input string to lower case and then capitalize it before searching our db so that it meets the format of country names in our db.
Notice that within some of our :fields, we are also specifying arguments. This is what allows us to accept input data as argument when a user is querying our db.
That’s pretty much it. Time to test out all our work.
Re-start your rails server, head to localhost:3000/graphiql and let’s make some queries.
Another important thing to note is that even though we write things in snake_case within ruby/rails, when we make queries, they must be done in camelCase like above.
Hope you learnt something new!
The full repo is available here although it’s not exactly the same — I’ve setup some things differently from this tutorial.
Leave a clap if this helped you.