Roman Dubrovsky

Life With GraphQL API: Good Practices And Unresolved Issues

Pivorak Conf 4.0

00:00:08.170 Hello, everyone! I'm Roman, and I'm really glad to see you all. I'm very happy to visit Iraq; this is my first time here.
00:00:14.500 Thank you for having me! I knew before coming that Pivorak is one of the friendliest Ruby communities in Eastern Europe, and I’ve found that to be true.
00:00:21.369 Currently, I work at Trollkinds, an international company, and we have some cool gifts for you. You can find our stickers at our table.
00:00:36.190 Additionally, I'm a member of the Minsk Ruby community, and I want to invite you to visit us in Minsk. If you ever find yourself there, just let me know and I can help organize a pre-party, after-party, or any other event you might be interested in.
00:01:12.130 Now, let’s start my talk. Today, I’ll be discussing life with GraphQL APIs. I won't be diving into the theory behind GraphQL, nor will I cover how to set one up or the positive and negative sides of the technology.
00:01:25.170 Instead, I will share our story about how we worked with GraphQL, the journey we undertook, and the results we achieved. I’ll walk you through our transition from using individual components in our React application with GraphQL queries to rewriting much of our application to fully embrace GraphQL.
00:01:44.680 I will also discuss some real issues, as well as some unclear points for those of you who are considering using GraphQL in production. Plus, I'll share insights that people have asked me about in the past.
00:02:17.200 In terms of my experience with GraphQL, we spent almost two years developing and supporting our GraphQL API for our single-page application. We decided to make our complex GraphQL API public and began preparations for that as well, while also gaining experience in integrating with external development.
00:02:41.079 Let’s dive into part zero, which is the introduction to GraphQL. I understand that some of you might not be familiar with GraphQL, so I’ll cover the basics.
00:03:05.110 First of all, GraphQL is a query language for APIs that allows you to structure your data and defines your business model. In a GraphQL schema, every entity is a type, and each type has a list of fields. Some types can also be connected to others through fields.
00:03:39.340 The schema is the most important part of the GraphQL API, describing our types and their relationships. It typically contains two main parts: queries and mutations. A mutation describes actions we want to perform, while queries specify the data structure we wish to retrieve.
00:04:50.830 In Ruby, we have the GraphQL gem, which facilitates the official Ruby implementation, helping us describe our GraphQL schema, serialize data, execute queries and mutations, and provides generators and helpers for setting up a GraphQL API in our application.
00:05:11.500 About three years ago, we undertook a project that involved a mix of large components and small components in the front end. We had multiple versions of a REST API and faced significant challenges with a convoluted system that had been heavily modified over time. Our customer wanted a modern single-page application with a reactive UI, so we decided to build it with React.
00:06:44.520 As we developed the application, we encountered numerous performance issues with the REST API, leading us to send multiple requests just to load a single page. To resolve this, we opted to use GraphQL. During this process, we selected Relay because, at that time, Apollo was less mature and didn't meet our needs as effectively.
00:08:13.380 When we began designing our GraphQL API, we had little knowledge of design best practices. We sought good examples and found inspiration in GitHub's GraphQL API. This marked the beginning of our journey towards developing our API.
00:09:26.900 We started by designing our GraphQL API specifically for our internal single-page application. A key takeaway was the importance of establishing good conventions for organizing our business logic. The GraphQL philosophy encouraged us to separate our business logic from the representation layer.
00:10:51.339 The architecture of our project had evolved over more than ten years, heavily relying on Rails. While many discussions around Rails revolved around the best practices of fat controllers vs. fat models, we realized that this was not suitable for production applications.
00:11:47.230 We introduced a 'Boy Scout rule' in our company, which meant that whenever we worked on any area of the codebase, we aimed to improve it. As we began the transition to GraphQL, we also undertook significant refactoring efforts to enhance the applications overall performance.
00:12:40.699 This refactoring allowed us to move business logic out of the models and into service objects, which greatly improved our code's organization and reusability.
00:13:32.020 As our GraphQL implementation progressed, we realized the IDs defined in our GraphQL schema did not match those in our database. We had to adapt our approach, providing the relevant arguments through our service layer when needed.
00:14:14.350 This restructuring led to significant benefits, particularly in establishing conventions for how we created our services and designed our business logic, which was a major win for us.
00:15:43.800 Now, I want to talk about pagination, which was a challenge we faced when developing our API. We learned from our REST API experiences when implementing pagination in GraphQL.
00:16:08.100 Poorly implemented pagination could lead to severe performance issues, such as loading massive collections of items in a single response. As part of our implementation, we ensured that pagination included metadata, allowing us to understand how many pages or items were present.
00:17:45.800 We came across various ways of handling pagination, and it's crucial to ensure efficient results while avoiding common pitfalls of returning too many items at once.
00:19:08.560 Another crucial aspect of our implementation was how we handled mutations and authorization. The best practice we found was to handle the business logic authorization within the service layer, rather than directly in our GraphQL resolver functions.
00:20:58.780 It was essential to expose clear authorization rules while keeping in mind how we could manage fields with limited scopes. We needed to create an efficient system for conveying authorization messages back to users without breaking the queries.
00:22:50.170 In our development, we faced various challenges around handling N+1 query issues, which affected performance. We learned how important it was to optimize these queries and how we could leverage the GraphQL API effectively to address these problems.
00:24:25.560 Ultimately, we wanted to integrate our new GraphQL API while also ensuring that we maintained compatibility with our legacy REST API, which brought its own challenges in terms of documentation and support.
00:25:31.580 We recognized that thorough documentation was essential for understanding the GraphQL API. The official GraphQL documentation became invaluable, as it helped everyone involved to understand the types and fields better.
00:27:30.320 We also emphasized the importance of treating each field in our schema like a function that accepts arguments and returns a value, which improved both user experience and security.
00:28:14.900 As we progressed, it became clear that validation was a non-negotiable aspect of our implementation, helping guard against issues like SQL injections and ensuring a more robust application overall.
00:29:17.900 Unfortunately, time has run out for this presentation, and I still have many points left to cover. However, I'm eager to continue these discussions during the coffee break.
00:29:54.760 I welcome everyone to approach me about any questions or topics that we didn’t have a chance to dive into further.
00:30:39.670 Thank you for your attention! I hope you enjoy the rest of the conference.