Combining GraphQL with JsonSerializable
Hello everyone, Habr readers! In this article I will tell you how I met GraphQLwhat is it and how did I manage to combine it with JsonSerializable.
It was 7 months of work in my first company. In general, I was satisfied with the work, but the pay was low. The raise was supposed to be in 2 months, so I decided to play it safe and get an offer in case I was not satisfied with the new salary. I started sending resumes and one of the companies asked me to do a test, where I needed to get information about the missions SpaceX using GraphQL. With this analogue of REST API I was unfamiliar and my first step was to get acquainted with the technology, and then choose a package and implement the task.
What is GraphQL?
As I wrote above, this is an analogue of the REST API. GraphQL was developed at Facebook (now Meta). It is somewhat reminiscent of SQL, namely, that it has its own syntax for making requests. It is mainly used to download data from the server.
Among its main characteristics are the following:
Allows the client to specify exactly what data they need.
Facilitates the aggregation of data from multiple sources.
Uses a type system to describe data.
Meta created GraphQL for the following purposes: instead of having a lot of “stupid” endpoints, it’s better to have one “smart” endpoint, which will be able to work with complex queries and give the data the form requested by the client. If some data is stored, say, in MySQL, and others in PostgreSQL, then this technology is designed to make it easier to obtain data from different sources. That is, when working with the REST API, you execute queries “synchronously” to get aggregated data (for this you need multiple endpoints), then with GraphQL you can do this “parallel” (by writing one clever endpoint). And this smart endpoint is called request.
In the picture above you can see an example of such a request. I think after reading it you can understand that we are requesting a list of all missions. Each mission includes a name and details. There are also parameters here: limit and offset. The first of them indicates how many missions we should receive after executing the request, and the second – from which index in the array we will receive data.
GraphQL allows not only to receive data, but also to create. It is called mutation operation (similar to POST). If you want to learn more about GraphQL, then I highly recommend reading this article.
Time to do a test
After reading the article on Habr, I had a basic understanding of what this technology is and I moved on to choosing a package to start doing a test. After an hour of research, I settled on graphql. The documentation seemed clear to me, why not.
The first step is to create a client, where we need to pass a link to the source and create a CacheManager. If everything is clear with the first, then with the second I myself still have questions.
After we have created the client, we can already write and execute requests. After looking at what data serialization / deserialization looks like in the documentation, I realized that something is not right here … (you can say that it doesn’t exist at all)
And at that moment I realized what it is problem and it needs to be solved somehow.
I think most of us are familiar with a wonderful package for serializing / deserializing json objects – JsonSerializable. Using the annotation, we can mark any model that should be able to convert to json and from json. Next, based on code generation, the package generates two methods: toJson() and fromJson(Map
At the beginning, I got into Google, but either I didn’t search well, or there was no information, in the end I didn’t find anything, so I started to come up with a solution on my own.
In addition to GraphQL, of course, I used the REST API. At first my choice fell on chopper, then I switched to retrofit + dio. And here the first package, unlike the second one, cannot work with JsonSerializable out of the box. To do this, you need to write your own class parser, and then pass it to the client. He looks like this.
As we can understand, this class can decode either one model or a list of models. And more than that is not needed. To do this, we need to specify in the factories dictionary all the models that the parser is capable of processing. The key is the type of the model, and its value is the fromJsonFactory method, which must be written in the model after the JsonSerializable code generation. You need to make it static.
After all these manipulations, I moved on to the next step. I hope most of you are familiar with the pattern repositoryThe one that is responsible for getting the data. I came up with the idea to create a class BaseRepositorywhich will contain the parser class, which will allow us to parameterize all our requests.
This class allows us to get one model and a list of all models. Further, we can inherit from it any of our repository to call methods. Here, for example, is my repository, which is responsible for the SpaceX missions.
Thus, I solved one of the main problems for me personally. After I implemented another search, I sent the task for verification and a day later I received an offer for $ 1500 (however, I still stayed in my company, although I still left after 4 months 🙂 ).
That’s all for me. Thanks to those who have read to the end! Here is a link to this repository.