Introducing the new Solid Query client
Tags: solidjs, javascript, webdev, programming
Published: 2023-03-02 20:03:30



We're excited to announce that we now have official Solid.js support! 🎉. This new client is built on top of [TanStack Solid Query](https://tanstack.com/query/v4/docs/solid/overview), and brings all the good stuff from WunderGraph to the Solid.js ecosystem. Query, mutate and subscribe to your WunderGraph API fully typesafe in Solid.js.

The release is still in beta and we're looking for feedback on the API and how it works with Solid.js. If you have any feedback, please let us know by opening an [issue on Github](https://github.com/wundergraph/wundergraph/issues/new/choose) or talk to us [directly on Discord](https://wundergraph.com/discord).

Let's go through quickly how to set it up and how it works.

## Installation

Install the Solid Query client:

```bash
npm install @wundergraph/solid-query @tanstack/solid-query
```

## Configuration

Before you can use the hooks, you need to modify your code generation to include the base typescript client.

```typescript
// wundergraph.config.ts
configureWunderGraphApplication({
  // ... omitted for brevity
  codeGenerators: [
    {
      templates: [templates.typescript.client],
      // the location where you want to generate the client
      path: '../src/generated',
    },
  ],
})
```

Now you can configure the hooks. Create a new file, for example `src/lib/wundergraph.ts` and add the following code:

```ts
import { createHooks } from '@wundergraph/solid-query'
import { createClient, Operations } from '../generated/client'

const client = createClient() // Typesafe WunderGraph client

export const {
  createQuery,
  createMutation,
  createSubscription,
  createFileUpload,
  useUser,
  useAuth,
  queryKey,
} = createHooks<Operations>(client)
```

### Queries

```ts
const weather = createQuery({
  operationName: 'Weather',
  input: {
    forCity: 'Berlin',
  },
})

weather.data
```

Turn queries into live queries, live queries are refetched on a interval on the WunderGraph server.

```ts
const liveWeather = createQuery({
  operationName: 'Weather',
  input: {
    forCity: 'Berlin',
  },
  liveQuery: true,
})
```

### Subscriptions

Build realtime apps with subscriptions.

```ts
const subscription = createSubscription({
  operationName: 'Countdown',
  input: {
    from: 100,
  },
})
```

### Mutations

```ts
const mutation = createMutation({
  operationName: 'SetName',
})

mutation.mutate({ name: 'Eelco' })

// Async mutate
const result = await mutation.mutateAsync({ name: 'Eelco' })
```

### Invalidating queries

Let's say we have a query that fetches the current user's profile in one component and we have a form that updates the profile. We can add an `onSuccess` handler to the mutation that calls `queryClient.invalidateQueries` on the `GetProfile` query and trigger a refetch and update the internal React Query cache.

```ts
const Profile = () => {
  const query = createQuery({
    operationName: 'GetProfile',
  })

  return <div>{query.data?.getProfile.name}</div>
}

const FormComponent = () => {
  const queryClient = useQueryClient();

  const mutation = createMutation({
    operationName: 'UpdateProfile',
    onSuccess() {
      // invalidate the query
      queryClient.invalidateQueries(queryKey({ operationName: 'GetProfile' }));
    },
  })

  const onSubmit = (event) => {
    e.preventDefault();
    const data = new FormData(event.target);
    mutation.mutate(data)
  }

  return <form onSubmit={onSubmit}><input name="name" /><button type="submit">Save></button></form>
}
```

Now we could even make this fully optimistic by updating the `GetProfile` cache instead and then refetching it, it would look something like this:

```ts
const FormComponent = () => {
  const queryClient = useQueryClient()

  const mutation = createMutation({
    operationName: 'UpdateProfile',
    onMutate: async (data) => {
      const key = queryKey({ operationName: 'GetProfile' })
      // Cancel any outgoing refetches
      // (so they don't overwrite our optimistic update)
      await queryClient.cancelQueries(key)

      // Snapshot the previous value
      const previousProfile = queryClient.getQueryData<Profile>(key)

      // Optimistically update to the new value
      if (previousProfile) {
        queryClient.setQueryData<Profile>(key, {
          ...previousProfile,
          ...data,
        })
      }

      return { previousProfile }
    },
    // If the mutation fails,
    // use the context returned from onMutate to roll back
    onError: (err, variables, context) => {
      if (context?.previousProfile) {
        queryClient.setQueryData<Profile>(
          queryKey({ operationName: 'GetProfile' }),
          context.previousProfile
        )
      }
    },
    // Always refetch after error or success:
    onSettled: () => {
      queryClient.invalidateQueries(queryKey({ operationName: 'GetProfile' }))
    },
  })

  const onSubmit = (event) => {
    e.preventDefault()
    const data = new FormData(event.target)
    mutation.mutate(data)
  }

  return (
    <form onSubmit={onSubmit}>
      <input name="name" />
      <button type="submit">Save</button>
    </form>
  )
}
```

Check out the reference and example app below to learn more about the new Solid Query integration.

## Resources

- [Solid Query reference](https://docs.wundergraph.com/docs/clients-reference/solid-query)
- [Vite + Solid.js Example](https://docs.wundergraph.com/docs/examples/vite-solidjs)
- [TanStack Solid Query](https://tanstack.com/query/v4/docs/solid/overview)

## Summary

You can now leverage the power of WunderGraph with Solid.js, we are excited to see what you'll build with it.

Thanks go out to Tanstack for making this awesome async state management library. We will be releasing Svelte and Vue integrations soon, stay tuned!

We would love to know more about your experience with Solid.js. Do you use Vite, or Solid Start? What do you like about it?

Share it in the comments below or come join us on our [Discord server](https://wundergraph.com/discord).