What I Need to Learn for Work Next Week: It’s GraphQL Time

Mike Diaz
5 min readSep 24, 2023
Photo by Pixabay: https://www.pexels.com/photo/abstract-art-cobweb-connection-276223/

I am a full stack software engineer. Am I equally strong in all parts of the stack? Of course not, but I do have responsibilities on the front end and the back end, so part of my job is finding my weaknesses and working on them. When I finished my boot camp, I was very comfortable with React and JS, but I rarely use those skills professionally, so I would now say it’s the where I struggle the most.

This past week, I finally got a new feature working on the back end of one of our APIs. Next week, the expectation will be that I figure out how to allow users to interact with it on the front end, and boy did I have a lot of trouble reading that code. For this weekend, I tried to find one part of the code that I couldn’t understand and see what I could learn.

useMutation

And here it is:

export function useMutation<TMutation extends MutationParameters>(
mutation: GraphQLTaggedNode,
commitMutationFn?: (environment: IEnvironment, config: MutationConfig<TMutation>) => Disposable,
): [(config: UseMutationConfig<TMutation>) => Disposable, boolean];

At the core of my work is the question “how to I build an object with my request data and then how do I send it to the back end?” I was able to see the React components putting data together and then being passed into a function called insertConfig, which was defined like this:

const [insertConfig] = useMutation<InsertNewEtlConfigMutationType>(InsertNewEtlConfigMutation);

I vaguely recognized the destructuring going on here: useMutation returns an array and we’re pulling one element out of that array and naming it insertConfig. The <> is a type assertion on our parameters, which means useMutation will accept an argument of type InsertNewEtlConfigMutationType. Before I look any further into useMutation, I should try to understand the argument I’m passing it.

A graphql.ts file

I think my favorite thing about a modern IDE like Visual Studio Code is that you can cmd + click on a variable reference to see its origin. When I clicked into InsertNewEtlConfigMutationType , it took me to InsertNewEtlConfigMutation.graphql.ts, which is perfect because I had a feeling that this would all come down to GraphQL in the end.

If you’re like me, you’ve always had a hard time understanding what exactly GraphQL is. I was recommended some Relay docs, which say:

GraphQL presents new ways for clients to fetch data… It provides a way for developers to specify the precise data needed for a view and enables a client to fetch that data in a single network request. Compared to traditional approaches such as REST, GraphQL helps applications to fetch data more efficiently (compared to resource-oriented REST approaches) and avoid duplication of server logic…

To make it even more straightforward: GraphQL makes an API call. In the early examples I saw, it fetched data, but in practice, we can also use it to mutate objects on the other side of our API. REST, a more traditional API framework, is often referenced when explaining GraphQL because they can give us the same results, but at different levels of efficiency.

In this video, YouTuber Net Ninja shares an example of fetching author data from a booksendpoint. The book has an author_id, so we can plug that into the authors endpoint to learn more about that person. But if we’re starting from books, that’s two API calls. With GraphQL, we can make a fetch request with a specific structure and pull in only the pieces we’re looking for.

I’ve started to understand what I’m seeing in this graphql.ts file. There are a bunch of types defined with the various properties of the object I’m trying to build and they all come together to create the InsertNewEtlConfigMutation type that we saw passed to useMutation. I’m still not totally sure how this file came to be (was it manually written or auto-generated, and if so, what is it based on?), but I do believe that I’ll have to update it in order to pass a new payload to the back end since I’ve altered the shape of what we would expect from an EtlConfig. There’s also some other code in here that I don’t understand, but the pieces come together when I circle back to:

useMutation, again

My initial investigation revealed the origin of InsertNewEtlConfigMutation, but with that out of the way, we can look at useMutation again. Let’s work through the TypeScript:

export function useMutation<TMutation extends MutationParameters>(

The function can be used in other modules (export) and it will accept parameters of type TMutation, a generic that takes its definition from MutationParameters. Generics have always been difficult for me to understand, but now that we’ve seen the implementation of this function, it makes sense: we’re passing in the mutation that we have specifically defined for our ETL configuration. It was written with MutationParameters in mind, so it should have all the right properties.

(
mutation: GraphQLTaggedNode,
commitMutationFn?: (environment: IEnvironment, config: MutationConfig<TMutation>) => Disposable,
)

Here are our parameters: mutation and commitMutationFn. I had some trouble understanding what these should look like, so I checked out the implementation again. We’re passing InsertNewConfigMutation as the argument when we invoke the useMutation hook, but I didn’t see where that was actually being instatiated. Finally, I did a cmd + click and realized that the file itself was the class file; hence the name…InsertNewEtlConfigMutation.graphql.ts!

The very last line in the file is export default node;, which will be exported as InsertNewEtlConfigMutation. The node is a complicated object with keys like fragment, kind, operation, etc. I’ve got to believe this was automatically generated by some GraphQL or React engine. But I suppose that’s what a GraphQLTaggedNode looks like. The commitMutationFn has a question mark after it, meaning it’s optional. We don’t use it in my case, so I can’t say much about what it would normally look like, except that it’s a function that accepts two arguments and returns something of type Disposable, which I believe means the object will be properly disposed of at the end of its lifetime.

): [(config: UseMutationConfig<TMutation>) => Disposable, boolean];

The last line shows what the function actually returns: an array with a function that returns a Disposable and a boolean. The function accepts a config of type UseMutationConfig. In practice, we pass that function an object with variables (the actual data we want to use for the mutation), and onCompleted function, and an onError function. So a useMutationConfig likely looks something like that.

Is this helpful?

This turned out to be a meandering post that’s more about exploring my own company’s codebase than understanding GraphQL concepts. I’m not sure if anyone else will be able to glean anything useful from it, but I’ll publish it anyway. You never know when you’ll be able to help someone learn something new!

Sources:

--

--