{
  "$type": "site.standard.document",
  "coverImage": {
    "$type": "blob",
    "ref": {
      "$link": "bafkreih6hk4eylzs5nr4qcgoc3gbgemzw6rdoa56j7dghwwgt4zd2j2akq"
    },
    "mimeType": "image/png",
    "size": 76194
  },
  "description": "<p>tl;dr: Use <code>relay --validate</code> to catch Relay validation errors in CI.</p>",
  "path": "/what-is-relay-validate",
  "publishedAt": "2019-03-22T00:00:00.000Z",
  "site": "at://did:plc:wm37qzgdjvwztq6loytrtpul/site.standard.publication/3mgjrev2z22sw",
  "textContent": "tl;dr: Use relay --validate to catch Relay validation errors in CI!I'm a big fan of GraphQL (seriously, ask me about GraphQL). One tool I've been\nabsolutely loving lately has been Relay. We\nuse Relay at Clubhouse to build some really awesome\nfeatures in\nClubhouse for iOS.\nAs of the writing of this blog post, we've got nearly 100 different components\nusing Relay in some way, shape or form!Hold up, what's Relay again?Relay is to GraphQL and data fetching what React is to DOM and UI. It's a\ndeclarative way to dictate what data your components need, rather than how\nand when to fetch it.A typical use-case of Relay looks something like this. Say you've got an social\nmedia app that shows a list of friends for the current user.Each of these components gets data from a different part of our tree. We can\ncolocate our queries of how to fetch the data for each component using\nRelay. A common way to do this is using Relay's createFragmentContainer\n(there's other methods to do this too, to handle pagination, refetching, etc. ,\nbut for the sake brevity in this post, let's focus on fragment containers).Some of the components may look like this:// in src/Avatar.js\nconst Avatar = ({ user }) => <Image src={user.thumbnailImgSrc} />;\n\nconst AvatarContainer = createFragmentContainer(\n  Avatar,\n  graphql`\n    fragment AvatarContainer_user on User {\n      thumbnailImgSrc\n    }\n  `,\n);\n\n// in src/FriendListItem.js\nconst FriendListItem = ({ user }) => (\n  <View>\n    <Avatar user={user.thumbnailImgSrc} />\n    <Text>{user.name}</Text>\n  </View>\n);\n\nconst FriendListItemContainer = createFragmentContainer(\n  FriendListItem,\n  graphql`\n    fragment FriendListItemContainer_user on User {\n      name\n      ...AvatarContainer_user\n    }\n  `,\n);\n\n// in src/FriendsList.js\nconst FriendsList = ({ currentUser }) => (\n  <FlatList\n    data={currentUser.friends}\n    renderItem={({ item }) => <FriendListItem user={item} />}\n  />\n);\n\nconst FriendListItemContainer = createFragmentContainer(\n  FriendListItem,\n  graphql`\n    fragment FriendListItemContainer_currentUser on CurrentUser {\n      friends {\n        ...FriendListItemContainer_user\n      }\n    }\n  `,\n);Now each of our components composes together both is UI components and it's\ndata-requirements, declaratively!Dope. Relay seems cool. But what's this __generated__ directory I've got here?The\nRelay Compiler\nwill read through our source code to find Relay components and their colocated\nGraphQL queries to generate artifacts that will be used by the Relay runtime.These artifacts look something like this (abbreviated here):// from src/__generated__/AvatarContainer_user.graphql.js\nconst node /*: ReaderFragment*/ = {\n  kind: \"Fragment\",\n  name: \"AvatarContainer_user\",\n  type: \"User\",\n  metadata: null,\n  argumentDefinitions: [],\n  selections: [\n    {\n      kind: \"ScalarField\",\n      alias: null,\n      name: \"thumbnailImgSrc\",\n      args: null,\n      storageKey: null,\n    },\n  ],\n};\n(node/*: any*/).hash = '693ff4889bc9965ae9f6512d628b7292'; // prettier-ignore\nmodule.exports = node;We can see that for the Avatar component, the compiler generates a static set\nof data for the GraphQL fragment it needs to fetch the data.Relay recommends checking in these artifacts from the Relay Compiler into your\nsource control, as they're crucial and necessary to run your app.As you work through your app, you'll likely run yarn relay --watch to run the\ncompiler in watch mode to automatically generate these artifacts and as you\nbuild new components, pages, features and so on. You'll see that as your change\nyour GraphQL queries, the Relay Compiler will indicate what is changed, and you\ncan see the changes in your git diff as well.❯ yarn relay\nyarn run v1.15.2\n$ relay-compiler --src ./src --schema ./schema.graphql --watch\n\nWriting js\nUpdated:\n - AvatarContainer_user.graphql.js\nUnchanged: 2 files\n\n❯ git status\nOn branch master\nChanges not staged for commit:\n  (use \"git add <file>...\" to update what will be committed)\n  (use \"git checkout -- <file>...\" to discard changes in working directory)\n\n\tmodified:   src/Avatar.js\n\tmodified:   src/__generated__/AvatarContainer_user.graphql.jsHowever, these artifacts are only autogenerated if you run the Relay Compiler\nwhile you're working! If a team member (or even yourself) forgets to run\nyarn relay while you're working, and a GraphQL query changes, your generated\nartifacts will be out of sync with your product code! 😰🤔 So how do we fix this? How do we prevent our product code's queries from\ncoming out of sync with our autogenerated Relay artifacts?Luckily, Relay makes this easy.The Relay Compiler includes\na flag called --validate.\nThis flag will run the Relay Compiler and if there are any autogenerated\nartifacts that will be overwritten based on the GraphQL queries, the compiler\nwill indicate that an artifact is our of date and exit with an error.❯ yarn relay --validate\nyarn run v1.15.2\n$ relay-compiler --src ./src --schema ./schema.graphql --validate\n\nWriting js\nOut of date:\n - AvatarContainer_user.graphql.js\nerror Command failed with exit code 101.This makes it really easy to validate your Relay codebase in CI, just as you\nmight run your tests in CI! Add relay --validate to your CI flow today and\ncatch changes in GraphQL queries before they land on master.",
  "title": "Validating Relay Queries With This One Weird Trick™"
}