DEV Community

Cover image for How Woovi uses Relay?
Sibelius Seraphini for Woovi

Posted on

How Woovi uses Relay?

What is Relay?

If you look at relay.dev, Relay is the GraphQL client that scales with you. This definition is simple and defines Relay pretty well for the ones that already know all the features that Relay brings to the table.

For the ones that still having used Relay or still do not understand all the benefits of using Relay, this article provides practical examples of how Woovi is using Relay to scale their backend and frontend.

Relay Architecture

Relay is composed by many packages. Understanding each package, can help you understand how Relay works.

Relay Compiler

Relay Compiler will read all GraphQL operations (queries, mutations, subscriptions), and fragments. It will parse, transform and optimize.

You can play with some Relay Compiler transforms here Relay Compiler Repl.

There is also a new Relay Compiler Explorer

Relay Compiler also polyfill GraphQL fragments to enable variables at fragment level, as GraphQL still do not support variables at fragment level yet.

Relay Compiler also ensure everything is correct, you won't be able to send a broke query to production, it won't even compile.

The output of this optimization uses AST, and it is stored on __generated__ folders. You can explore GraphQL AST using AST Explorer.

babel-plugin-relay

Relay provides a babel plugin that replaces the graphql tag to require the artifact generated static query generated by Relay Compiler.

Here is an example of this transformation

const user = useFragment(
    graphql`
      fragment App_user on User {
        app
      }
    `,
    props.user,
  );
Enter fullscreen mode Exit fullscreen mode

Transforms into

const user = useFragment(require('./__generated__/App_user.graphql.ts'),
    props.user,
  );
Enter fullscreen mode Exit fullscreen mode

Relay Test Utils

We use Relay Test Utils in our integration tests at frontend. It makes it pretty easy to mock Relay environment and any GraphQL query or field.

Below is an example of a mock resolver that tells relay test utils to mock every User to have a name Woovi. I don't need to mock the whole GraphQL operation, just the fields that make sense for my test case. It reduces a lot the number of fixtures.

const mockResolver = {
   User: () => ({ name: 'Woovi'}),
};
Enter fullscreen mode Exit fullscreen mode

Relay Runtime

Relay Runtime is the core part of Relay. It handles how Relay will do the requests (network layer), it will says how Relay will store the data. It also handles mutations and subscriptions.

If you wanna port Relay to angular or vue, you just take the Relay Runtime and add your favorite framework on top of it.

React Relay

It is the React bindings for Relay Runtime.
It evolved a lot since Relay Classic, to Relay Modern, and now Relay hooks with support to Suspense and render as you fetch.

Relay hooks provides the best DX. useFragment let you declare what data your components needs, and Relay will figure it out how to bring this data to that component, from the store? from the network? you don't need to care about it.

useMutation will execute GraphQL Mutations and will also ensure you don't double execute them, so you don't need to worry when an user clicks the form button twice or more.

Partial Rendering

One of the Relay unique feature is to partial render your components based on existing data in your store.

<>
  <PostTitle post={post} />
  <Suspense>
     <PostComments post={post} />
  </Suspense>
</>
Enter fullscreen mode Exit fullscreen mode

Imagine that you already have post.title in your Relay store, but you don't have post.comments.
Relay will be able to render <PostTitle /> component, and it will suspend <PostComments /> until it gets the post comments. This provides a faster first render experience, and better UX for our users.

Relay at Backend

relay-at-backend

We also use Relay at Backend.

We use Relay Compiler to compile and generate types for queries/mutations/subscriptions of our tests in the backend. This workflow provides typesafe testing and a better DX and asserting resulting of GraphQL tests.

Here is some code showing how to use it:

const graphql = (strings: TemplateStringsArray) => {
  if (strings?.schema) {
    throw new Error('use graphqlExecute');
  }

  return strings[0];
};

export const graphqlExecute = async <T extends OperationType>(
  args: GraphQLArgs<T['variables']>,
) => {
  const result = await graphql(args);

  return result as unknown as ExecutionResult<T['response']>;
};

const source = graphql`
  query AppQuery($id: ID) {
    user: node(id: $id) {
      ... on User {
        name
     }
   }
  } 
`;

const result = await graphqlExecute<AppQuery>({
    schema,
    source,
    rootValue,
    contextValue,
    variableValues,
  });
Enter fullscreen mode Exit fullscreen mode

AppQuery type is generated by Relay Compiler, and result has the correct type of it, if you change the query, it will change the result type. It is a great DX.

More Relay at Woovi

We are using more and more Relay at Woovi. Relay let us decouple our components. It lets us easily refactor without breaking anything. Relay Compiler in rust is faster than ever.

In Conclusion

My first contribution to Relay was December 15th, 2015, check it here https://github.com/facebookarchive/relay-starter-kit/commits?author=sibelius.

Since there, GraphQL and Relay evolved a lot. Relay has a step learning curve, because it requires you to do the right thing, not the easiest thing. Relay requires a new mental model of how to deal with data in components.

We are going to keep using more Relay at Woovi to help us scale.

Relay Workshop

If you want to learn Relay, the best resource is Relay Workshop. It has 12 practical exercises to learn the most used Relay features.


Woovi
Woovi is a Startup that enables shoppers to pay as they like. To make this possible, Woovi provides instant payment solutions for merchants to accept orders.

If you want to work with us, we are hiring!

Top comments (0)