Talks

GraphQL-DDD on Rails Architecture

Recorded in June 2018 during https://2018.rubyparis.org in Paris. More talks at https://goo.gl/8egyWi

Paris.rb Conf 2018

00:00:11.380 Okay, please welcome Paul! Hello everyone, it's such an honor to be here in front of such a great audience.
00:00:22.750 I'm Paul, a web developer for five years. I have been a Ruby developer for five years and a former CTO. I am very interested in performance, automation, and related topics.
00:00:28.590 I really enjoy AI and machine learning in my off-time.
00:00:33.210 Today, I'm going to talk about my recent experience as a CTO and what I built there. I will outline my programs and explain why I transitioned from REST to GraphQL.
00:00:54.190 So, why are we building APIs? Building an API is about providing data to consumers, whether that's to a front-end application or a mobile application.
00:01:02.019 Rails gives us the API only Rails engine, which is straightforward to use. At that time, when I started the API for a large and ambitious project, I didn't really know the best approach to building an API.
00:01:15.570 I began with the JSON API standard. However, after a few weeks, things started to get messy. For example, when my front-end developer asked me for particular data in an endpoint, I found myself overwhelmed.
00:01:31.750 Initially, I set up numerous custom endpoints to accommodate these requests, but the structure became too complicated and tiresome. After about three months of building these challenging APIs, I decided to try a different approach.
00:02:11.410 I wanted to develop an API from scratch that I wouldn't need to revisit once it was done. That's when I discovered GraphQL, which was a revelation for me.
00:02:36.340 GraphQL allows you to have a single endpoint where consumers can query or mutate the data they need. This means you only need to manage one endpoint, which greatly simplifies everything.
00:02:41.860 With GraphQL, you also have the concept of subscriptions, which is akin to WebSockets. You can subscribe to a channel and perform various tasks through it.
00:03:04.450 We were quite entertained by GraphQL at the time, so I started exploring what had been done in Ruby for GraphQL. Thanks to Robert, the work on GraphQL was excellent.
00:03:28.390 However, I wanted to simplify the architecture further. I looked into domain-driven design principles and restructured some designs specifically for Rails.
00:03:54.880 I developed a gem that would clean and streamline the GraphQL architecture, effectively transforming a Rails API into a GraphQL API.
00:04:08.630 I think the best way to explain how this works is through an example. Let's create a simple API together.
00:04:17.220 For my first big conference in English, I wanted to gather feedback, so I'll create an API that allows for that. We will have speakers, spectators, comments, and categories for talks.
00:04:25.350 This will be a simple API that allows users to create speakers, spectators, comments, and tags, as well as modify and destroy them as needed.
00:04:42.010 Next, I will set up an application using PostgreSQL because it handles UUIDs well and works neatly with front ends. I will add the Gemma GraphQL and GraphQL Rails API to my application.
00:05:14.390 After that, I created the database and designed my data model. For example, a speaker has a name and many talks, which means you can define relationships between the entities.
00:05:41.640 For instance, a talk belongs to a speaker while a spectator has a body and belongs to both a talk and a speaker. I described the model, and from there, I generated my GraphQL API.
00:06:09.160 This made it possible to create backend logic for generating the necessary migrations, models, and GraphQL types and mutations automatically.
00:06:36.290 Whenever I add a speaker who has many talks, the system automatically includes a speaker ID in the talk model and sets everything up.
00:07:04.450 Now, let me show you the results in code. As you can see, I am working with GraphQL, and I only have one controller, which is the GraphQL controller. In my routes, I only need one route that relates to the GraphQL method.
00:07:40.560 This route executes the GraphQL query passed as a parameter and handles user authentication. You can authenticate your user however you want and pass it into GraphQL.
00:08:19.320 The structure has also been designed to correspond with domain-driven principles. For example, if I take a command, its type automatically includes spectator ID, talk ID, body, timestamps, and IDs.
00:09:01.740 In addition, the mutation creates, destroys, updates, and has input types, which defines the data sent to create or update commands.
00:09:26.970 In the service layer, this is where you manage your business logic. For instance, if you want to change how commands are created, you simply redefine the creation method here, and it updates automatically.
00:09:50.460 My domains and services are organized so that you can test the logic easily. I have incorporated visibility filters into my gem, allowing filtering of commands.
00:10:20.940 For example, if I want to filter commands based on the authenticated user, I can easily do that so that they only see their own commands.
00:10:47.010 The advanced querying functionality is another powerful aspect of GraphQL, including querying for specific fields while ensuring optimal database queries.
00:11:29.820 For instance, when creating commands, you simply invoke a mutation like 'create a command' or 'create a spectator'. It's straightforward.
00:12:11.520 To demonstrate this, I have deployed the application on Heroku, and you can access it via the provided URL. Feel free to try it out and have fun with it.
00:12:34.660 You can post comments, and I will check them. Thank you!
00:12:59.050 Thank you so much!
00:13:05.960 Does anyone have any comments or questions?
00:13:18.230 Yes, thank you very much for your talk! I have been looking for an opportunity to use GraphQL for a while, but I often find myself unable to destroy my existing JSON API and start from scratch.
00:13:50.400 What would you advise in this scenario? It appears that the barrier to entry for GraphQL, in terms of the amount of code required to implement it, is quite high.
00:14:13.750 It can be high, but you can add the GraphQL layer to your existing Rails application easily. Just add it and introduce your types iteratively.
00:14:41.080 You don't have to overhaul your entire API at once; instead, do it resource by resource. Your front-end developers will appreciate using the new GraphQL resources.
00:15:28.830 There is another question? Yes, what happens when a request comes in for a field that no longer exists? Do you have an unknown contract to retain or will it throw an error?
00:15:55.640 For GraphQL, you have access to your schema and can ask for the possible queries. The GraphQL documentation explorer allows you to see what you can query.
00:16:40.230 If you try to query a misspelled field, it will inform you that the field does not exist. That adds a layer of robustness to the querying process.
00:17:25.250 Thank you. Are there any other questions?
00:17:47.940 Hi, thank you for the talk. I wonder how you handle the increased responsibilities of the front-end with this approach dealing with API.
00:18:29.370 That's not entirely true because you can enhance your API however you want. It's similar to a REST API; developers find it easy to adapt. Frameworks like Apollo or Relay help in managing this complexity.
00:19:20.370 The front-end teams I worked with were eager to add logic in the front end when it's appropriate. All backend logic remains intact.
00:19:55.670 Hi, thank you for the talk. How do you deal with filtering data at the request level? For instance, if I want to get talks that include 'Ruby' in the title?
00:20:32.900 You can easily add arguments to your queries to filter data. You could append, for instance, a search field in your query to only retrieve talks with 'Ruby' in the title.
00:21:14.020 Does that clarify how you specify it on the front-end?
00:21:32.820 You can structure the arguments neatly in your GraphQL queries to enforce filtering based on user input; this approach is both flexible and efficient.
00:22:14.720 Thank you for pointing that out. Any other questions?
00:22:40.210 How are validation errors returned in an update request?
00:23:15.800 Validations are set up, so when a required field is missing, the error gets returned in an array format, which provides feedback on what went wrong.
00:23:49.030 If you attempt to create a spectator without a name, the input type validation will block that and return an appropriate error message.
00:24:30.890 I want to better understand the reasoning behind your switch from JSON API to GraphQL, especially considering the specifications.
00:25:35.570 The JSON API specification does allow for specific fields to be requested, yet the limitations regarding deeply nested relationships and filtering are why I favored the flexibility that GraphQL offers.
00:26:05.170 In conclusion, thank you for your attention, and I appreciate the questions you've shared.