Documentation
Querying your API (client)
Best practices

Best practices

There are some best practices we strongly believe in while developing with fuse.

Use fragment co-location

One of the pillars of fuse is Fragment co-location, we strongly believe that this patterns helps us get a better overview of our data-requirements and makes it easier to reason about the data a component will receive.

When creating components it's useful to co-locate your data-requirements with your component, this way when you need more data for your component you know exactly where to add it and you don't have to go up your component-tree to find the query responsible for adding the data.

import { FragmentType, graphql, readFragment } from '@/fuse'
 
export const UserFields = graphql(`
  fragment Avatar_UserFields on User {
    firstName
    avatarUrl
  }
`)
 
export const Avatar = (props: {
  user: FragmentOf<typeof UserFields>
}) => {
  const user = readFragment(UserFields, props.user)
 
  return (
    <div>
      {(user.avatarUrl && user.firstName) && <img src={user.avatarUrl} alt={user.firstName} />}
      <span>Welcome, {user.firstName}</span>
    </div>
  )
}

The above defined fragment is now globally available and we can add it to our query:

import { graphql } from '@/fuse'
import { UserFields } from './Avatar'
 
const UserQuery = graphql(`
  query User ($id: ID!) {
    user(id: $id) {
      ...Avatar_UserFields
    }
  }
`, [UserFields])

From now on out, every time we need a new field in the Avatar component we can just add it there and trust that the query is updated automatically and our data is passed into the component by menans of <Avatar user={result.data.user} />.

All Fragments you define in a component will be globally available, this means that if your client components define their data requirements you can spread your fragments in your top-level server-component and pass the data down.

Type-conditions

Something you might notice when we define a fragment is that we add this on X keyword after the name, this is called a type-condition and is used to tell the GraphQL that we only want those fields when the type is either X or a type that inherits from X (like with interfaces).

Don't interpolate arguments

When we are working with field-arguments it's important to either write them as a literal value i.e.

query {
  users(limit: 10) {
    nodes {
      id
      name
    }
  }
}

or interpolate them as variables

query ($limit: Int!) {
  users(limit: $limit) {
    nodes {
      id
      name
    }
  }
}

String concatenation like limit: ${myJsLimitValue} is discouraged!

Fragment naming

We suggest that you follow a naming pattern with fragments to make them both easy to discover as well as easy to understand to what component they relate.

When we name our fragments like Filename_TypeFields we can easily see which component the fragment relates to when it's being spread into a query. This allows us to also easily know that we can remove the fragment once we remove the component.

An example of this could be the following, when we have an Author.ts file we would define a fragment that looks like

fragment Author_UserFields on User {
  id
  name
  avatarUrl
}

Now when we spread it in our Blog page we can easily see that it relates to the Author component, when we inspect the GraphQL document being sent to the server we can also derive that this is meant for that component.

readFragment and FragmentOf

You'll see that we use this readFragment function in our components that have a fragment describing their data-requirements, this helper ensures that we remove any extraneous fields and type the output correctly. Another thing worth noting is how we type the props, we use this FragmentOf helper which ensures that the parent-component uses the fragment and passes that into props, this means that if the parent-component would define all the fields of the fragment manually and not spread it that we would show a warning.

Top-level queries

One of the benefits that comes with describing the data you need is that you perform 1 request and get 1 response, no waterfall where you need to wait for the list and then perform a whole set of other requests to enrich that data, ... We wrangle the data once, with this comes our sugestion to aggregate the data you need by means of your fragments at the page-level, in doing so you resolve all data in a single request.

With modals/... that pop up you can do one-off requests later when you need the data but not having a waterfall of loading spinners because you are navigating around feels both more performant and more user-friendly.